-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
- Introduction
- The three layers
- Layer rules
- The vocabulary problem
- Naming rules
- Why the namespace is
OttoFlow - Blocking today, async ready
- Guards: disabled means silent
- Source layout
Three goals shape every decision in OttoFlow:
- Rapid development. A working behaviour in a handful of readable lines.
- A layered audience. Beginners never need to leave the top layer; power users never hit a locked door.
- A clear, consistent API. Every identifier states what it does, and in which unit.
Facades Mouth, Eyes, Voice, Legs, Arms, Gestures, src/facades/
Motion, Touch, Ears, Balance
Expressive sugar. Inline, zero overhead.
Modules Matrix, Ultrasonic, Buzzer, Melody, LegServos, src/modules/
ArmServos, TouchSensor, SoundSensor, LightSensor,
Bluetooth, Mpu6050, AppLink
Hardware-truth names. All real logic lives here.
Driver OttoDIYLib dependency
Reached by module .cpp files, and by you through
the official escape hatch, OttoFlowDriver.h.
The same action at each layer:
Mouth::show(Icon::Heart); // facade
Matrix::drawIcon(Icon::Heart); // module
OttoFlow::driver().putMouth(heart); // driverFacades are inline forwarders, so the first line compiles to exactly the same machine code as the second. Expressiveness costs nothing on an ATmega328.
- Each layer talks only to the layer directly below it.
- Facades contain no logic -- only inline forwarding. This keeps the friendly vocabulary and the technical vocabulary in lockstep with zero duplication.
- Public headers never include OttoDIYLib headers. OttoDIYLib defines lowercase macros such as
heartandsmile; keeping them out of<OttoFlow.h>prevents them from colliding with names in your sketch. Modules include<Otto.h>in their.cppfiles only. - Modules reach the shared driver instance and the active configuration through
core/Internal.h, which is framework-internal and never included by a sketch.
What one person calls a face, another calls a mouth, and a third calls a display. OttoFlow does not pick a winner -- it layers:
- Underneath, unambiguous technical names. Nobody argues about what
Matrixmeans. - On top, expressive names as documented sugar:
Mouth.
Both are official API. The technical layer is the truth.
For the sugar word itself OttoFlow deliberately adopts the upstream OttoDIYLib and community vocabulary: the matrix is Otto's mouth (putMouth in the driver, "mouth" in every Otto tutorial). Ecosystem consistency beats inventing a prettier word.
-
Units live in the name.
distanceCm(),playToneHz(),periodMs,positionLeftDegrees(). Never a bare number with an implicit unit. -
Directions are words, not signs.
walkForward(2)andwalkBackward(2), neverwalk(2, 1000, -1)in user-facing code. -
Conditions read as sentences.
Eyes::closerThanCm(15). -
Enums instead of magic numbers.
Icon::Heart,Sound::Happy,Gesture::Victory. - PascalCase for namespaces and enum values, camelCase for functions.
-
Plain hardware names over domain jargon. The leg module is
LegServos, symmetric withArmServos, notGait. A beginner should never need a robotics glossary to guess what a module controls.
OttoDIYLib defines a C++ class named Otto. A namespace with the same name cannot coexist with it in one translation unit -- and the escape hatch requires both to be visible at once. So the entry point is OttoFlow:: (on brand anyway) and the driver class keeps its original name.
Every movement call blocks: Legs::walkForward(2) returns when the walk is finished. The underlying OttoDIYLib is blocking, and sequential code is what beginners reason about most easily.
The names were chosen so a non-blocking engine can be added later without renaming or breaking anything: startWalkingForward(), isMoving(), and stop() will sit next to the current calls. See the Roadmap.
Every module that can be switched off follows the same pattern: while it is disabled, its calls are silent no-ops. Not an error, not a warning, not a compile-time flag.
Motion::disable();
Legs::walkForward(2); // does nothing, and that is fineThis is what makes Bench Testing work without #ifdefs scattered through a sketch, and what lets one sketch run on builds with and without arms.
src/
OttoFlow.h the single include a sketch needs
OttoFlowDriver.h opt-in escape hatch to raw OttoDIYLib
core/
OttoCore.h/.cpp start(), isStarted(), version(), the driver instance
OttoConfig.h OttoConfig, Preset, per-module settings
Icons.h the Icon enum
Sounds.h the Sound enum
Gestures.h the Gesture enum
Internal.h framework-internal access to driver and config
modules/ hardware-truth layer
facades/ expressive layer
console/ the serial test console
To add your own part, see Extending OttoFlow.
OttoFlow is licensed under GPL-3.0 and wraps OttoDIYLib. Buy the kits at ottodiy.com.
Prologue
Getting Started
The Basics
Digging Deeper
- Bench Testing
- Serial Console
- Calibration
- Bluetooth and the Otto App
- Modules
- The Driver
- Extending OttoFlow
Reference