Episode 44: Kinematics Part 2
author |
Steve Losh <steve@stevelosh.com> |
date |
Sun, 14 Aug 2016 22:37:23 +0000 |
parents |
085ab1bb07c6
|
children |
28dc985f4d51
|
branches/tags |
(none) |
files |
src/2d/demo.lisp src/vectors.lisp |
Changes
--- a/src/2d/demo.lisp Sun Aug 14 21:17:02 2016 +0000
+++ b/src/2d/demo.lisp Sun Aug 14 22:37:23 2016 +0000
@@ -33,11 +33,24 @@
;;;; Episode
-(defstruct (arm (:constructor make-arm (pos length angle &optional parent)))
- pos length angle parent)
+(defstruct (arm (:constructor %make-arm))
+ pos length angle parent center-angle rotation-range phase-offset)
-(define-with-macro arm pos length angle parent)
+(defun make-arm (length center-angle rotation-range parent phase-offset)
+ (%make-arm :pos (vec2 0 0)
+ :length length
+ :angle center-angle
+ :parent parent
+ :center-angle center-angle
+ :rotation-range rotation-range
+ :phase-offset phase-offset))
+(define-with-macro arm pos length angle parent center-angle rotation-range phase-offset)
+
+
+(defun arm-set-phase (arm phase)
+ (with-arm arm
+ (setf angle (+ center-angle (* rotation-range (sin (+ phase-offset phase)))))))
(defun arm-total-angle (arm)
(loop :for a = arm :then (arm-parent a)
@@ -55,6 +68,50 @@
(with-pen pen (draw-line pos (arm-end arm)))))
+(defclass forward-kinematics-system ()
+ ((origin :type vec2 :initarg :origin :reader fks-origin)
+ (arms :type vector :initarg :arms :accessor fks-arms)
+ (last-arm :initarg :last-arm :accessor fks-last-arm)
+ (phase :initarg :phase :accessor fks-phase)
+ (speed :initform 0.05 :accessor fks-speed)))
+
+(defun make-fks (x y &optional (starting-phase 0.0))
+ (make-instance 'forward-kinematics-system
+ :origin (vec2 x y)
+ :arms (make-array 10 :fill-pointer 0)
+ :last-arm nil
+ :phase starting-phase))
+
+
+(defun fks-update (fks)
+ (iterate (with phase = (fks-phase fks))
+ (for arm :in-vector (fks-arms fks))
+ (for parent = (arm-parent arm))
+ (arm-set-phase arm phase)
+ (setf (arm-pos arm)
+ (if parent
+ (arm-end parent)
+ (fks-origin fks))))
+ (incf (fks-phase fks) (fks-speed fks))
+ (wrapf (fks-phase fks) 0 tau)
+ )
+
+
+(defun fks-add-arm (fks length center-angle rotation-range &optional (phase-offset 0.0))
+ (let* ((arm (make-arm length center-angle rotation-range
+ (fks-last-arm fks) phase-offset)))
+ (vector-push-extend arm (fks-arms fks) 10)
+ (setf (fks-last-arm fks) arm))
+ (fks-update fks))
+
+(defun draw-fks (fks)
+ (map nil #'draw-arm (fks-arms fks)))
+
+(defun fks-rotate-arm (fks arm-index angle)
+ (setf (arm-angle (aref (fks-arms fks) arm-index))
+ angle))
+
+
;;;; Sketch
(defun draw-particle (p)
(circle (particle-x p) (particle-y p) (particle-radius p)))
@@ -104,15 +161,16 @@
(total-time 0)
;; Data
(a 0.0)
- (arms (iterate (repeat 8)
- (for arm = (make-arm (if prev
- (arm-end prev)
- (vec2 0 0))
- (random-range 30 60)
- (random-around 0.0 (* tau 0.3))
- prev))
- (for prev :previous arm)
- (collect arm)))
+ (leg0 (make-fks 0 0))
+ (leg1 (make-fks 0 0 pi))
+ (lol (progn
+ (fks-add-arm leg0 90 (* tau -1/4) (* tau 1/6))
+ (fks-add-arm leg0 60 (* tau -1/12) (* tau 1/12) -1.5)
+ (fks-add-arm leg0 20 (* tau 1/5) (* tau (- 1/4 1/5)) -1.5)
+ (fks-add-arm leg1 90 (* tau -1/4) (* tau 1/6))
+ (fks-add-arm leg1 60 (* tau -1/12) (* tau 1/12) -1.5)
+ (fks-add-arm leg1 20 (* tau 1/5) (* tau (- 1/4 1/5)) -1.5)
+ ))
;; Pens
(particle-pen (make-pen :fill (gray 0.9) :stroke (gray 0.4)))
(black-pen (make-pen :stroke (rgb 0 0 0) :fill (rgb 0.4 0.4 0.4) :weight 1 :curve-steps 50))
@@ -129,20 +187,10 @@
(in-context
(translate *center-x* *center-y*)
- (incf a 0.03)
-
- (iterate
- (for arm :in arms)
- (for prev :previous arm)
- (for incr :first 1.0 :then (* incr 0.8))
- (if-first-time
- (setf (arm-angle arm) (* incr pi (sin a)))
- ;; uncomment to twirl vvvvv
- ; (setf (arm-angle arm) (* incr pi (sin a)))
- )
- (when prev
- (setf (arm-pos arm) (arm-end prev)))
- (draw-arm arm))
+ (fks-update leg0)
+ (fks-update leg1)
+ (draw-fks leg0)
+ (draw-fks leg1)
))
;;
--- a/src/vectors.lisp Sun Aug 14 21:17:02 2016 +0000
+++ b/src/vectors.lisp Sun Aug 14 22:37:23 2016 +0000
@@ -9,6 +9,7 @@
(defun symbolize (&rest args)
(intern (format nil "~{~A~}" args))))
+
(defun square (x)
(* x x))