view org/test-creature.org @ 158:811127d79d24

refactored muscles
author Robert McIntyre <rlm@mit.edu>
date Fri, 03 Feb 2012 06:33:37 -0700
parents 84c67be00abe
children 75b6c2ebbf8e
line wrap: on
line source
1 #+title: First attempt at a creature!
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description:
5 #+keywords: simulation, jMonkeyEngine3, clojure
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
12 * Intro
13 So far, I've made the following senses --
14 - Vision
15 - Hearing
16 - Touch
17 - Proprioception
19 And one effector:
20 - Movement
22 However, the code so far has only enabled these senses, but has not
23 actually implemented them. For example, there is still a lot of work
24 to be done for vision. I need to be able to create an /eyeball/ in
25 simulation that can be moved around and see the world from different
26 angles. I also need to determine weather to use log-polar or cartesian
27 for the visual input, and I need to determine how/wether to
28 disceritise the visual input.
30 I also want to be able to visualize both the sensors and the
31 effectors in pretty pictures. This semi-retarted creature will be my
32 first attempt at bringing everything together.
34 * The creature's body
36 Still going to do an eve-like body in blender, but due to problems
37 importing the joints, etc into jMonkeyEngine3, I'm going to do all
38 the connecting here in clojure code, using the names of the individual
39 components and trial and error. Later, I'll maybe make some sort of
40 creature-building modifications to blender that support whatever
41 discritized senses I'm going to make.
43 #+name: body-1
44 #+begin_src clojure
45 (ns cortex.silly
46 "let's play!"
47 {:author "Robert McIntyre"})
49 ;; TODO remove this!
50 (require 'cortex.import)
51 (cortex.import/mega-import-jme3)
52 (use '(cortex world util body hearing touch vision sense
53 proprioception movement))
55 (rlm.rlm-commands/help)
56 (import java.awt.image.BufferedImage)
57 (import javax.swing.JPanel)
58 (import javax.swing.SwingUtilities)
59 (import java.awt.Dimension)
60 (import javax.swing.JFrame)
61 (import java.awt.Dimension)
62 (import com.aurellem.capture.RatchetTimer)
63 (declare joint-create)
64 (use 'clojure.contrib.def)
66 (defn load-blender-model
67 "Load a .blend file using an asset folder relative path."
68 [^String model]
69 (.loadModel
70 (doto (asset-manager)
71 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
72 model))
74 (defn blender-to-jme
75 "Convert from Blender coordinates to JME coordinates"
76 [#^Vector3f in]
77 (Vector3f. (.getX in)
78 (.getZ in)
79 (- (.getY in))))
82 (defmulti joint-dispatch
83 "Translate blender pseudo-joints into real JME joints."
84 (fn [constraints & _]
85 (:type constraints)))
87 (defmethod joint-dispatch :point
88 [constraints control-a control-b pivot-a pivot-b rotation]
89 (println-repl "creating POINT2POINT joint")
90 ;; bullet's point2point joints are BROKEN, so we must use the
91 ;; generic 6DOF joint instead of an actual Point2Point joint!
93 ;; should be able to do this:
94 (comment
95 (Point2PointJoint.
96 control-a
97 control-b
98 pivot-a
99 pivot-b))
101 ;; but instead we must do this:
102 (println-repl "substuting 6DOF joint for POINT2POINT joint!")
103 (doto
104 (SixDofJoint.
105 control-a
106 control-b
107 pivot-a
108 pivot-b
109 false)
110 (.setLinearLowerLimit Vector3f/ZERO)
111 (.setLinearUpperLimit Vector3f/ZERO)
112 ;;(.setAngularLowerLimit (Vector3f. 1 1 1))
113 ;;(.setAngularUpperLimit (Vector3f. 0 0 0))
115 ))
118 (defmethod joint-dispatch :hinge
119 [constraints control-a control-b pivot-a pivot-b rotation]
120 (println-repl "creating HINGE joint")
121 (let [axis
122 (if-let
123 [axis (:axis constraints)]
124 axis
125 Vector3f/UNIT_X)
126 [limit-1 limit-2] (:limit constraints)
127 hinge-axis
128 (.mult
129 rotation
130 (blender-to-jme axis))]
131 (doto
132 (HingeJoint.
133 control-a
134 control-b
135 pivot-a
136 pivot-b
137 hinge-axis
138 hinge-axis)
139 (.setLimit limit-1 limit-2))))
141 (defmethod joint-dispatch :cone
142 [constraints control-a control-b pivot-a pivot-b rotation]
143 (let [limit-xz (:limit-xz constraints)
144 limit-xy (:limit-xy constraints)
145 twist (:twist constraints)]
147 (println-repl "creating CONE joint")
148 (println-repl rotation)
149 (println-repl
150 "UNIT_X --> " (.mult rotation (Vector3f. 1 0 0)))
151 (println-repl
152 "UNIT_Y --> " (.mult rotation (Vector3f. 0 1 0)))
153 (println-repl
154 "UNIT_Z --> " (.mult rotation (Vector3f. 0 0 1)))
155 (doto
156 (ConeJoint.
157 control-a
158 control-b
159 pivot-a
160 pivot-b
161 rotation
162 rotation)
163 (.setLimit (float limit-xz)
164 (float limit-xy)
165 (float twist)))))
167 (defn connect
168 "here are some examples:
169 {:type :point}
170 {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)}
171 (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints)
173 {:type :cone :limit-xz 0]
174 :limit-xy 0]
175 :twist 0]} (use XZY rotation mode in blender!)"
176 [#^Node obj-a #^Node obj-b #^Node joint]
177 (let [control-a (.getControl obj-a RigidBodyControl)
178 control-b (.getControl obj-b RigidBodyControl)
179 joint-center (.getWorldTranslation joint)
180 joint-rotation (.toRotationMatrix (.getWorldRotation joint))
181 pivot-a (world-to-local obj-a joint-center)
182 pivot-b (world-to-local obj-b joint-center)]
184 (if-let [constraints
185 (map-vals
186 eval
187 (read-string
188 (meta-data joint "joint")))]
189 ;; A side-effect of creating a joint registers
190 ;; it with both physics objects which in turn
191 ;; will register the joint with the physics system
192 ;; when the simulation is started.
193 (do
194 (println-repl "creating joint between"
195 (.getName obj-a) "and" (.getName obj-b))
196 (joint-dispatch constraints
197 control-a control-b
198 pivot-a pivot-b
199 joint-rotation))
200 (println-repl "could not find joint meta-data!"))))
205 (defn assemble-creature [#^Node pieces joints]
206 (dorun
207 (map
208 (fn [geom]
209 (let [physics-control
210 (RigidBodyControl.
211 (HullCollisionShape.
212 (.getMesh geom))
213 (if-let [mass (meta-data geom "mass")]
214 (do
215 (println-repl
216 "setting" (.getName geom) "mass to" (float mass))
217 (float mass))
218 (float 1)))]
220 (.addControl geom physics-control)))
221 (filter #(isa? (class %) Geometry )
222 (node-seq pieces))))
223 (dorun
224 (map
225 (fn [joint]
226 (let [[obj-a obj-b] (joint-targets pieces joint)]
227 (connect obj-a obj-b joint)))
228 joints))
229 pieces)
231 (declare blender-creature)
233 (def hand "Models/creature1/one.blend")
235 (def worm "Models/creature1/try-again.blend")
237 (defn worm-model [] (load-blender-model worm))
239 (defn x-ray [#^ColorRGBA color]
240 (doto (Material. (asset-manager)
241 "Common/MatDefs/Misc/Unshaded.j3md")
242 (.setColor "Color" color)
243 (-> (.getAdditionalRenderState)
244 (.setDepthTest false))))
246 (defn colorful []
247 (.getChild (worm-model) "worm-21"))
249 (import jme3tools.converters.ImageToAwt)
251 (import ij.ImagePlus)
255 (defn test-eye []
256 (.getChild
257 (.getChild (worm-model) "eyes")
258 "eye"))
262 ;; Ears work the same way as vision.
264 ;; (hearing creature) will return [init-functions
265 ;; sensor-functions]. The init functions each take the world and
266 ;; register a SoundProcessor that does foureier transforms on the
267 ;; incommong sound data, making it available to each sensor function.
269 (defn creature-ears
270 "Return the children of the creature's \"ears\" node."
271 ;;dylan
272 ;;"The ear nodes which are children of the \"ears\" node in the
273 ;;creature."
274 [#^Node creature]
275 (if-let [ear-node (.getChild creature "ears")]
276 (seq (.getChildren ear-node))
277 (do (println-repl "could not find ears node") [])))
280 ;;dylan (defn follow-sense, adjoin-sense, attach-stimuli,
281 ;;anchor-qualia, augment-organ, with-organ
284 (defn update-listener-velocity
285 "Update the listener's velocity every update loop."
286 [#^Spatial obj #^Listener lis]
287 (let [old-position (atom (.getLocation lis))]
288 (.addControl
289 obj
290 (proxy [AbstractControl] []
291 (controlUpdate [tpf]
292 (let [new-position (.getLocation lis)]
293 (.setVelocity
294 lis
295 (.mult (.subtract new-position @old-position)
296 (float (/ tpf))))
297 (reset! old-position new-position)))
298 (controlRender [_ _])))))
300 (import com.aurellem.capture.audio.AudioSendRenderer)
302 (defn attach-ear
303 [#^Application world #^Node creature #^Spatial ear continuation]
304 (let [target (closest-node creature ear)
305 lis (Listener.)
306 audio-renderer (.getAudioRenderer world)
307 sp (sound-processor continuation)]
308 (.setLocation lis (.getWorldTranslation ear))
309 (.setRotation lis (.getWorldRotation ear))
310 (bind-sense target lis)
311 (update-listener-velocity target lis)
312 (.addListener audio-renderer lis)
313 (.registerSoundProcessor audio-renderer lis sp)))
315 (defn enable-hearing
316 [#^Node creature #^Spatial ear]
317 (let [hearing-data (atom [])]
318 [(fn [world]
319 (attach-ear world creature ear
320 (fn [data]
321 (reset! hearing-data (vec data)))))
322 [(fn []
323 (let [data @hearing-data
324 topology
325 (vec (map #(vector % 0) (range 0 (count data))))
326 scaled-data
327 (vec
328 (map
329 #(rem (int (* 255 (/ (+ 1 %) 2))) 256)
330 data))]
331 [topology scaled-data]))
332 ]]))
334 (defn hearing
335 [#^Node creature]
336 (reduce
337 (fn [[init-a senses-a]
338 [init-b senses-b]]
339 [(conj init-a init-b)
340 (into senses-a senses-b)])
341 [[][]]
342 (for [ear (creature-ears creature)]
343 (enable-hearing creature ear))))
350 ;; lower level --- nodes
351 ;; closest-node "parse/compile-x" -> makes organ, which is spatial, fn pair
353 ;; higher level -- organs
354 ;;
356 ;; higher level --- sense/effector
357 ;; these are the functions that provide world i/o, chinese-room style
362 (defn blender-creature
363 "Return a creature with all joints in place."
364 [blender-path]
365 (let [model (load-blender-model blender-path)
366 joints (creature-joints model)]
367 (assemble-creature model joints)))
369 (defn gray-scale [num]
370 (+ num
371 (bit-shift-left num 8)
372 (bit-shift-left num 16)))
374 (defn debug-touch-window
375 "creates function that offers a debug view of sensor data"
376 []
377 (let [vi (view-image)]
378 (fn
379 [[coords sensor-data]]
380 (let [image (points->image coords)]
381 (dorun
382 (for [i (range (count coords))]
383 (.setRGB image ((coords i) 0) ((coords i) 1)
384 (gray-scale (sensor-data i)))))
387 (vi image)))))
389 (defn debug-vision-window
390 "creates function that offers a debug view of sensor data"
391 []
392 (let [vi (view-image)]
393 (fn
394 [[coords sensor-data]]
395 (let [image (points->image coords)]
396 (dorun
397 (for [i (range (count coords))]
398 (.setRGB image ((coords i) 0) ((coords i) 1)
399 (sensor-data i))))
400 (vi image)))))
402 (defn debug-hearing-window
403 "view audio data"
404 [height]
405 (let [vi (view-image)]
406 (fn [[coords sensor-data]]
407 (let [image (BufferedImage. (count coords) height
408 BufferedImage/TYPE_INT_RGB)]
409 (dorun
410 (for [x (range (count coords))]
411 (dorun
412 (for [y (range height)]
413 (let [raw-sensor (sensor-data x)]
414 (.setRGB image x y (gray-scale raw-sensor)))))))
416 (vi image)))))
420 ;;(defn test-touch [world creature]
426 (defn test-creature [thing]
427 (let [x-axis
428 (box 1 0.01 0.01 :physical? false :color ColorRGBA/Red)
429 y-axis
430 (box 0.01 1 0.01 :physical? false :color ColorRGBA/Green)
431 z-axis
432 (box 0.01 0.01 1 :physical? false :color ColorRGBA/Blue)
433 creature (blender-creature thing)
434 touch-nerves (touch creature)
435 touch-debug-windows (map (fn [_] (debug-touch-window)) touch-nerves)
436 [init-vision-fns vision-data] (vision creature)
437 vision-debug (map (fn [_] (debug-vision-window)) vision-data)
438 me (sphere 0.5 :color ColorRGBA/Blue :physical? false)
439 [init-hearing-fns hearing-senses] (hearing creature)
440 hearing-windows (map (fn [_] (debug-hearing-window 50))
441 hearing-senses)
442 bell (AudioNode. (asset-manager)
443 "Sounds/pure.wav" false)
444 prop (proprioception creature)
445 prop-debug (proprioception-debug-window)
447 muscle-fns (enable-muscles creature)
448 ;; dream
450 ]
453 (apply
454 world
455 (with-movement
456 (.getChild creature "worm-21")
457 ["key-r" "key-t"
458 "key-f" "key-g"
459 "key-v" "key-b"]
460 [10 10 10 10 1 1]
461 [(nodify [creature
462 (box 10 2 10 :position (Vector3f. 0 -9 0)
463 :color ColorRGBA/Gray :mass 0)
464 x-axis y-axis z-axis
465 me
466 ])
467 (merge standard-debug-controls
468 {"key-return"
469 (fn [_ value]
470 (if value
471 (do
472 (println-repl "play-sound")
473 (.play bell))))
474 "key-h"
475 (fn [_ value]
476 (if value
477 (do
478 (println-repl "muscle activating!")
479 ((first muscle-fns) 199))))
481 })
482 (fn [world]
483 (light-up-everything world)
484 (enable-debug world)
485 (dorun (map #(% world) init-vision-fns))
486 (dorun (map #(% world) init-hearing-fns))
488 (add-eye world
489 (attach-eye creature (test-eye))
490 (comp (view-image) BufferedImage!))
492 (add-eye world (.getCamera world) no-op)
493 ;;(set-gravity world (Vector3f. 0 0 0))
494 ;;(com.aurellem.capture.Capture/captureVideo
495 ;; world (file-str "/home/r/proj/ai-videos/hand"))
496 ;;(.setTimer world (RatchetTimer. 60))
497 (speed-up world)
498 (set-gravity world (Vector3f. 0 0 0))
499 )
500 (fn [world tpf]
501 ;;(dorun
502 ;; (map #(%1 %2) touch-nerves (repeat (.getRootNode world))))
504 (prop-debug (prop))
506 (dorun
507 (map #(%1 (%2 (.getRootNode world)))
508 touch-debug-windows touch-nerves))
510 (dorun
511 (map #(%1 (%2))
512 vision-debug vision-data))
513 (dorun
514 (map #(%1 (%2)) hearing-windows hearing-senses))
517 ;;(println-repl (vision-data))
518 (.setLocalTranslation me (.getLocation (.getCamera world)))
521 )]
522 ;;(let [timer (atom 0)]
523 ;; (fn [_ _]
524 ;; (swap! timer inc)
525 ;; (if (= (rem @timer 60) 0)
526 ;; (println-repl (float (/ @timer 60))))))
527 ))))
531 ;; the camera will stay in its initial position/rotation with relation
532 ;; to the spatial.
535 (defn follow-test
536 "show a camera that stays in the same relative position to a blue cube."
537 []
538 (let [camera-pos (Vector3f. 0 30 0)
539 rock (box 1 1 1 :color ColorRGBA/Blue
540 :position (Vector3f. 0 10 0)
541 :mass 30
542 )
543 rot (.getWorldRotation rock)
545 table (box 3 1 10 :color ColorRGBA/Gray :mass 0
546 :position (Vector3f. 0 -3 0))]
548 (world
549 (nodify [rock table])
550 standard-debug-controls
551 (fn [world]
552 (let
553 [cam (doto (.clone (.getCamera world))
554 (.setLocation camera-pos)
555 (.lookAt Vector3f/ZERO
556 Vector3f/UNIT_X))]
557 (bind-sense rock cam)
559 (.setTimer world (RatchetTimer. 60))
560 (add-eye world cam (comp (view-image) BufferedImage!))
561 (add-eye world (.getCamera world) no-op))
562 )
563 (fn [_ _] (println-repl rot)))))
567 #+end_src
569 #+results: body-1
570 : #'cortex.silly/follow-test
573 * COMMENT purgatory
574 #+begin_src clojure
576 (defn bullet-trans* []
577 (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red
578 :position (Vector3f. 5 0 0)
579 :mass 90)
580 obj-b (sphere 0.5 :color ColorRGBA/Blue
581 :position (Vector3f. -5 0 0)
582 :mass 0)
583 control-a (.getControl obj-a RigidBodyControl)
584 control-b (.getControl obj-b RigidBodyControl)
585 move-up? (atom nil)
586 move-down? (atom nil)
587 move-left? (atom nil)
588 move-right? (atom nil)
589 roll-left? (atom nil)
590 roll-right? (atom nil)
591 force 100
592 swivel
593 (.toRotationMatrix
594 (doto (Quaternion.)
595 (.fromAngleAxis (/ Math/PI 2)
596 Vector3f/UNIT_X)))
597 x-move
598 (doto (Matrix3f.)
599 (.fromStartEndVectors Vector3f/UNIT_X
600 (.normalize (Vector3f. 1 1 0))))
602 timer (atom 0)]
603 (doto
604 (ConeJoint.
605 control-a control-b
606 (Vector3f. -8 0 0)
607 (Vector3f. 2 0 0)
608 ;;swivel swivel
609 ;;Matrix3f/IDENTITY Matrix3f/IDENTITY
610 x-move Matrix3f/IDENTITY
611 )
612 (.setCollisionBetweenLinkedBodys false)
613 (.setLimit (* 1 (/ Math/PI 4)) ;; twist
614 (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane
615 (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane
616 (world (nodify
617 [obj-a obj-b])
618 (merge standard-debug-controls
619 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
620 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
621 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
622 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
623 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
624 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
626 (fn [world]
627 (enable-debug world)
628 (set-gravity world Vector3f/ZERO)
629 )
631 (fn [world _]
633 (if @move-up?
634 (.applyForce control-a
635 (Vector3f. force 0 0)
636 (Vector3f. 0 0 0)))
637 (if @move-down?
638 (.applyForce control-a
639 (Vector3f. (- force) 0 0)
640 (Vector3f. 0 0 0)))
641 (if @move-left?
642 (.applyForce control-a
643 (Vector3f. 0 force 0)
644 (Vector3f. 0 0 0)))
645 (if @move-right?
646 (.applyForce control-a
647 (Vector3f. 0 (- force) 0)
648 (Vector3f. 0 0 0)))
650 (if @roll-left?
651 (.applyForce control-a
652 (Vector3f. 0 0 force)
653 (Vector3f. 0 0 0)))
654 (if @roll-right?
655 (.applyForce control-a
656 (Vector3f. 0 0 (- force))
657 (Vector3f. 0 0 0)))
659 (if (zero? (rem (swap! timer inc) 100))
660 (.attachChild
661 (.getRootNode world)
662 (sphere 0.05 :color ColorRGBA/Yellow
663 :physical? false :position
664 (.getWorldTranslation obj-a)))))
665 )
666 ))
668 (defn test-joint [joint]
669 (let [[origin top bottom floor] (world-setup joint)
670 control (.getControl top RigidBodyControl)
671 move-up? (atom false)
672 move-down? (atom false)
673 move-left? (atom false)
674 move-right? (atom false)
675 roll-left? (atom false)
676 roll-right? (atom false)
677 timer (atom 0)]
679 (world
680 (nodify [top bottom floor origin])
681 (merge standard-debug-controls
682 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
683 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
684 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
685 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
686 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
687 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
689 (fn [world]
690 (light-up-everything world)
691 (enable-debug world)
692 (set-gravity world (Vector3f. 0 0 0))
693 )
695 (fn [world _]
696 (if (zero? (rem (swap! timer inc) 100))
697 (do
698 ;; (println-repl @timer)
699 (.attachChild (.getRootNode world)
700 (sphere 0.05 :color ColorRGBA/Yellow
701 :position (.getWorldTranslation top)
702 :physical? false))
703 (.attachChild (.getRootNode world)
704 (sphere 0.05 :color ColorRGBA/LightGray
705 :position (.getWorldTranslation bottom)
706 :physical? false))))
708 (if @move-up?
709 (.applyTorque control
710 (.mult (.getPhysicsRotation control)
711 (Vector3f. 0 0 10))))
712 (if @move-down?
713 (.applyTorque control
714 (.mult (.getPhysicsRotation control)
715 (Vector3f. 0 0 -10))))
716 (if @move-left?
717 (.applyTorque control
718 (.mult (.getPhysicsRotation control)
719 (Vector3f. 0 10 0))))
720 (if @move-right?
721 (.applyTorque control
722 (.mult (.getPhysicsRotation control)
723 (Vector3f. 0 -10 0))))
724 (if @roll-left?
725 (.applyTorque control
726 (.mult (.getPhysicsRotation control)
727 (Vector3f. -1 0 0))))
728 (if @roll-right?
729 (.applyTorque control
730 (.mult (.getPhysicsRotation control)
731 (Vector3f. 1 0 0))))))))
732 #+end_src
735 * COMMENT generate source
736 #+begin_src clojure :tangle ../src/cortex/silly.clj
737 <<body-1>>
738 #+end_src