view org/proprioception.org @ 257:5d7961d7fded

wrote intro text for proprioception
author Robert McIntyre <rlm@mit.edu>
date Tue, 14 Feb 2012 00:37:42 -0700
parents df46a609fed9
children f4b67005b702
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
41 #+name: helpers
42 #+begin_src clojure
43 (in-ns 'cortex.proprioception)
45 (defn right-handed?
46 "true iff the three vectors form a right handed coordinate
47 system. The three vectors do not have to be normalized or
48 orthogonal."
49 [vec1 vec2 vec3]
50 (< 0 (.dot (.cross vec1 vec2) vec3)))
52 (defn absolute-angle
53 "The angle between 'vec1 and 'vec2. Positive if the angle to get
54 from 'vec1 to 'vec2 is counterclockwise around 'axis, and negative
55 otherwise."
56 [vec1 vec2 axis]
57 (let [angle (.angleBetween vec1 vec2)]
58 (if (right-handed? vec1 vec2 axis)
59 angle (- (* 2 Math/PI) angle))))
60 #+end_src
62 #+name: proprioception
63 #+begin_src clojure
64 (defn proprioception-kernel
65 "Returns a function which returns proprioceptive sensory data when
66 called inside a running simulation."
67 [#^Node parts #^Node joint]
68 (let [[obj-a obj-b] (joint-targets parts joint)
69 joint-rot (.getWorldRotation joint)
70 x0 (.mult joint-rot Vector3f/UNIT_X)
71 y0 (.mult joint-rot Vector3f/UNIT_Y)
72 z0 (.mult joint-rot Vector3f/UNIT_Z)]
73 (println-repl "x:" x0)
74 (println-repl "y:" y0)
75 (println-repl "z:" z0)
76 (println-repl "init-a:" (.getWorldRotation obj-a))
77 (println-repl "init-b:" (.getWorldRotation obj-b))
79 (fn []
80 (let [rot-a (.clone (.getWorldRotation obj-a))
81 rot-b (.clone (.getWorldRotation obj-b))
82 x (.mult rot-a x0)
83 y (.mult rot-a y0)
84 z (.mult rot-a z0)
86 X (.mult rot-b x0)
87 Y (.mult rot-b y0)
88 Z (.mult rot-b z0)
89 heading (Math/atan2 (.dot X z) (.dot X x))
90 pitch (Math/atan2 (.dot X y) (.dot X x))
92 ;; rotate x-vector back to origin
93 reverse
94 (doto (Quaternion.)
95 (.fromAngleAxis
96 (.angleBetween X x)
97 (let [cross (.normalize (.cross X x))]
98 (if (= 0 (.length cross)) y cross))))
99 roll (absolute-angle (.mult reverse Y) y x)]
100 [heading pitch roll]))))
102 (defn proprioception!
103 "Endow the creature with the sense of proprioception. Returns a
104 sequence of functions, one for each child of the \"joints\" node in
105 the creature, which each report proprioceptive information about
106 that joint."
107 [#^Node creature]
108 ;; extract the body's joints
109 (let [senses (map (partial proprioception-kernel creature)
110 (joints creature))]
111 (fn []
112 (map #(%) senses))))
113 #+end_src
115 #+name: visualize
116 #+begin_src clojure
117 (in-ns 'cortex.proprioception)
119 (defn draw-sprite [image sprite x y color ]
120 (dorun
121 (for [[u v] sprite]
122 (.setRGB image (+ u x) (+ v y) color))))
124 (defn view-angle
125 "create a debug view of an angle"
126 [color]
127 (let [image (BufferedImage. 50 50 BufferedImage/TYPE_INT_RGB)
128 previous (atom [25 25])
129 sprite [[0 0] [0 1]
130 [0 -1] [-1 0] [1 0]]]
131 (fn [angle]
132 (let [angle (float angle)]
133 (let [position
134 [(+ 25 (int (* 20 (Math/cos angle))))
135 (+ 25 (int (* -20 (Math/sin angle))))]]
136 (draw-sprite image sprite (@previous 0) (@previous 1) 0x000000)
137 (draw-sprite image sprite (position 0) (position 1) color)
138 (reset! previous position))
139 image))))
142 (defn proprioception-display-kernel
143 "Display proprioception angles in a BufferedImage"
144 [[h p r]]
145 (let [image (BufferedImage. 50 50 BufferedImage/TYPE_INT_RGB)
146 previous-heading (atom [25 25])
147 previous-pitch (atom [25 25])
148 previous-roll (atom [25 25])
150 heading-sprite [[0 0] [0 1] [0 -1] [-1 0] [1 0]]
151 pitch-sprite [[0 0] [0 1] [0 -1] [-1 0] [1 0]]
152 roll-sprite [[0 0] [0 1] [0 -1] [-1 0] [1 0]]
153 draw-angle
154 (fn [angle sprite previous color]
155 (let [angle (float angle)]
156 (let [position
157 [(+ 25 (int (* 20 (Math/cos angle))))
158 (+ 25 (int (* -20 (Math/sin angle))))]]
159 (draw-sprite image sprite (@previous 0) (@previous 1) 0x000000)
160 (draw-sprite image sprite (position 0) (position 1) color)
161 (reset! previous position))
162 image))]
163 (dorun (map draw-angle
164 [h p r]
165 [heading-sprite pitch-sprite roll-sprite]
166 [previous-heading previous-pitch previous-roll]
167 [0xFF0000 0x00FF00 0xFFFFFF]))
168 image))
170 (defn view-proprioception
171 "Creates a function which accepts a list of proprioceptive data and
172 display each element of the list to the screen as an image."
173 []
174 (view-sense proprioception-display-kernel))
175 #+end_src
177 #+name: proprioception-header
178 #+begin_src clojure
179 (ns cortex.proprioception
180 "Simulate the sense of proprioception (ability to detect the
181 relative positions of body parts with repsect to other body parts)
182 in jMonkeyEngine3. Reads specially prepared blender files to
183 automatically generate proprioceptive senses."
184 (:use (cortex world util sense body))
185 (:use clojure.contrib.def)
186 (:import com.jme3.scene.Node)
187 (:import java.awt.image.BufferedImage)
188 (:import (com.jme3.math Vector3f Quaternion)))
189 #+end_src
191 #+name: test-body
192 #+begin_src clojure
193 (defn test-proprioception
194 "Testing proprioception:
195 You should see two foating bars, and a printout of pitch, yaw, and
196 roll. Pressing key-r/key-t should move the blue bar up and down and
197 change only the value of pitch. key-f/key-g moves it side to side
198 and changes yaw. key-v/key-b will spin the blue segment clockwise
199 and counterclockwise, and only affect roll."
200 []
201 (let [hand (box 0.2 1 0.2 :position (Vector3f. 0 0 0)
202 :mass 0 :color ColorRGBA/Green :name "hand")
203 finger (box 0.2 1 0.2 :position (Vector3f. 0 2.4 0)
204 :mass 1 :color ColorRGBA/Red :name "finger")
205 joint-node (box 0.1 0.05 0.05 :color ColorRGBA/Yellow
206 :position (Vector3f. 0 1.2 0)
207 :rotation (doto (Quaternion.)
208 (.fromAngleAxis
209 (/ Math/PI 2)
210 (Vector3f. 0 0 1)))
211 :physical? false)
212 joint (join-at-point hand finger (Vector3f. 0 1.2 0 ))
213 creature (nodify [hand finger joint-node])
214 finger-control (.getControl finger RigidBodyControl)
215 hand-control (.getControl hand RigidBodyControl)]
218 (let
219 ;; *******************************************
221 [floor (box 10 10 10 :position (Vector3f. 0 -15 0)
222 :mass 0 :color ColorRGBA/Gray)
224 root (nodify [creature floor])
225 prop (joint-proprioception creature joint-node)
226 prop-view (proprioception-debug-window)
228 controls
229 (merge standard-debug-controls
230 {"key-o"
231 (fn [_ _] (.setEnabled finger-control true))
232 "key-p"
233 (fn [_ _] (.setEnabled finger-control false))
234 "key-k"
235 (fn [_ _] (.setEnabled hand-control true))
236 "key-l"
237 (fn [_ _] (.setEnabled hand-control false))
238 "key-i"
239 (fn [world _] (set-gravity world (Vector3f. 0 0 0)))
240 "key-period"
241 (fn [world _]
242 (.setEnabled finger-control false)
243 (.setEnabled hand-control false)
244 (.rotate creature (doto (Quaternion.)
245 (.fromAngleAxis
246 (float (/ Math/PI 15))
247 (Vector3f. 0 0 -1))))
249 (.setEnabled finger-control true)
250 (.setEnabled hand-control true)
251 (set-gravity world (Vector3f. 0 0 0))
252 )
255 }
256 )
258 ]
259 (comment
260 (.setCollisionGroup
261 (.getControl hand RigidBodyControl)
262 PhysicsCollisionObject/COLLISION_GROUP_NONE)
263 )
264 (apply
265 world
266 (with-movement
267 hand
268 ["key-y" "key-u" "key-h" "key-j" "key-n" "key-m"]
269 [10 10 10 10 1 1]
270 (with-movement
271 finger
272 ["key-r" "key-t" "key-f" "key-g" "key-v" "key-b"]
273 [1 1 10 10 10 10]
274 [root
275 controls
276 (fn [world]
277 (.setTimer world (com.aurellem.capture.RatchetTimer. 60))
278 (set-gravity world (Vector3f. 0 0 0))
279 (light-up-everything world))
280 (fn [_ _] (prop-view (list (prop))))]))))))
282 #+end_src
285 * COMMENT generate source
286 #+begin_src clojure :tangle ../src/cortex/proprioception.clj
287 <<proprioception-header>>
288 <<helpers>>
289 <<proprioception>>
290 <<visualize>>
291 #+end_src