# HG changeset patch # User Robert McIntyre # Date 1329211705 25200 # Node ID 7cac5ef852e3b08e82fd0492246c4eb20ad98e7f # Parent f4b67005b702829ef3bfca8f001895091e2b7abb proprioception rough draft complete. diff -r f4b67005b702 -r 7cac5ef852e3 org/proprioception.org --- a/org/proprioception.org Tue Feb 14 00:39:16 2012 -0700 +++ b/org/proprioception.org Tue Feb 14 02:28:25 2012 -0700 @@ -37,6 +37,12 @@ * Helper Functions +=(absolute-angle)= calculates the angle between two vectors, relative to a +third axis vector. This angle is the number of radians you have to +move counterclockwise around the axis vector to get from the first to +the second vector. It is not commutative like a normal dot-product +angle is. + #+name: helpers #+begin_src clojure (in-ns 'cortex.proprioception) @@ -49,17 +55,37 @@ (< 0 (.dot (.cross vec1 vec2) vec3))) (defn absolute-angle - "The angle between 'vec1 and 'vec2. Positive if the angle to get - from 'vec1 to 'vec2 is counterclockwise around 'axis, and negative - otherwise." + "The angle between 'vec1 and 'vec2 around 'axis. In the range + [0 (* 2 Math/PI)]." [vec1 vec2 axis] (let [angle (.angleBetween vec1 vec2)] (if (right-handed? vec1 vec2 axis) angle (- (* 2 Math/PI) angle)))) #+end_src +#+begin_src clojure :exports both +(in-ns 'cortex.proprioception) +(absolute-angle Vector3f/UNIT_X Vector3f/UNIT_Y Vector3f/UNIT_Z) +#+end_src + +#+results: +: 1.5707964 + +#+begin_src clojure :exports both +(in-ns 'cortex.proprioception) +(absolute-angle + Vector3f/UNIT_X (.mult Vector3f/UNIT_Y (float -1)) Vector3f/UNIT_Z) +#+end_src + +#+results: +: 4.7123889366733 + * Proprioception Kernel +Given a joint, =(proprioception-kernel)= produces a function that +calculates the euler angles between the the objects the joint +connects. + #+name: proprioception #+begin_src clojure (defn proprioception-kernel @@ -71,12 +97,6 @@ x0 (.mult joint-rot Vector3f/UNIT_X) y0 (.mult joint-rot Vector3f/UNIT_Y) z0 (.mult joint-rot Vector3f/UNIT_Z)] - (println-repl "x:" x0) - (println-repl "y:" y0) - (println-repl "z:" z0) - (println-repl "init-a:" (.getWorldRotation obj-a)) - (println-repl "init-b:" (.getWorldRotation obj-b)) - (fn [] (let [rot-a (.clone (.getWorldRotation obj-a)) rot-b (.clone (.getWorldRotation obj-b)) @@ -113,8 +133,18 @@ (map #(%) senses)))) #+end_src + +=(proprioception!)= maps =(proprioception-kernel)= across all the +joints of the creature. It uses the same list of joints that +=(cortex.body/joints)= uses. + * Visualizing Proprioception +Proprioception has the lowest bandwidth of all the senses so far, and +it doesn't lend itself as readily to visual representation like +vision, hearing, or touch. This visualization code creates a "guage" +to view each of the three relative angles along a circle. + #+name: visualize #+begin_src clojure (in-ns 'cortex.proprioception) @@ -141,7 +171,6 @@ (reset! previous position)) image)))) - (defn proprioception-display-kernel "Display proprioception angles in a BufferedImage" [[h p r]] @@ -177,10 +206,15 @@ (view-sense proprioception-display-kernel)) #+end_src -* Demonstration of Proprioception +* Proprioception Test +This test does not use the worm, but instead uses two bars, bound +together by a point2point joint. One bar is fixed, and I control the +other bar from the keyboard. -#+name: test-body +#+name: test-proprioception #+begin_src clojure +(in-ns 'cortex.test.proprioception) + (defn test-proprioception "Testing proprioception: You should see two foating bars, and a printout of pitch, yaw, and @@ -188,87 +222,115 @@ change only the value of pitch. key-f/key-g moves it side to side and changes yaw. key-v/key-b will spin the blue segment clockwise and counterclockwise, and only affect roll." - [] - (let [hand (box 0.2 1 0.2 :position (Vector3f. 0 0 0) - :mass 0 :color ColorRGBA/Green :name "hand") - finger (box 0.2 1 0.2 :position (Vector3f. 0 2.4 0) - :mass 1 :color ColorRGBA/Red :name "finger") - joint-node (box 0.1 0.05 0.05 :color ColorRGBA/Yellow - :position (Vector3f. 0 1.2 0) - :rotation (doto (Quaternion.) - (.fromAngleAxis - (/ Math/PI 2) - (Vector3f. 0 0 1))) - :physical? false) - joint (join-at-point hand finger (Vector3f. 0 1.2 0 )) - creature (nodify [hand finger joint-node]) - finger-control (.getControl finger RigidBodyControl) - hand-control (.getControl hand RigidBodyControl)] - + ([] (test-proprioception false)) + ([record?] + (let [hand (box 0.2 1 0.2 :position (Vector3f. 0 0 0) + :mass 0 :color ColorRGBA/Gray :name "hand") + finger (box 0.2 1 0.2 :position (Vector3f. 0 2.4 0) + :mass 1 + :color + (ColorRGBA. (/ 184 255) (/ 127 255) (/ 201 255) 1) + :name "finger") + joint-node (box 0.1 0.05 0.05 :color ColorRGBA/Yellow + :position (Vector3f. 0 1.2 0) + :rotation (doto (Quaternion.) + (.fromAngleAxis + (/ Math/PI 2) + (Vector3f. 0 0 1))) + :physical? false) + creature (nodify [hand finger joint-node]) + finger-control (.getControl finger RigidBodyControl) + hand-control (.getControl hand RigidBodyControl) + joint (joint-dispatch {:type :point} hand-control finger-control + (Vector3f. 0 1.2 0) + (Vector3f. 0 -1.2 0) nil) - (let - ;; ******************************************* - - [floor (box 10 10 10 :position (Vector3f. 0 -15 0) - :mass 0 :color ColorRGBA/Gray) - - root (nodify [creature floor]) - prop (joint-proprioception creature joint-node) - prop-view (proprioception-debug-window) - - controls - (merge standard-debug-controls - {"key-o" - (fn [_ _] (.setEnabled finger-control true)) - "key-p" - (fn [_ _] (.setEnabled finger-control false)) - "key-k" - (fn [_ _] (.setEnabled hand-control true)) - "key-l" - (fn [_ _] (.setEnabled hand-control false)) - "key-i" - (fn [world _] (set-gravity world (Vector3f. 0 0 0))) - "key-period" - (fn [world _] - (.setEnabled finger-control false) - (.setEnabled hand-control false) - (.rotate creature (doto (Quaternion.) - (.fromAngleAxis - (float (/ Math/PI 15)) - (Vector3f. 0 0 -1)))) - - (.setEnabled finger-control true) - (.setEnabled hand-control true) - (set-gravity world (Vector3f. 0 0 0)) - ) - - - } - ) + root (nodify [creature]) + prop (proprioception-kernel creature joint-node) + prop-view (view-proprioception)] + (.setCollisionGroup + (.getControl hand RigidBodyControl) + PhysicsCollisionObject/COLLISION_GROUP_NONE) + (apply + world + (with-movement + finger + ["key-r" "key-t" "key-f" "key-g" "key-v" "key-b"] + [1 1 10 10 10 10] + [root + standard-debug-controls + (fn [world] + (if record? + (Capture/captureVideo + world + (File. "/home/r/proj/cortex/render/proprio/main-view"))) + (.setTimer world (com.aurellem.capture.RatchetTimer. 60)) + (set-gravity world (Vector3f. 0 0 0)) + (enable-debug world) + (light-up-everything world)) + (fn [_ _] + (prop-view + (list (prop)) + (if record? + (File. "/home/r/proj/cortex/render/proprio/proprio"))))]))))) +#+end_src - ] - (comment - (.setCollisionGroup - (.getControl hand RigidBodyControl) - PhysicsCollisionObject/COLLISION_GROUP_NONE) - ) - (apply - world - (with-movement - hand - ["key-y" "key-u" "key-h" "key-j" "key-n" "key-m"] - [10 10 10 10 1 1] - (with-movement - finger - ["key-r" "key-t" "key-f" "key-g" "key-v" "key-b"] - [1 1 10 10 10 10] - [root - controls - (fn [world] - (.setTimer world (com.aurellem.capture.RatchetTimer. 60)) - (set-gravity world (Vector3f. 0 0 0)) - (light-up-everything world)) - (fn [_ _] (prop-view (list (prop))))])))))) +#+results: test-proprioception +: #'cortex.test.proprioception/test-proprioception + +* Video of Proprioception + +#+begin_html +
+
+ +
+

Proprioception in a simple creature. The proprioceptive readout is + in the upper left corner of the screen.

+
+#+end_html + +** Generating the Proprioception Video +#+name: magick6 +#+begin_src clojure +(ns cortex.video.magick6 + (:import java.io.File) + (:use clojure.contrib.shell-out)) + +(defn images [path] + (sort (rest (file-seq (File. path))))) + +(def base "/home/r/proj/cortex/render/proprio/") + +(defn pics [file] + (images (str base file))) + +(defn combine-images [] + (let [main-view (pics "main-view") + proprioception (pics "proprio/0") + targets (map + #(File. (str base "out/" (format "%07d.png" %))) + (range 0 (count main-view)))] + (dorun + (pmap + (comp + (fn [[ main-view proprioception target]] + (println target) + (sh "convert" + main-view + proprioception "-geometry" "+20+20" "-composite" + target)) + (fn [& args] (map #(.getCanonicalPath %) args))) + main-view proprioception targets)))) +#+end_src + +#+begin_src sh :results silent +cd ~/proj/cortex/render/proprio +ffmpeg -r 60 -i out/%07d.png -b:v 9000k -c:v libtheora \ + test-proprioception.ogg #+end_src * Headers @@ -286,6 +348,26 @@ (:import (com.jme3.math Vector3f Quaternion))) #+end_src +#+name: test-proprioception-header +#+begin_src clojure +(ns cortex.test.proprioception +(:import (com.aurellem.capture Capture RatchetTimer)) +(:use (cortex util world proprioception body)) +(:import java.io.File)) +(cortex.import/mega-import-jme3) +#+end_src + +* Source Listing + - [[../src/cortex/proprioception.clj][cortex.proprioception]] + - [[../src/cortex/test/touch.clj][cortex.test.proprioception]] + - [[../src/cortex/video/magick6.clj][cortex.video.magick6]] +#+html: + - [[http://hg.bortreb.com ][source-repository]] + +* Next + +Next time, I'll give the Worm the power to [[./movement.org][move on it's own]]. + * COMMENT generate source #+begin_src clojure :tangle ../src/cortex/proprioception.clj @@ -294,3 +376,12 @@ <> <> #+end_src + +#+begin_src clojure :tangle ../src/cortex/test/proprioception.clj +<> +<> +#+end_src + +#+begin_src clojure :tangle ../src/cortex/video/magick6.clj +<> +#+end_src