comparison org/proprioception.org @ 259:7cac5ef852e3

proprioception rough draft complete.
author Robert McIntyre <rlm@mit.edu>
date Tue, 14 Feb 2012 02:28:25 -0700
parents f4b67005b702
children c39b8b29a79e
comparison
equal deleted inserted replaced
258:f4b67005b702 259:7cac5ef852e3
35 simulates the muscle-spindles and joint capsules. I will deal with 35 simulates the muscle-spindles and joint capsules. I will deal with
36 Golgi tendon organs, which calculate muscle strain, in the [[./movement.org][next post]]. 36 Golgi tendon organs, which calculate muscle strain, in the [[./movement.org][next post]].
37 37
38 * Helper Functions 38 * Helper Functions
39 39
40 =(absolute-angle)= calculates the angle between two vectors, relative to a
41 third axis vector. This angle is the number of radians you have to
42 move counterclockwise around the axis vector to get from the first to
43 the second vector. It is not commutative like a normal dot-product
44 angle is.
45
40 #+name: helpers 46 #+name: helpers
41 #+begin_src clojure 47 #+begin_src clojure
42 (in-ns 'cortex.proprioception) 48 (in-ns 'cortex.proprioception)
43 49
44 (defn right-handed? 50 (defn right-handed?
47 orthogonal." 53 orthogonal."
48 [vec1 vec2 vec3] 54 [vec1 vec2 vec3]
49 (< 0 (.dot (.cross vec1 vec2) vec3))) 55 (< 0 (.dot (.cross vec1 vec2) vec3)))
50 56
51 (defn absolute-angle 57 (defn absolute-angle
52 "The angle between 'vec1 and 'vec2. Positive if the angle to get 58 "The angle between 'vec1 and 'vec2 around 'axis. In the range
53 from 'vec1 to 'vec2 is counterclockwise around 'axis, and negative 59 [0 (* 2 Math/PI)]."
54 otherwise."
55 [vec1 vec2 axis] 60 [vec1 vec2 axis]
56 (let [angle (.angleBetween vec1 vec2)] 61 (let [angle (.angleBetween vec1 vec2)]
57 (if (right-handed? vec1 vec2 axis) 62 (if (right-handed? vec1 vec2 axis)
58 angle (- (* 2 Math/PI) angle)))) 63 angle (- (* 2 Math/PI) angle))))
59 #+end_src 64 #+end_src
60 65
66 #+begin_src clojure :exports both
67 (in-ns 'cortex.proprioception)
68 (absolute-angle Vector3f/UNIT_X Vector3f/UNIT_Y Vector3f/UNIT_Z)
69 #+end_src
70
71 #+results:
72 : 1.5707964
73
74 #+begin_src clojure :exports both
75 (in-ns 'cortex.proprioception)
76 (absolute-angle
77 Vector3f/UNIT_X (.mult Vector3f/UNIT_Y (float -1)) Vector3f/UNIT_Z)
78 #+end_src
79
80 #+results:
81 : 4.7123889366733
82
61 * Proprioception Kernel 83 * Proprioception Kernel
84
85 Given a joint, =(proprioception-kernel)= produces a function that
86 calculates the euler angles between the the objects the joint
87 connects.
62 88
63 #+name: proprioception 89 #+name: proprioception
64 #+begin_src clojure 90 #+begin_src clojure
65 (defn proprioception-kernel 91 (defn proprioception-kernel
66 "Returns a function which returns proprioceptive sensory data when 92 "Returns a function which returns proprioceptive sensory data when
69 (let [[obj-a obj-b] (joint-targets parts joint) 95 (let [[obj-a obj-b] (joint-targets parts joint)
70 joint-rot (.getWorldRotation joint) 96 joint-rot (.getWorldRotation joint)
71 x0 (.mult joint-rot Vector3f/UNIT_X) 97 x0 (.mult joint-rot Vector3f/UNIT_X)
72 y0 (.mult joint-rot Vector3f/UNIT_Y) 98 y0 (.mult joint-rot Vector3f/UNIT_Y)
73 z0 (.mult joint-rot Vector3f/UNIT_Z)] 99 z0 (.mult joint-rot Vector3f/UNIT_Z)]
74 (println-repl "x:" x0)
75 (println-repl "y:" y0)
76 (println-repl "z:" z0)
77 (println-repl "init-a:" (.getWorldRotation obj-a))
78 (println-repl "init-b:" (.getWorldRotation obj-b))
79
80 (fn [] 100 (fn []
81 (let [rot-a (.clone (.getWorldRotation obj-a)) 101 (let [rot-a (.clone (.getWorldRotation obj-a))
82 rot-b (.clone (.getWorldRotation obj-b)) 102 rot-b (.clone (.getWorldRotation obj-b))
83 x (.mult rot-a x0) 103 x (.mult rot-a x0)
84 y (.mult rot-a y0) 104 y (.mult rot-a y0)
111 (joints creature))] 131 (joints creature))]
112 (fn [] 132 (fn []
113 (map #(%) senses)))) 133 (map #(%) senses))))
114 #+end_src 134 #+end_src
115 135
136
137 =(proprioception!)= maps =(proprioception-kernel)= across all the
138 joints of the creature. It uses the same list of joints that
139 =(cortex.body/joints)= uses.
140
116 * Visualizing Proprioception 141 * Visualizing Proprioception
142
143 Proprioception has the lowest bandwidth of all the senses so far, and
144 it doesn't lend itself as readily to visual representation like
145 vision, hearing, or touch. This visualization code creates a "guage"
146 to view each of the three relative angles along a circle.
117 147
118 #+name: visualize 148 #+name: visualize
119 #+begin_src clojure 149 #+begin_src clojure
120 (in-ns 'cortex.proprioception) 150 (in-ns 'cortex.proprioception)
121 151
138 (+ 25 (int (* -20 (Math/sin angle))))]] 168 (+ 25 (int (* -20 (Math/sin angle))))]]
139 (draw-sprite image sprite (@previous 0) (@previous 1) 0x000000) 169 (draw-sprite image sprite (@previous 0) (@previous 1) 0x000000)
140 (draw-sprite image sprite (position 0) (position 1) color) 170 (draw-sprite image sprite (position 0) (position 1) color)
141 (reset! previous position)) 171 (reset! previous position))
142 image)))) 172 image))))
143
144 173
145 (defn proprioception-display-kernel 174 (defn proprioception-display-kernel
146 "Display proprioception angles in a BufferedImage" 175 "Display proprioception angles in a BufferedImage"
147 [[h p r]] 176 [[h p r]]
148 (let [image (BufferedImage. 50 50 BufferedImage/TYPE_INT_RGB) 177 (let [image (BufferedImage. 50 50 BufferedImage/TYPE_INT_RGB)
175 display each element of the list to the screen as an image." 204 display each element of the list to the screen as an image."
176 [] 205 []
177 (view-sense proprioception-display-kernel)) 206 (view-sense proprioception-display-kernel))
178 #+end_src 207 #+end_src
179 208
180 * Demonstration of Proprioception 209 * Proprioception Test
181 210 This test does not use the worm, but instead uses two bars, bound
182 #+name: test-body 211 together by a point2point joint. One bar is fixed, and I control the
183 #+begin_src clojure 212 other bar from the keyboard.
213
214 #+name: test-proprioception
215 #+begin_src clojure
216 (in-ns 'cortex.test.proprioception)
217
184 (defn test-proprioception 218 (defn test-proprioception
185 "Testing proprioception: 219 "Testing proprioception:
186 You should see two foating bars, and a printout of pitch, yaw, and 220 You should see two foating bars, and a printout of pitch, yaw, and
187 roll. Pressing key-r/key-t should move the blue bar up and down and 221 roll. Pressing key-r/key-t should move the blue bar up and down and
188 change only the value of pitch. key-f/key-g moves it side to side 222 change only the value of pitch. key-f/key-g moves it side to side
189 and changes yaw. key-v/key-b will spin the blue segment clockwise 223 and changes yaw. key-v/key-b will spin the blue segment clockwise
190 and counterclockwise, and only affect roll." 224 and counterclockwise, and only affect roll."
191 [] 225 ([] (test-proprioception false))
192 (let [hand (box 0.2 1 0.2 :position (Vector3f. 0 0 0) 226 ([record?]
193 :mass 0 :color ColorRGBA/Green :name "hand") 227 (let [hand (box 0.2 1 0.2 :position (Vector3f. 0 0 0)
194 finger (box 0.2 1 0.2 :position (Vector3f. 0 2.4 0) 228 :mass 0 :color ColorRGBA/Gray :name "hand")
195 :mass 1 :color ColorRGBA/Red :name "finger") 229 finger (box 0.2 1 0.2 :position (Vector3f. 0 2.4 0)
196 joint-node (box 0.1 0.05 0.05 :color ColorRGBA/Yellow 230 :mass 1
197 :position (Vector3f. 0 1.2 0) 231 :color
198 :rotation (doto (Quaternion.) 232 (ColorRGBA. (/ 184 255) (/ 127 255) (/ 201 255) 1)
199 (.fromAngleAxis 233 :name "finger")
200 (/ Math/PI 2) 234 joint-node (box 0.1 0.05 0.05 :color ColorRGBA/Yellow
201 (Vector3f. 0 0 1))) 235 :position (Vector3f. 0 1.2 0)
202 :physical? false) 236 :rotation (doto (Quaternion.)
203 joint (join-at-point hand finger (Vector3f. 0 1.2 0 )) 237 (.fromAngleAxis
204 creature (nodify [hand finger joint-node]) 238 (/ Math/PI 2)
205 finger-control (.getControl finger RigidBodyControl) 239 (Vector3f. 0 0 1)))
206 hand-control (.getControl hand RigidBodyControl)] 240 :physical? false)
207 241 creature (nodify [hand finger joint-node])
208 242 finger-control (.getControl finger RigidBodyControl)
209 (let 243 hand-control (.getControl hand RigidBodyControl)
210 ;; ******************************************* 244 joint (joint-dispatch {:type :point} hand-control finger-control
211 245 (Vector3f. 0 1.2 0)
212 [floor (box 10 10 10 :position (Vector3f. 0 -15 0) 246 (Vector3f. 0 -1.2 0) nil)
213 :mass 0 :color ColorRGBA/Gray) 247
214 248 root (nodify [creature])
215 root (nodify [creature floor]) 249 prop (proprioception-kernel creature joint-node)
216 prop (joint-proprioception creature joint-node) 250 prop-view (view-proprioception)]
217 prop-view (proprioception-debug-window) 251 (.setCollisionGroup
218 252 (.getControl hand RigidBodyControl)
219 controls 253 PhysicsCollisionObject/COLLISION_GROUP_NONE)
220 (merge standard-debug-controls 254 (apply
221 {"key-o" 255 world
222 (fn [_ _] (.setEnabled finger-control true)) 256 (with-movement
223 "key-p" 257 finger
224 (fn [_ _] (.setEnabled finger-control false)) 258 ["key-r" "key-t" "key-f" "key-g" "key-v" "key-b"]
225 "key-k" 259 [1 1 10 10 10 10]
226 (fn [_ _] (.setEnabled hand-control true)) 260 [root
227 "key-l" 261 standard-debug-controls
228 (fn [_ _] (.setEnabled hand-control false)) 262 (fn [world]
229 "key-i" 263 (if record?
230 (fn [world _] (set-gravity world (Vector3f. 0 0 0))) 264 (Capture/captureVideo
231 "key-period" 265 world
232 (fn [world _] 266 (File. "/home/r/proj/cortex/render/proprio/main-view")))
233 (.setEnabled finger-control false) 267 (.setTimer world (com.aurellem.capture.RatchetTimer. 60))
234 (.setEnabled hand-control false) 268 (set-gravity world (Vector3f. 0 0 0))
235 (.rotate creature (doto (Quaternion.) 269 (enable-debug world)
236 (.fromAngleAxis 270 (light-up-everything world))
237 (float (/ Math/PI 15)) 271 (fn [_ _]
238 (Vector3f. 0 0 -1)))) 272 (prop-view
239 273 (list (prop))
240 (.setEnabled finger-control true) 274 (if record?
241 (.setEnabled hand-control true) 275 (File. "/home/r/proj/cortex/render/proprio/proprio"))))])))))
242 (set-gravity world (Vector3f. 0 0 0)) 276 #+end_src
243 ) 277
244 278 #+results: test-proprioception
245 279 : #'cortex.test.proprioception/test-proprioception
246 } 280
247 ) 281 * Video of Proprioception
248 282
249 ] 283 #+begin_html
250 (comment 284 <div class="figure">
251 (.setCollisionGroup 285 <center>
252 (.getControl hand RigidBodyControl) 286 <video controls="controls" width="550">
253 PhysicsCollisionObject/COLLISION_GROUP_NONE) 287 <source src="../video/test-proprioception.ogg" type="video/ogg"
254 ) 288 preload="none" poster="../images/aurellem-1280x480.png" />
255 (apply 289 </video>
256 world 290 </center>
257 (with-movement 291 <p>Proprioception in a simple creature. The proprioceptive readout is
258 hand 292 in the upper left corner of the screen.</p>
259 ["key-y" "key-u" "key-h" "key-j" "key-n" "key-m"] 293 </div>
260 [10 10 10 10 1 1] 294 #+end_html
261 (with-movement 295
262 finger 296 ** Generating the Proprioception Video
263 ["key-r" "key-t" "key-f" "key-g" "key-v" "key-b"] 297 #+name: magick6
264 [1 1 10 10 10 10] 298 #+begin_src clojure
265 [root 299 (ns cortex.video.magick6
266 controls 300 (:import java.io.File)
267 (fn [world] 301 (:use clojure.contrib.shell-out))
268 (.setTimer world (com.aurellem.capture.RatchetTimer. 60)) 302
269 (set-gravity world (Vector3f. 0 0 0)) 303 (defn images [path]
270 (light-up-everything world)) 304 (sort (rest (file-seq (File. path)))))
271 (fn [_ _] (prop-view (list (prop))))])))))) 305
306 (def base "/home/r/proj/cortex/render/proprio/")
307
308 (defn pics [file]
309 (images (str base file)))
310
311 (defn combine-images []
312 (let [main-view (pics "main-view")
313 proprioception (pics "proprio/0")
314 targets (map
315 #(File. (str base "out/" (format "%07d.png" %)))
316 (range 0 (count main-view)))]
317 (dorun
318 (pmap
319 (comp
320 (fn [[ main-view proprioception target]]
321 (println target)
322 (sh "convert"
323 main-view
324 proprioception "-geometry" "+20+20" "-composite"
325 target))
326 (fn [& args] (map #(.getCanonicalPath %) args)))
327 main-view proprioception targets))))
328 #+end_src
329
330 #+begin_src sh :results silent
331 cd ~/proj/cortex/render/proprio
332 ffmpeg -r 60 -i out/%07d.png -b:v 9000k -c:v libtheora \
333 test-proprioception.ogg
272 #+end_src 334 #+end_src
273 335
274 * Headers 336 * Headers
275 #+name: proprioception-header 337 #+name: proprioception-header
276 #+begin_src clojure 338 #+begin_src clojure
284 (:import com.jme3.scene.Node) 346 (:import com.jme3.scene.Node)
285 (:import java.awt.image.BufferedImage) 347 (:import java.awt.image.BufferedImage)
286 (:import (com.jme3.math Vector3f Quaternion))) 348 (:import (com.jme3.math Vector3f Quaternion)))
287 #+end_src 349 #+end_src
288 350
351 #+name: test-proprioception-header
352 #+begin_src clojure
353 (ns cortex.test.proprioception
354 (:import (com.aurellem.capture Capture RatchetTimer))
355 (:use (cortex util world proprioception body))
356 (:import java.io.File))
357 (cortex.import/mega-import-jme3)
358 #+end_src
359
360 * Source Listing
361 - [[../src/cortex/proprioception.clj][cortex.proprioception]]
362 - [[../src/cortex/test/touch.clj][cortex.test.proprioception]]
363 - [[../src/cortex/video/magick6.clj][cortex.video.magick6]]
364 #+html: <ul> <li> <a href="../org/proprioception.org">This org file</a> </li> </ul>
365 - [[http://hg.bortreb.com ][source-repository]]
366
367 * Next
368
369 Next time, I'll give the Worm the power to [[./movement.org][move on it's own]].
370
289 371
290 * COMMENT generate source 372 * COMMENT generate source
291 #+begin_src clojure :tangle ../src/cortex/proprioception.clj 373 #+begin_src clojure :tangle ../src/cortex/proprioception.clj
292 <<proprioception-header>> 374 <<proprioception-header>>
293 <<helpers>> 375 <<helpers>>
294 <<proprioception>> 376 <<proprioception>>
295 <<visualize>> 377 <<visualize>>
296 #+end_src 378 #+end_src
379
380 #+begin_src clojure :tangle ../src/cortex/test/proprioception.clj
381 <<test-proprioception-header>>
382 <<test-proprioception>>
383 #+end_src
384
385 #+begin_src clojure :tangle ../src/cortex/video/magick6.clj
386 <<magick6>>
387 #+end_src