changeset 410:e6a7e80f885a

refactor, fix null pointer bug.
author Robert McIntyre <rlm@mit.edu>
date Tue, 18 Mar 2014 22:29:03 -0400
parents ea524e4d8f8d
children a331d5ff73e0
files org/self_organizing_touch.clj org/worm_learn.clj
diffstat 2 files changed, 148 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/org/self_organizing_touch.clj	Tue Mar 18 22:29:03 2014 -0400
     1.3 @@ -0,0 +1,146 @@
     1.4 +(ns org.aurellem.self-organizing-touch
     1.5 +  "Using free play to automatically organize touch perception into regions."
     1.6 +  {:author "Robert McIntyre"}
     1.7 +  (:use (cortex world util import body sense
     1.8 +                hearing touch vision proprioception movement
     1.9 +                test))
    1.10 +  (:use [clojure set pprint])
    1.11 +  (:import (com.jme3.math ColorRGBA Vector3f))
    1.12 +  (:import java.io.File)
    1.13 +  (:import com.jme3.audio.AudioNode)
    1.14 +  (:import com.aurellem.capture.RatchetTimer)
    1.15 +  (:import (com.aurellem.capture Capture IsoTimer))
    1.16 +  (:import (com.jme3.math Vector3f ColorRGBA)))
    1.17 +
    1.18 +(use 'org.aurellem.worm-learn)
    1.19 +(dorun (cortex.import/mega-import-jme3))
    1.20 +
    1.21 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    1.22 +;; A demonstration of self organiging touch maps through experience. ;
    1.23 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    1.24 +
    1.25 +(def single-worm-segment-view
    1.26 +  [(Vector3f. 2.0681207, -6.1406755, 1.6106138)
    1.27 +   (Quaternion. -0.15558705, 0.843615, -0.3428654, -0.38281822)])
    1.28 +
    1.29 +(def worm-single-segment-muscle-labels
    1.30 +  [:lift-1 :lift-2 :roll-1 :roll-2])
    1.31 +
    1.32 +(defn touch-kinesthetics []
    1.33 +  [[170 :lift-1 40]
    1.34 +   [190 :lift-1 20]
    1.35 +   [206 :lift-1  0]
    1.36 +
    1.37 +   [400 :lift-2 40]
    1.38 +   [410 :lift-2  0]
    1.39 +
    1.40 +   [570 :lift-2 40]
    1.41 +   [590 :lift-2 20]
    1.42 +   [606 :lift-2  0]
    1.43 +
    1.44 +   [800 :lift-1 30]
    1.45 +   [809 :lift-1 0]
    1.46 +
    1.47 +   [900 :roll-2 40]
    1.48 +   [905 :roll-2 20]
    1.49 +   [910 :roll-2  0]
    1.50 +
    1.51 +   [1000 :roll-2 40]
    1.52 +   [1005 :roll-2 20]
    1.53 +   [1010 :roll-2  0]
    1.54 +   
    1.55 +   [1100 :roll-2 40]
    1.56 +   [1105 :roll-2 20]
    1.57 +   [1110 :roll-2  0]
    1.58 +   ])
    1.59 +
    1.60 +(defn single-worm-segment []
    1.61 +  (load-blender-model "Models/worm/worm-single-segment.blend"))
    1.62 +
    1.63 +(defn worm-segment-defaults []
    1.64 +  (let [direct-control (worm-direct-control worm-muscle-labels 40)]
    1.65 +    (merge (worm-world-defaults)
    1.66 +           {:worm-model single-worm-segment
    1.67 +            :view single-worm-segment-view
    1.68 +            :motor-control
    1.69 +            (motor-control-program
    1.70 +             worm-single-segment-muscle-labels
    1.71 +             (touch-kinesthetics))
    1.72 +            :end-frame 1200})))
    1.73 +
    1.74 +(def full-contact [(float 0.0) (float 0.1)])
    1.75 +
    1.76 +(defn pure-touch?
    1.77 +  "This is worm specific code to determine if a large region of touch
    1.78 +   sensors is either all on or all off."
    1.79 +  [[coords touch :as touch-data]]
    1.80 +  (= (set (map first touch)) (set full-contact)))
    1.81 +
    1.82 +(defn remove-similar
    1.83 +  [coll]
    1.84 +  (loop [result () coll (sort-by (comp - count) coll)]
    1.85 +    (if (empty? coll) result
    1.86 +        (let  [x  (first coll)
    1.87 +               xs (rest coll)
    1.88 +               c (count x)]
    1.89 +          (if (some
    1.90 +               (fn [other-set]
    1.91 +                 (let [oc (count other-set)]
    1.92 +                   (< (- (count (union other-set x)) c) (* oc 0.1))))
    1.93 +               xs)
    1.94 +            (recur result xs)
    1.95 +            (recur (cons x result) xs))))))
    1.96 +
    1.97 +(defn rect-region [[x0 y0] [x1 y1]]
    1.98 +  (vec
    1.99 +   (for [x (range x0 (inc x1))
   1.100 +         y (range y0 (inc y1))]
   1.101 +     [x y])))
   1.102 +
   1.103 +(def all-touch-coordinates
   1.104 +  (concat
   1.105 +   (rect-region [0  15] [7  22])
   1.106 +   (rect-region [8   0] [14 29])
   1.107 +   (rect-region [15 15] [22 22])))
   1.108 +
   1.109 +(defn view-touch-region [coords]
   1.110 +  (let [touched-region
   1.111 +        (reduce
   1.112 +         (fn [m k]
   1.113 +           (assoc m k [0.0 0.1]))
   1.114 +         (zipmap all-touch-coordinates (repeat [0.1 0.1])) coords)
   1.115 +        data
   1.116 +        [[(vec (keys touched-region)) (vec (vals touched-region))]]
   1.117 +        touch-display (view-touch)]
   1.118 +    (touch-display data)
   1.119 +    (touch-display data)))
   1.120 +
   1.121 +(defn learn-touch-regions []
   1.122 +  (let [experiences (atom [])
   1.123 +        world (apply-map
   1.124 +               worm-world
   1.125 +               (assoc (worm-segment-defaults)
   1.126 +                 :experiences experiences))]
   1.127 +    (run-world world)
   1.128 +    (->>
   1.129 +     @experiences
   1.130 +     (drop 175)
   1.131 +     ;; access the single segment's touch data
   1.132 +     (map (comp first :touch))
   1.133 +     ;; only deal with "pure" touch data to determine surfaces
   1.134 +     (filter pure-touch?)
   1.135 +     ;; associate coordinates with touch values
   1.136 +     (map (partial apply zipmap))
   1.137 +     ;; select those regions where contact is being made
   1.138 +     (map (partial group-by second))
   1.139 +     (map #(get % full-contact))
   1.140 +     (map (partial map first))
   1.141 +     ;; remove redundant/subset regions
   1.142 +     (map set)
   1.143 +     remove-similar)))
   1.144 +
   1.145 +(defn learn-and-view-touch-regions []
   1.146 +  (map view-touch-region
   1.147 +       (learn-touch-regions)))
   1.148 +
   1.149 +
     2.1 --- a/org/worm_learn.clj	Tue Mar 18 21:44:15 2014 -0400
     2.2 +++ b/org/worm_learn.clj	Tue Mar 18 22:29:03 2014 -0400
     2.3 @@ -196,9 +196,8 @@
     2.4       :worm-model worm-model
     2.5       :end-frame nil}))
     2.6  
     2.7 -
     2.8  (defn dir! [file]
     2.9 -  (if (not (.exists file))
    2.10 +  (if-not (.exists file)
    2.11      (.mkdir file))
    2.12    file)
    2.13  
    2.14 @@ -238,7 +237,7 @@
    2.15           (speed-up world)
    2.16           (light-up-everything world))
    2.17         (fn [world tpf]
    2.18 -         (if (> (.getTime timer) end-frame)
    2.19 +         (if (and end-frame (> (.getTime timer) end-frame))
    2.20             (.stop world))
    2.21           (let [muscle-data (motor-control muscles)
    2.22                 proprioception-data (prop)
    2.23 @@ -266,130 +265,4 @@
    2.24              (if record (dir! (File. record "touch")))))))))
    2.25  
    2.26  
    2.27 -;; A demonstration of self organiging touch maps through experience. 
    2.28  
    2.29 -(def single-worm-segment-view
    2.30 -  [(Vector3f. 2.0681207, -6.1406755, 1.6106138)
    2.31 -   (Quaternion. -0.15558705, 0.843615, -0.3428654, -0.38281822)])
    2.32 -
    2.33 -(def worm-single-segment-muscle-labels
    2.34 -  [:lift-1 :lift-2 :roll-1 :roll-2])
    2.35 -
    2.36 -(defn touch-kinesthetics []
    2.37 -  [[170 :lift-1 40]
    2.38 -   [190 :lift-1 20]
    2.39 -   [206 :lift-1  0]
    2.40 -
    2.41 -   [400 :lift-2 40]
    2.42 -   [410 :lift-2  0]
    2.43 -
    2.44 -   [570 :lift-2 40]
    2.45 -   [590 :lift-2 20]
    2.46 -   [606 :lift-2  0]
    2.47 -
    2.48 -   [800 :lift-1 30]
    2.49 -   [809 :lift-1 0]
    2.50 -
    2.51 -   [900 :roll-2 40]
    2.52 -   [905 :roll-2 20]
    2.53 -   [910 :roll-2  0]
    2.54 -
    2.55 -   [1000 :roll-2 40]
    2.56 -   [1005 :roll-2 20]
    2.57 -   [1010 :roll-2  0]
    2.58 -   
    2.59 -   [1100 :roll-2 40]
    2.60 -   [1105 :roll-2 20]
    2.61 -   [1110 :roll-2  0]
    2.62 -   ])
    2.63 -
    2.64 -(defn single-worm-segment []
    2.65 -  (load-blender-model "Models/worm/worm-single-segment.blend"))
    2.66 -
    2.67 -(defn worm-segment-defaults []
    2.68 -  (let [direct-control (worm-direct-control worm-muscle-labels 40)]
    2.69 -    (merge (worm-world-defaults)
    2.70 -           {:worm-model single-worm-segment
    2.71 -            :view single-worm-segment-view
    2.72 -            :motor-control
    2.73 -            (motor-control-program
    2.74 -             worm-single-segment-muscle-labels
    2.75 -             (touch-kinesthetics))
    2.76 -            :end-frame 1200})))
    2.77 -
    2.78 -(def full-contact [(float 0.0) (float 0.1)])
    2.79 -
    2.80 -(defn pure-touch?
    2.81 -  "This is worm specific code to determine if a large region of touch
    2.82 -   sensors is either all on or all off."
    2.83 -  [[coords touch :as touch-data]]
    2.84 -  (= (set (map first touch)) (set full-contact)))
    2.85 -
    2.86 -(defn remove-similar
    2.87 -  [coll]
    2.88 -  (loop [result () coll (sort-by (comp - count) coll)]
    2.89 -    (if (empty? coll) result
    2.90 -        (let  [x  (first coll)
    2.91 -               xs (rest coll)
    2.92 -               c (count x)]
    2.93 -          (if (some
    2.94 -               (fn [other-set]
    2.95 -                 (let [oc (count other-set)]
    2.96 -                   (< (- (count (union other-set x)) c) (* oc 0.1))))
    2.97 -               xs)
    2.98 -            (recur result xs)
    2.99 -            (recur (cons x result) xs))))))
   2.100 -
   2.101 -
   2.102 -(defn rect-region [[x0 y0] [x1 y1]]
   2.103 -  (vec
   2.104 -   (for [x (range x0 (inc x1))
   2.105 -         y (range y0 (inc y1))]
   2.106 -     [x y])))
   2.107 -
   2.108 -(def all-touch-coordinates
   2.109 -  (concat
   2.110 -   (rect-region [0  15] [7  22])
   2.111 -   (rect-region [8   0] [14 29])
   2.112 -   (rect-region [15 15] [22 22])))
   2.113 -
   2.114 -(defn view-touch-region [coords]
   2.115 -  (let [touched-region
   2.116 -        (reduce
   2.117 -         (fn [m k]
   2.118 -           (assoc m k [0.0 0.1]))
   2.119 -         (zipmap all-touch-coordinates (repeat [0.1 0.1])) coords)
   2.120 -        data
   2.121 -        [[(vec (keys touched-region)) (vec (vals touched-region))]]
   2.122 -        touch-display (view-touch)]
   2.123 -    (touch-display data)
   2.124 -    (touch-display data)))
   2.125 -
   2.126 -(defn learn-touch-regions []
   2.127 -  (let [experiences (atom [])
   2.128 -        world (apply-map
   2.129 -               worm-world
   2.130 -               (assoc (worm-segment-defaults)
   2.131 -                 :experiences experiences))]
   2.132 -    (run-world world)
   2.133 -    (->>
   2.134 -     @experiences
   2.135 -     (drop 175)
   2.136 -     ;; access the single segment's touch data
   2.137 -     (map (comp first :touch))
   2.138 -     ;; only deal with "pure" touch data to determine surfaces
   2.139 -     (filter pure-touch?)
   2.140 -     ;; associate coordinates with touch values
   2.141 -     (map (partial apply zipmap))
   2.142 -     ;; select those regions where contact is being made
   2.143 -     (map (partial group-by second))
   2.144 -     (map #(get % full-contact))
   2.145 -     (map (partial map first))
   2.146 -     ;; remove redundant/subset regions
   2.147 -     (map set)
   2.148 -     remove-similar)))
   2.149 -
   2.150 -(defn learn-and-view-touch-regions []
   2.151 -  (map view-touch-region
   2.152 -       (learn-touch-regions)))
   2.153 -