view org/proprioception.org @ 258:f4b67005b702

reorganized proprioception
author Robert McIntyre <rlm@mit.edu>
date Tue, 14 Feb 2012 00:39:16 -0700
parents 5d7961d7fded
children 7cac5ef852e3
line wrap: on
line source
1 #+title: The Sense of Proprioception
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description: proprioception for simulated creatures
5 #+keywords: simulation, jMonkeyEngine3, clojure
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
9 * Proprioception
11 Close your eyes, and touch your nose with your right index finger. How
12 did you do it? You could not see your hand, and neither your hand nor
13 your nose could use the sense of touch to guide the path of your hand.
14 There are no sound cues, and Taste and Smell certainly don't provide
15 any help. You know where your hand is without your other senses
16 because of Proprioception.
18 Humans can sometimes loose this sense through viral infections or
19 damage to the spinal cord or brain, and when they do, they loose the
20 ability to control their own bodies without looking directly at the
21 parts they want to move. In [[http://en.wikipedia.org/wiki/The_Man_Who_Mistook_His_Wife_for_a_Hat][The Man Who Mistook His Wife for a Hat]],
22 a woman named Christina looses this sense and has to learn how to move
23 by carefully watching her arms and legs. She describes proprioception
24 as the "eyes of the body, the way the body sees itself".
26 Proprioception in humans is mediated by [[http://en.wikipedia.org/wiki/Articular_capsule][joint capsules]], [[http://en.wikipedia.org/wiki/Muscle_spindle][muscle
27 spindles]], and the [[http://en.wikipedia.org/wiki/Golgi_tendon_organ][Golgi tendon organs]]. These measure the relative
28 positions of each pody part by monitoring muscle strain and length.
30 It's clear that this is a vital sense for fulid, graceful
31 movement. It's also particurally easy to implement in jMonkeyEngine.
33 My simulated proprioception calculates the relative angles of each
34 joint from the rest position defined in the blender file. This
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]].
38 * Helper Functions
40 #+name: helpers
41 #+begin_src clojure
42 (in-ns 'cortex.proprioception)
44 (defn right-handed?
45 "true iff the three vectors form a right handed coordinate
46 system. The three vectors do not have to be normalized or
47 orthogonal."
48 [vec1 vec2 vec3]
49 (< 0 (.dot (.cross vec1 vec2) vec3)))
51 (defn absolute-angle
52 "The angle between 'vec1 and 'vec2. Positive if the angle to get
53 from 'vec1 to 'vec2 is counterclockwise around 'axis, and negative
54 otherwise."
55 [vec1 vec2 axis]
56 (let [angle (.angleBetween vec1 vec2)]
57 (if (right-handed? vec1 vec2 axis)
58 angle (- (* 2 Math/PI) angle))))
59 #+end_src
61 * Proprioception Kernel
63 #+name: proprioception
64 #+begin_src clojure
65 (defn proprioception-kernel
66 "Returns a function which returns proprioceptive sensory data when
67 called inside a running simulation."
68 [#^Node parts #^Node joint]
69 (let [[obj-a obj-b] (joint-targets parts joint)
70 joint-rot (.getWorldRotation joint)
71 x0 (.mult joint-rot Vector3f/UNIT_X)
72 y0 (.mult joint-rot Vector3f/UNIT_Y)
73 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))
80 (fn []
81 (let [rot-a (.clone (.getWorldRotation obj-a))
82 rot-b (.clone (.getWorldRotation obj-b))
83 x (.mult rot-a x0)
84 y (.mult rot-a y0)
85 z (.mult rot-a z0)
87 X (.mult rot-b x0)
88 Y (.mult rot-b y0)
89 Z (.mult rot-b z0)
90 heading (Math/atan2 (.dot X z) (.dot X x))
91 pitch (Math/atan2 (.dot X y) (.dot X x))
93 ;; rotate x-vector back to origin
94 reverse
95 (doto (Quaternion.)
96 (.fromAngleAxis
97 (.angleBetween X x)
98 (let [cross (.normalize (.cross X x))]
99 (if (= 0 (.length cross)) y cross))))
100 roll (absolute-angle (.mult reverse Y) y x)]
101 [heading pitch roll]))))
103 (defn proprioception!
104 "Endow the creature with the sense of proprioception. Returns a
105 sequence of functions, one for each child of the \"joints\" node in
106 the creature, which each report proprioceptive information about
107 that joint."
108 [#^Node creature]
109 ;; extract the body's joints
110 (let [senses (map (partial proprioception-kernel creature)
111 (joints creature))]
112 (fn []
113 (map #(%) senses))))
114 #+end_src
116 * Visualizing Proprioception
118 #+name: visualize
119 #+begin_src clojure
120 (in-ns 'cortex.proprioception)
122 (defn draw-sprite [image sprite x y color ]
123 (dorun
124 (for [[u v] sprite]
125 (.setRGB image (+ u x) (+ v y) color))))
127 (defn view-angle
128 "create a debug view of an angle"
129 [color]
130 (let [image (BufferedImage. 50 50 BufferedImage/TYPE_INT_RGB)
131 previous (atom [25 25])
132 sprite [[0 0] [0 1]
133 [0 -1] [-1 0] [1 0]]]
134 (fn [angle]
135 (let [angle (float angle)]
136 (let [position
137 [(+ 25 (int (* 20 (Math/cos angle))))
138 (+ 25 (int (* -20 (Math/sin angle))))]]
139 (draw-sprite image sprite (@previous 0) (@previous 1) 0x000000)
140 (draw-sprite image sprite (position 0) (position 1) color)
141 (reset! previous position))
142 image))))
145 (defn proprioception-display-kernel
146 "Display proprioception angles in a BufferedImage"
147 [[h p r]]
148 (let [image (BufferedImage. 50 50 BufferedImage/TYPE_INT_RGB)
149 previous-heading (atom [25 25])
150 previous-pitch (atom [25 25])
151 previous-roll (atom [25 25])
153 heading-sprite [[0 0] [0 1] [0 -1] [-1 0] [1 0]]
154 pitch-sprite [[0 0] [0 1] [0 -1] [-1 0] [1 0]]
155 roll-sprite [[0 0] [0 1] [0 -1] [-1 0] [1 0]]
156 draw-angle
157 (fn [angle sprite previous color]
158 (let [angle (float angle)]
159 (let [position
160 [(+ 25 (int (* 20 (Math/cos angle))))
161 (+ 25 (int (* -20 (Math/sin angle))))]]
162 (draw-sprite image sprite (@previous 0) (@previous 1) 0x000000)
163 (draw-sprite image sprite (position 0) (position 1) color)
164 (reset! previous position))
165 image))]
166 (dorun (map draw-angle
167 [h p r]
168 [heading-sprite pitch-sprite roll-sprite]
169 [previous-heading previous-pitch previous-roll]
170 [0xFF0000 0x00FF00 0xFFFFFF]))
171 image))
173 (defn view-proprioception
174 "Creates a function which accepts a list of proprioceptive data and
175 display each element of the list to the screen as an image."
176 []
177 (view-sense proprioception-display-kernel))
178 #+end_src
180 * Demonstration of Proprioception
182 #+name: test-body
183 #+begin_src clojure
184 (defn test-proprioception
185 "Testing proprioception:
186 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
188 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
190 and counterclockwise, and only affect roll."
191 []
192 (let [hand (box 0.2 1 0.2 :position (Vector3f. 0 0 0)
193 :mass 0 :color ColorRGBA/Green :name "hand")
194 finger (box 0.2 1 0.2 :position (Vector3f. 0 2.4 0)
195 :mass 1 :color ColorRGBA/Red :name "finger")
196 joint-node (box 0.1 0.05 0.05 :color ColorRGBA/Yellow
197 :position (Vector3f. 0 1.2 0)
198 :rotation (doto (Quaternion.)
199 (.fromAngleAxis
200 (/ Math/PI 2)
201 (Vector3f. 0 0 1)))
202 :physical? false)
203 joint (join-at-point hand finger (Vector3f. 0 1.2 0 ))
204 creature (nodify [hand finger joint-node])
205 finger-control (.getControl finger RigidBodyControl)
206 hand-control (.getControl hand RigidBodyControl)]
209 (let
210 ;; *******************************************
212 [floor (box 10 10 10 :position (Vector3f. 0 -15 0)
213 :mass 0 :color ColorRGBA/Gray)
215 root (nodify [creature floor])
216 prop (joint-proprioception creature joint-node)
217 prop-view (proprioception-debug-window)
219 controls
220 (merge standard-debug-controls
221 {"key-o"
222 (fn [_ _] (.setEnabled finger-control true))
223 "key-p"
224 (fn [_ _] (.setEnabled finger-control false))
225 "key-k"
226 (fn [_ _] (.setEnabled hand-control true))
227 "key-l"
228 (fn [_ _] (.setEnabled hand-control false))
229 "key-i"
230 (fn [world _] (set-gravity world (Vector3f. 0 0 0)))
231 "key-period"
232 (fn [world _]
233 (.setEnabled finger-control false)
234 (.setEnabled hand-control false)
235 (.rotate creature (doto (Quaternion.)
236 (.fromAngleAxis
237 (float (/ Math/PI 15))
238 (Vector3f. 0 0 -1))))
240 (.setEnabled finger-control true)
241 (.setEnabled hand-control true)
242 (set-gravity world (Vector3f. 0 0 0))
243 )
246 }
247 )
249 ]
250 (comment
251 (.setCollisionGroup
252 (.getControl hand RigidBodyControl)
253 PhysicsCollisionObject/COLLISION_GROUP_NONE)
254 )
255 (apply
256 world
257 (with-movement
258 hand
259 ["key-y" "key-u" "key-h" "key-j" "key-n" "key-m"]
260 [10 10 10 10 1 1]
261 (with-movement
262 finger
263 ["key-r" "key-t" "key-f" "key-g" "key-v" "key-b"]
264 [1 1 10 10 10 10]
265 [root
266 controls
267 (fn [world]
268 (.setTimer world (com.aurellem.capture.RatchetTimer. 60))
269 (set-gravity world (Vector3f. 0 0 0))
270 (light-up-everything world))
271 (fn [_ _] (prop-view (list (prop))))]))))))
272 #+end_src
274 * Headers
275 #+name: proprioception-header
276 #+begin_src clojure
277 (ns cortex.proprioception
278 "Simulate the sense of proprioception (ability to detect the
279 relative positions of body parts with repsect to other body parts)
280 in jMonkeyEngine3. Reads specially prepared blender files to
281 automatically generate proprioceptive senses."
282 (:use (cortex world util sense body))
283 (:use clojure.contrib.def)
284 (:import com.jme3.scene.Node)
285 (:import java.awt.image.BufferedImage)
286 (:import (com.jme3.math Vector3f Quaternion)))
287 #+end_src
290 * COMMENT generate source
291 #+begin_src clojure :tangle ../src/cortex/proprioception.clj
292 <<proprioception-header>>
293 <<helpers>>
294 <<proprioception>>
295 <<visualize>>
296 #+end_src