|
ME 405 Term Project
|
The Romi firmware is organized around a cooperative multitasking architecture, following the structure introduced in ME 405. Rather than implementing all behavior in a single monolithic loop, the system is decomposed into independent tasks responsible for sensing, control, actuation, estimation, and communication.
This architecture allows time-critical operations to execute deterministically while higher-level logic runs concurrently without blocking. Tasks communicate exclusively through shared variables and queues, which enforces clear interfaces and simplifies debugging and validation.
The figure below shows the high-level task structure used in the final system and the flow of information between tasks.
Each task executes periodically under control of the cooperative scheduler. Task periods were selected based on the timing requirements of each subsystem, balancing responsiveness with computational load.
The major tasks in the final system are summarized below.
Optional or experimental tasks, such as state estimation and path planning, are retained in the repository but are not enabled in the final configuration.
Tasks exchange data using thread-safe shared variables and queues rather than direct function calls. This design choice provides several advantages:
Low-bandwidth, frequently accessed values (e.g., velocity setpoints, measured velocities) are communicated using shared variables, while streamed data is handled using queues.
A cooperative scheduler is used to manage task execution. Each task yields control back to the scheduler after completing a bounded amount of work. This ensures that no single task can monopolize CPU time and that all tasks execute predictably.
Task periods were selected based on subsystem requirements:
This approach provided sufficient determinism for closed-loop control while remaining simple to reason about and debug.
The task-based architecture proved critical to the success of the project. Separating sensing, control, estimation, and communication into independent tasks made it possible to validate each subsystem incrementally before full system integration.
In practice, overall system performance was limited less by control structure and more by measurement quality and timing consistency. The cooperative multitasking framework made these limitations visible and manageable, reinforcing the importance of architecture in embedded system design.