Fruit Fly
README.md
FruitFly
An embodied fly driven by a FruitFlyBrain. Every frame it writes the world
into the network's sensory neurons and reads a motor command out of named
motor and descending cell types.
Which side of the body a sense or a command belongs to is the dataset's answer, not this component's. MaleCNS v1.0 labels a side on the looming detectors and on the leg motor neurons, and labels the tarsal and labellar taste neurons "unknown", so looming is driven per eye and taste is not.
| sense | cell types | driven by |
|---|---|---|
| tarsal taste | claw_tpGRN, dorsal_tpGRN (60, side unknown) | either front foot on a FoodPatch |
| labellar taste | LB* (165, side unknown) | the extended proboscis on a FoodPatch |
| looming, left eye | LPLC2 side L (94), LC4 side L (71) | anything growing in the left eye's field, the arena wall included |
| looming, right eye | LPLC2 side R (91), LC4 side R (55) | the same for the right eye |
The two looming classes are separate drives, so silencing LPLC2 leaves LC4
driven and the ablation has an answer.
| command | cell types |
|---|---|
| walk | leg motor neurons (vnc_motor types ending in MN), left 189 and right 185, averaged |
| turn | DNa01 + DNa02 left minus right, plus the leg motor neurons right minus left |
| proboscis | MN9 |
| flight | DLMn + DVMn wing power-muscle motor neurons |
| jump | a DNp01 burst above escapeHz |
Beating wings lift the fly only once it is already off the ground: on six legs the beat is a beat, and the legs keep walking underneath it.
The arena
arenaRadius is a circle around the world origin the fly cannot leave. Inside
arenaMargin of it the wall is read by each eye as something looming, so the
fly meets the wall with the circuits it already has; the body is clamped at
the radius as well, so whatever the circuits do the fly is still in the arena.
The wall is only a stimulus while the fly is carrying itself into it, and the
detectors adapt to it over WALL_ADAPT_S and recover over WALL_RECOVER_S.
A fly walking at the edge gets the burst that turns it; a fly resting against
the edge is looking at something that has stopped arriving, and drives
nothing. That matters beyond the fly: a standing drive on 165 looming neurons
puts the whole network into a spreading state, and every reading anyone takes
in this world is taken from that network.
escapeHz is a RISE, not a level. The reading is how far DNp01 has gone
above the rate it has been holding, averaged over ESCAPE_BASELINE_S. The
network's own recurrence holds the giant fibre at a standing rate with nothing
looming at all, and a threshold on the absolute rate reads that as a permanent
emergency and hops the fly for ever.
Fields: brain, bodyLength, walkSpeed, turnRate, legTurnGain,
motorFullHz, flightFullHz, tasteHz, loomHz, loomFov, escapeHz,
arenaRadius, arenaMargin, groundY, wander, wanderTurn.
wander and wanderTurn are the walking and the turning this fly does that
its connectome is not asking for, and motor() reports both apart from
brainWalk and turn, which are the network's. Set them to zero for a fly
that does only what the wiring says; leave them and a quiet network leaves a
fly that explores its arena instead of walking one straight line to the edge.
Methods: motor(), senses(), readouts(), sensoryNeurons(), drives(),
soundVolumes(). Events: onJump, onFeed (once per meal).
local fly = entity.spawn("Fly")
fly.component.add("FruitFly", { brain = entity.find("Brain"), bodyLength = 0.6, wander = 0.15, arenaRadius = 12 })
motor() reports brainWalk (the leg-motor term alone) and wander (the
baseline added to it) beside speed. senses() reports sugarFootL and
sugarFootR per front foot, loomLPLC2 and loomLC4 in Hz, loomSide
(-1 the left eye to +1 the right) and wall (0 to 1).
The fly's own drives are filed under the source fly, so clearing them leaves
the bench's and a protocol's standing.
On a shared world the entity's owner writes the senses into the brain (a synced call); every peer poses its own copy from its own network.