comparison org/body.org @ 64:ab1fee4280c3

divided body into test suite and core functions
author Robert McIntyre <rlm@mit.edu>
date Wed, 30 Nov 2011 20:42:07 -0700
parents 7f2653ad3199
children 4b5f00110d8c
comparison
equal deleted inserted replaced
63:7f2653ad3199 64:ab1fee4280c3
3 #+email: rlm@mit.edu 3 #+email: rlm@mit.edu
4 #+description: Simulating a body (movement, touch, propioception) in jMonkeyEngine3. 4 #+description: Simulating a body (movement, touch, propioception) in jMonkeyEngine3.
5 #+SETUPFILE: ../../aurellem/org/setup.org 5 #+SETUPFILE: ../../aurellem/org/setup.org
6 #+INCLUDE: ../../aurellem/org/level-0.org 6 #+INCLUDE: ../../aurellem/org/level-0.org
7 7
8 * COMMENT Body 8
9 9
10 #+srcname: body-main 10 * Proprioception
11 #+srcname: proprioception
11 #+begin_src clojure 12 #+begin_src clojure
12 (ns cortex.body 13 (ns cortex.body
13 (use (cortex world util import))) 14 (:use (cortex world util))
14 15 (:import
15 (use 'clojure.contrib.def) 16 com.jme3.math.Vector3f
16 (cortex.import/mega-import-jme3) 17 com.jme3.math.Quaternion
17 (rlm.rlm-commands/help) 18 com.jme3.math.Vector2f
18 19 com.jme3.math.Matrix3f
19 (defn load-blender-model 20 com.jme3.bullet.control.RigidBodyControl))
20 "Load a .blend file using an asset folder relative path." 21
21 [^String model] 22 (defn any-orthogonal
22 (.loadModel
23 (doto (asset-manager)
24 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
25 model))
26
27 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28
29 ;;;;;;;;;;;; eve-style bodies ;;;;;;;;
30
31 (defn worm-segments
32 "Create multiple evenly spaced box segments. They're fabulous!"
33 [segment-length num-segments interstitial-space radius]
34 (letfn [(nth-segment
35 [n]
36 (box segment-length radius radius :mass 0.1
37 :position
38 (Vector3f.
39 (* 2 n (+ interstitial-space segment-length)) 0 0)
40 :name (str "worm-segment" n)
41 :color (ColorRGBA/randomColor)))]
42 (map nth-segment (range num-segments))))
43
44 (defn connect-at-midpoint
45 "Connect two physics objects with a Point2Point joint constraint at
46 the point equidistant from both objects' centers."
47 [segmentA segmentB]
48 (let [centerA (.getWorldTranslation segmentA)
49 centerB (.getWorldTranslation segmentB)
50 midpoint (.mult (.add centerA centerB) (float 0.5))
51 pivotA (.subtract midpoint centerA)
52 pivotB (.subtract midpoint centerB)
53
54 ;; A side-effect of creating a joint registers
55 ;; it with both physics objects which in turn
56 ;; will register the joint with the physics system
57 ;; when the simulation is started.
58 joint (Point2PointJoint.
59 (.getControl segmentA RigidBodyControl)
60 (.getControl segmentB RigidBodyControl)
61 pivotA
62 pivotB)]
63 segmentB))
64
65 (defn point-worm []
66 (let [segments (worm-segments 0.2 5 0.1 0.1)]
67 (dorun (map (partial apply connect-at-midpoint)
68 (partition 2 1 segments)))
69 (nodify "worm" segments)))
70
71 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
72 ;;;;;;;;; Proprioception ;;;;;;;;;;;;;
73 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
74
75 (declare
76 ;; generate an arbitray (but stable) orthogonal vector
77 ;; to a given vector.
78 some-orthogonal
79
80 ;; determine the amount of rotation a quaternion will
81 ;; cause about a given axis
82 project-quaternion
83
84 ;; proprioception for a single joint
85 joint-proprioception
86
87 ;; create a function that provides proprioceptive information
88 ;; about an entire body.
89 proprioception)
90
91 (defn some-orthogonal
92 "Generate an arbitray (but stable) orthogonal vector to a given 23 "Generate an arbitray (but stable) orthogonal vector to a given
93 vector." 24 vector."
94 [vector] 25 [vector]
95 (let [x (.getX vector) 26 (let [x (.getX vector)
96 y (.getY vector) 27 y (.getY vector)
106 component-of-a-quaternion-rotation-around-an-axis. 37 component-of-a-quaternion-rotation-around-an-axis.
107 38
108 Determine the amount of rotation a quaternion will 39 Determine the amount of rotation a quaternion will
109 cause about a given axis." 40 cause about a given axis."
110 [#^Quaternion q #^Vector3f axis] 41 [#^Quaternion q #^Vector3f axis]
111 (let [basis-1 (orthogonal-vect axis) 42 (let [basis-1 (any-orthogonal axis)
112 basis-2 (.cross axis basis-1) 43 basis-2 (.cross axis basis-1)
113 rotated (.mult q basis-1) 44 rotated (.mult q basis-1)
114 alpha (.dot basis-1 (.project rotated basis-1)) 45 alpha (.dot basis-1 (.project rotated basis-1))
115 beta (.dot basis-2 (.project rotated basis-2))] 46 beta (.dot basis-2 (.project rotated basis-2))]
116 (Math/atan2 beta alpha))) 47 (Math/atan2 beta alpha)))
145 (.angleBetween 76 (.angleBetween
146 (.normalize (Vector2f. (.getX arm-b) (.getZ arm-b))) 77 (.normalize (Vector2f. (.getX arm-b) (.getZ arm-b)))
147 (Vector2f. 1 0)) 78 (Vector2f. 1 0))
148 79
149 roll 80 roll
150 (rot-about-axis 81 (project-quaternion
151 (.mult 82 (.mult
152 (.getLocalRotation object-b) 83 (.getLocalRotation object-b)
153 (doto (Quaternion.) 84 (doto (Quaternion.)
154 (.fromRotationMatrix rotate-a))) 85 (.fromRotationMatrix rotate-a)))
155 arm-b)] 86 arm-b)]
169 #(.getControl % RigidBodyControl) 100 #(.getControl % RigidBodyControl)
170 (node-seq body)))))] 101 (node-seq body)))))]
171 (fn [] 102 (fn []
172 (map joint-proprioception joints)))) 103 (map joint-proprioception joints))))
173 104
174 105 #+end_src
175 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 106
176 ;;;;;;;;; Mortor Control ;;;;;;;;;;;;; 107 #+srcname: motor-control
177 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 108 #+begin_src clojure
178 109 (in-ns 'cortex.body)
179 110
180 ;; surprisingly enough, terristerial creatures only move by using 111 ;; surprisingly enough, terristerial creatures only move by using
181 ;; torque applied about their joints. There's not a single straight 112 ;; torque applied about their joints. There's not a single straight
182 ;; line of force in the human body at all! (A straight line of force 113 ;; line of force in the human body at all! (A straight line of force
183 ;; would correspond to some sort of jet or rocket propulseion.) 114 ;; would correspond to some sort of jet or rocket propulseion.)
189 (let [nodes (node-seq body) 120 (let [nodes (node-seq body)
190 controls (keep #(.getControl % RigidBodyControl) nodes)] 121 controls (keep #(.getControl % RigidBodyControl) nodes)]
191 (fn [torques] 122 (fn [torques]
192 (map #(.applyTorque %1 %2) 123 (map #(.applyTorque %1 %2)
193 controls torques)))) 124 controls torques))))
194
195 ;; note -- might want to add a lower dimensional, discrete version of
196 ;; this if it proves usefull from a x-modal clustering perspective.
197
198 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 125 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
199 126 #+end_src
200 127
201 128 ## note -- might want to add a lower dimensional, discrete version of
202 (defn worm-pattern [time] 129 ## this if it proves useful from a x-modal clustering perspective.
203 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 130
204 131 * Examples
205 0 0 0 0 0 0 0 0 0 0 0 132
206 133 #+srcname: test-body
207 (* 20 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300)))) 134 #+begin_src clojure
208 135 (ns test.body
209 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 136 (:use (cortex world util body))
210 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 137 (:import
211 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 com.jme3.math.Vector3f
212 139 com.jme3.math.ColorRGBA
213 ]) 140 com.jme3.bullet.joints.Point2PointJoint
214 141 com.jme3.bullet.control.RigidBodyControl
215 (defn worm-pattern [time] 142 com.jme3.system.NanoTimer))
216 (let [angle (* Math/PI (/ 4 20)) 143
144 (defn worm-segments
145 "Create multiple evenly spaced box segments. They're fabulous!"
146 [segment-length num-segments interstitial-space radius]
147 (letfn [(nth-segment
148 [n]
149 (box segment-length radius radius :mass 0.1
150 :position
151 (Vector3f.
152 (* 2 n (+ interstitial-space segment-length)) 0 0)
153 :name (str "worm-segment" n)
154 :color (ColorRGBA/randomColor)))]
155 (map nth-segment (range num-segments))))
156
157 (defn connect-at-midpoint
158 "Connect two physics objects with a Point2Point joint constraint at
159 the point equidistant from both objects' centers."
160 [segmentA segmentB]
161 (let [centerA (.getWorldTranslation segmentA)
162 centerB (.getWorldTranslation segmentB)
163 midpoint (.mult (.add centerA centerB) (float 0.5))
164 pivotA (.subtract midpoint centerA)
165 pivotB (.subtract midpoint centerB)
166
167 ;; A side-effect of creating a joint registers
168 ;; it with both physics objects which in turn
169 ;; will register the joint with the physics system
170 ;; when the simulation is started.
171 joint (Point2PointJoint.
172 (.getControl segmentA RigidBodyControl)
173 (.getControl segmentB RigidBodyControl)
174 pivotA
175 pivotB)]
176 segmentB))
177
178 (defn eve-worm
179 "Create a worm body bound by invisible joint constraints."
180 []
181 (let [segments (worm-segments 0.2 5 0.1 0.1)]
182 (dorun (map (partial apply connect-at-midpoint)
183 (partition 2 1 segments)))
184 (nodify "worm" segments)))
185
186 (defn worm-pattern
187 "This is a simple, mindless motor control pattern that drives the
188 second segment of the worm's body at an offset angle with
189 sinusoidally varying strength."
190 [time]
191 (let [angle (* Math/PI (/ 9 20))
217 direction (Vector3f. 0 (Math/sin angle) (Math/cos angle))] 192 direction (Vector3f. 0 (Math/sin angle) (Math/cos angle))]
218 [Vector3f/ZERO 193 [Vector3f/ZERO
219 (.mult 194 (.mult
220 direction 195 direction
221 (float (* 2 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300)))))) 196 (float (* 2 (Math/sin (* Math/PI 2 (/ (rem time 300 ) 300))))))
222 Vector3f/ZERO 197 Vector3f/ZERO
223 Vector3f/ZERO 198 Vector3f/ZERO
224 Vector3f/ZERO])) 199 Vector3f/ZERO]))
225 200
226 (defn test-worm-control 201 (defn test-motor-control
227 [] 202 "You should see a multi-segmented worm-like object fall onto the
228 (let [worm (point-worm) 203 table and begin writhing and moving."
204 []
205 (let [worm (eve-worm)
229 time (atom 0) 206 time (atom 0)
230 worm-motor-map (vector-motor-control worm)] 207 worm-motor-map (vector-motor-control worm)]
231 (world 208 (world
232 (nodify [worm 209 (nodify [worm
233 (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0 210 (box 10 0.5 10 :position (Vector3f. 0 -5 0) :mass 0
242 (file-str "/home/r/proj/cortex/tmp/moving-worm"))) 219 (file-str "/home/r/proj/cortex/tmp/moving-worm")))
243 ) 220 )
244 221
245 (fn [_ _] 222 (fn [_ _]
246 (swap! time inc) 223 (swap! time inc)
247 ;;(Thread/sleep 200) 224 (Thread/sleep 20)
248 (dorun (worm-motor-map 225 (dorun (worm-motor-map
249 (worm-pattern @time))))))) 226 (worm-pattern @time)))))))
250 227
251 228 (defn test-proprioception
252 229 "You should see two foating bars, and a printout of pitch, yaw, and
253 230 roll. Pressing key-r/key-t should move the blue bar up and down and
254 (defn test-prop 231 change only the value of pitch. key-f/key-g moves it side to side
255 "see how torque works." 232 and changes yaw. key-v/key-b will spin the blue segment clockwise
233 and counterclockwise, and only affect roll."
256 [] 234 []
257 (let [hand (box 1 0.2 0.2 :position (Vector3f. 0 2 0) 235 (let [hand (box 1 0.2 0.2 :position (Vector3f. 0 2 0)
258 :mass 0 :color ColorRGBA/Green) 236 :mass 0 :color ColorRGBA/Green)
259 finger (box 1 0.2 0.2 :position (Vector3f. 2.4 2 0) 237 finger (box 1 0.2 0.2 :position (Vector3f. 2.4 2 0)
260 :mass 1 :color (ColorRGBA. 0.20 0.40 0.99 1.0)) 238 :mass 1 :color (ColorRGBA. 0.20 0.40 0.99 1.0))
274 (.getControl hand RigidBodyControl) 252 (.getControl hand RigidBodyControl)
275 control 253 control
276 (Vector3f. 1.2 0 0) 254 (Vector3f. 1.2 0 0)
277 (Vector3f. -1.2 0 0 )) 255 (Vector3f. -1.2 0 0 ))
278 (.setCollisionBetweenLinkedBodys false)) 256 (.setCollisionBetweenLinkedBodys false))
279 time (atom 0) 257 time (atom 0)]
280 ]
281 (world 258 (world
282 (nodify [hand finger floor]) 259 (nodify [hand finger floor])
283 (merge standard-debug-controls 260 (merge standard-debug-controls
284 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?)) 261 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
285 "key-t" (fn [_ pressed?] (reset! move-down? pressed?)) 262 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
325 302
326 (apply 303 (apply
327 (comp 304 (comp
328 println-repl 305 println-repl
329 #(format "pitch: %1.2f\nyaw: %1.2f\nroll: %1.2f\n" %1 %2 %3)) 306 #(format "pitch: %1.2f\nyaw: %1.2f\nroll: %1.2f\n" %1 %2 %3))
330 (relative-positions joint)))))))) 307 (joint-proprioception joint))))))))
331
332 #+end_src 308 #+end_src
309
310 #+results: test-body
311 : #'test.body/test-proprioception
312
333 313
334 314
335 * COMMENT code-limbo 315 * COMMENT code-limbo
336 #+begin_src clojure 316 #+begin_src clojure
337 ;;(.loadModel 317 ;;(.loadModel
338 ;; (doto (asset-manager) 318 ;; (doto (asset-manager)
339 ;; (.registerLoader BlenderModelLoader (into-array String ["blend"]))) 319 ;; (.registerLoader BlenderModelLoader (into-array String ["blend"])))
340 ;; "Models/person/person.blend") 320 ;; "Models/person/person.blend")
321
322
323 (defn load-blender-model
324 "Load a .blend file using an asset folder relative path."
325 [^String model]
326 (.loadModel
327 (doto (asset-manager)
328 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
329 model))
330
341 331
342 (defn view-model [^String model] 332 (defn view-model [^String model]
343 (view 333 (view
344 (.loadModel 334 (.loadModel
345 (doto (asset-manager) 335 (doto (asset-manager)
755 745
756 746
757 747
758 * COMMENT generate Source. 748 * COMMENT generate Source.
759 #+begin_src clojure :tangle ../src/cortex/body.clj 749 #+begin_src clojure :tangle ../src/cortex/body.clj
760 <<body-main>> 750 <<proprioception>>
751 <<motor-control>>
761 #+end_src 752 #+end_src
753
754 #+begin_src clojure :tangle ../src/test/body.clj
755 <<test-body>>
756 #+end_src
757
758
762 759
763