Repository navigation
How the Firmware Works
github-actions[bot] edited this page Nov 3, 2026
·
1 revision
You'll need: a copy of the project · Time: 10 minutes to read
Lola's code is a few Python files. One starts everything, one sets up the hardware, one reads your settings, and each behaviour has its own file.
| File | What it does |
|---|---|
code.py |
Starts here. Runs the start-up wiggle, then starts every behaviour at once. |
hardware.py |
Sets up the motors, lights, sensor and speaker. Says which part is on which channel. |
config.py |
Reads the numbers in settings.toml. |
settings.toml |
The numbers you can change. See Settings reference. |
behaviours/ |
One file per behaviour: boot, breathing, motion, attention, trench_run, leds. |
sounds/ |
Her sound files. |
log.py, boot.py, log_off.py
|
Messages, and saving them to log.txt. |
lib/ |
Adafruit's ready-made libraries. Don't change these. |
All the behaviours run at the same time, taking turns very quickly. When one needs the wings, it tells the others to wait using a shared signal (an event).
flowchart TD
start["code.py: main()"] --> boot["boot_sequence()<br/>start-up wiggle"]
boot --> snd["play one random sound"]
boot --> tasks{{"start every behaviour as a task"}}
tasks --> breathe["ambient_breathing()<br/>wings rise and fall"]
tasks --> motion["motion_sense()<br/>watches the accelerometer"]
tasks --> idle["idle_attention()<br/>waits, then wants attention"]
tasks --> leds["random_led_scheduler()<br/>white-light flickers"]
motion -- "small nudge" --> boop["nose_boops()"]
motion -- "3 nudges, or a shake" --> angry["angry_animation()"]
idle -- "50/50" --> att["attention_animation()"]
idle -- "50/50" --> trench["trench_run()"]
motion -. "sets reset_idle_event<br/>(restarts the wait)" .-> idle
boop -. "pause_breathing" .-> breathe
angry -. "pause_breathing" .-> breathe
att -. "pause_breathing" .-> breathe
trench -. "trench_active" .-> leds
The dotted lines are the events, in hardware.py:
-
pause_breathing: "I'm using the wings, stop breathing for a moment." -
reset_idle_event: "Someone touched her, start the attention wait again." -
trench_active: "The trench run is using the white light, don't flicker it."
-
asyncio, not threads. Every behaviour is an
async defrunning as a task. They only take turns at anawait, so a behaviour must useawait asyncio.sleep(), nevertime.sleep(): a blocking sleep freezes every other behaviour. The simulator warns[sim] <task> held the loop for N ms without an awaitwhen that happens. -
Motion reads only the accelerometer's z axis every 0.1 s, compared with the resting z measured after start-up and after each animation, so it works however the board is mounted. A change over
NUDGE_Z_MGis a nudge;ANGRY_NUDGESnudges inside one random window (ANGRY_MIN_WINDOW_S–ANGRY_MAX_WINDOW_S), or z overHARD_MOTION_MG, is angry. While an animation owns the wings the limit isANIMATION_NUDGE_Z_MG. -
Idle waits a random time between
IDLE_MIN_SandIDLE_MAX_Sforreset_idle_event. If it times out, it setspause_breathingand runs attention or the trench run. -
Sounds start with
play_wav("name.wav")inhardware.py, which returns straight away; a looped sound plays untilstop_wav()or the next sound. -
Eyes are PCA9685 channels driven as 360° "servos":
mainEye_red.angle = 360is full red. See the Channel map. -
CircuitPython subset. Stick to what CircuitPython 9 has: no
random.choices,os.pathorasyncio.TaskGroup. The simulator's CircuitPython strict catches these. -
Add a behaviour: write an
async defin abehaviours/module. If it takes no arguments it gets its own button in the simulator's Behaviours panel automatically. To make it run on its own, start it fromcode.pyor call it from another behaviour. - See also the Behaviour table.
DD-L0-LA59 Animatronics · Project on GitHub · Report a problem with this page · Edit these pages in the wiki/ folder
Start here
Using the simulator
- Get the simulator
- A tour of the window
- Make her breathe, boop and more
- Camera, overlays and recording
- Speed, scenarios and panels
- Layouts, themes and shortcuts
- Accessibility
- Troubleshooting and FAQ
Building the robot
- Safety first
- Parts list
- Wiring
- Install CircuitPython
- Copy the firmware
- Calibrate the wings
- Test it and read the log
Changing how she behaves
Adding new hardware
For developers
- Building the simulator
- Project layout
- CI and releases
- Contributing and branching
- Simulator architecture
- Adding a part kind
Reference