# HG changeset patch # User Robert McIntyre # Date 1329214610 25200 # Node ID 959127e21f8163c9233ffdb175f61454925a97e4 # Parent 7cac5ef852e3b08e82fd0492246c4eb20ad98e7f fleshing out text in muscle.org diff -r 7cac5ef852e3 -r 959127e21f81 images/basic-muscle.png Binary file images/basic-muscle.png has changed diff -r 7cac5ef852e3 -r 959127e21f81 org/movement.org --- a/org/movement.org Tue Feb 14 02:28:25 2012 -0700 +++ b/org/movement.org Tue Feb 14 03:16:50 2012 -0700 @@ -1,4 +1,4 @@ -#+title: Movement! +#+title: Simulated Muscles #+author: Robert McIntyre #+email: rlm@mit.edu #+description: muscles for a simulated creature @@ -7,48 +7,61 @@ #+INCLUDE: ../../aurellem/org/level-0.org +* Muscles + Surprisingly enough, terristerial creatures only move by using torque applied about their joints. There's not a single straight line of force in the human body at all! (A straight line of force would -correspond to some sort of jet or rocket propulseion.) +correspond to some sort of jet or rocket propulsion.) +*(next paragraph is from memory and needs to be checked!)* -Here's how motor-control/ proprioception will work: Each muscle is -defined by a 1-D array of numbers (the "motor pool") each of which -represent muscle fibers. A muscle also has a scalar :strength factor -which determines how strong the muscle as a whole is. The effector -function for a muscle takes a number < (count motor-pool) and that -number is said to "activate" all the muscle fibers whose index is -lower than the number. Each fiber will apply force in proportion to -its value in the array. Lower values cause less force. The lower -values can be put at the "beginning" of the 1-D array to simulate the -layout of actual human muscles, which are capable of more percise -movements when exerting less force. +In humans, muscles are composed of millions of sarcomeres, which can +contract to exert force. A single motor neuron might control 100-1,000 +sarcomeres. When the motor neuron is engaged by the brain, it +activates all of the sarcomeres to which it is attached. Some motor +neurons command many sarcomeres, and some command only a few. The +spinal cord generally engages the motor neurons which control few +sarcomeres before the motor neurons which control many sarcomeres. +This recruitment stragety allows for percise movements at low +strength. The collection of all motor neurons that control a muscle is +called the motor pool. The brain essentially says "activate 30% of the +motor pool" and the spinal cord recruits motor neurons untill 30% are +activated. Since the distribution of power among motor neurons is +unequal and recruitment goes from weakest to strongest, 30% of the +motor pool might be 5% of the strength of the muscle. + +My simulated muscles follow a similiar design: Each muscle is defined +by a 1-D array of numbers (the "motor pool"). Each number represents a +motor neuron which controlls a number of sarcomeres equal to the +number. A muscle also has a scalar :strength factor which determines +the total force the muscle can exert when all motor neurons are +activated. The effector function for a muscle takes a number to index +into the motor pool, and that number "activates" all the motor neurons +whose index is lower or equal to the number. Each motor-neuron will +apply force in proportion to its value in the array. Lower values +cause less force. The lower values can be put at the "beginning" of +the 1-D array to simulate the layout of actual human muscles, which +are capable of more percise movements when exerting less force. Or, +the motor pool can simulate more exoitic recruitment strageties which +do not correspond to human muscles. + +This 1D array is defined in an image file for ease of +creation/visualization. Here is an example muscle profile image. + +#+caption: A muscle profile image that describes the strengths of each motor neuron in a muscle. White is weakest and dark red is strongest. This particular pattern has weaker motor neurons at the beginning, just like human muscle. +[[../images/basic-muscle.png]] + +* Blender Meta-data + +In blender, each muscle is an empty node whose top level parent is +named "muscles", just like eyes, ears, and joints. + +These functions define the expected meta-data for a muscle node. #+name: movement #+begin_src clojure -(ns cortex.movement - "Give simulated creatures defined in special blender files the power - to move around in a simulated environment." - {:author "Robert McIntyre"} - (:use (cortex world util sense body)) - (:use clojure.contrib.def) - (:import java.awt.image.BufferedImage) - (:import com.jme3.scene.Node) - (:import com.jme3.math.Vector3f) - (:import com.jme3.bullet.control.RigidBodyControl)) - -(defn muscle-profile - "Return a vector where each entry is the strength of the \"motor - pool\" at that part in the muscle." - [#^BufferedImage profile] - (vec - (let [width (.getWidth profile)] - (for [x (range width)] - (- 255 - (bit-and - 0x0000FF - (.getRGB profile x 0))))))) +(in-ns 'cortex.movement) (defvar ^{:arglists '([creature])} @@ -56,30 +69,61 @@ (sense-nodes "muscles") "Return the children of the creature's \"muscles\" node.") -(defn movement-fn +(defn muscle-profile-image + "Get the muscle-profile image from the node's blender meta-data." + [#^Node muscle] + (if-let [image (meta-data muscle "muscle")] + (load-image image))) + +(defn muscle-strength + "Return the strength of this muscle, or 1 if it is not defined." + [#^Node muscle] + (if-let [strength (meta-data muscle "strength")] + strength 1)) + +(defn motor-pool + "Return a vector where each entry is the strength of the \"motor + neuron\" at that part in the muscle." + [#^Node muscle] + (let [profile (muscle-profile-image muscle)] + (vec + (let [width (.getWidth profile)] + (for [x (range width)] + (- 255 + (bit-and + 0x0000FF + (.getRGB profile x 0)))))))) +#+end_src + +Of note here is =(motor-pool)= which interprets the muscle-profile +image in a way that allows me to use gradients between white and red, +instead of shades of gray as I've been using for all the other +senses. This is purely an aesthetic touch. + +* Creating Muscles +#+begin_src clojure +(defn movement-kernel "Returns a function which when called with a integer value inside a running simulation will cause movement in the creature according to the muscle's position and strength profile. Each function returns the amount of force applied / max force." - [#^Node parts #^Node muscle] - (let [target (closest-node parts muscle) + [#^Node creature #^Node muscle] + (let [target (closest-node creature muscle) axis (.mult (.getWorldRotation muscle) Vector3f/UNIT_Y) - strength (meta-data muscle "strength") - image-name (read-string (meta-data muscle "muscle")) - image (load-image image-name) - fibers (muscle-profile image) - fiber-integral (reductions + fibers) + strength (muscle-strength muscle) + + pool (motor-pool muscle) + pool-integral (reductions + pool) force-index - (vec (map #(float (* strength (/ % (last fiber-integral)))) - fiber-integral)) + (vec (map #(float (* strength (/ % (last pool-integral)))) + pool-integral)) control (.getControl target RigidBodyControl)] (fn [n] - (let [pool-index (max 0 (min n (dec (count fibers)))) + (let [pool-index (max 0 (min n (dec (count pool)))) force (force-index pool-index)] (.applyTorque control (.mult axis force)) (float (/ force strength)))))) - (defn movement! "Endow the creature with the power of movement. Returns a sequence @@ -87,8 +131,23 @@ activate their corresponding muscle." [#^Node creature] (for [muscle (muscles creature)] - (movement-fn creature muscle))) + (movement-kernel creature muscle))) +#+end_src +=(movement-kernel)= creates a function that will move the nearest +physical object to the muscle node. The muscle exerts a rotational +force dependant on it's orientation to the object in the blender +file. The function returned by =(movement-kernel)= is also a sense +function: it returns the percent of the total muscle strength that is +currently being employed. This is analogous to muscle tension in +humans and completes the sense of proprioception begun in the last +post. + +* Visualizing Muscle Tension +Muscle exertion is a percent of a total, so the visulazation is just a +simple percent bar. + +#+begin_src clojure (defn movement-display-kernel "Display muscle exertion data as a bar filling up with red." [exertion] @@ -108,11 +167,26 @@ displays each element of the list to the screen." [] (view-sense movement-display-kernel)) - #+end_src +* Adding Touch to the Worm +* Headers +#+name: muscle-header +#+begin_src clojure +(ns cortex.movement + "Give simulated creatures defined in special blender files the power + to move around in a simulated environment." + {:author "Robert McIntyre"} + (:use (cortex world util sense body)) + (:use clojure.contrib.def) + (:import java.awt.image.BufferedImage) + (:import com.jme3.scene.Node) + (:import com.jme3.math.Vector3f) + (:import com.jme3.bullet.control.RigidBodyControl)) +#+end_src + * COMMENT code generation