Scaling Up Your Robot Config With The New Missions And Modular Config Features
Copper is on a mission to help you, robot creators, go from 0 to production as fast as possible.
One of the major pain points on that journey? Config files. As your system grows, managing tasks, connections, and hardware parameters across multiple robot modes and platforms quickly becomes a mess. Here's what we’ve recently added in Copper to make config files not just manageable… but scalable!
Missions
In real-world robotics, a robot’s behavior is not unique, you often want variations of them, for example a datacollect mission or an autonomous navigation mission (you can also think of those as modes). With Copper’s new Mission Config, you can now declaratively define multiple missions that reuse the same task and connection structure but selectively activate subsets of the graph. This eliminates duplication and enables dynamic switching between modes like as another example a fallback or degraded behavior.
Missions Dag
Missions streamline deployment and testing by making mode-specific logic explicit and composable. See this simple example DAG and its matching configuration below. Either the green or red paths will be enabled.
(
missions: [ (id: "autonomy"),
(id: "datacollect"),
],
tasks: [
(
id: "src",
type: "tasks::ExampleSrc",
),
(
id: "autonomy_task",
type: "tasks::AutonomyTask",
missions: ["autonomy"],
),
(
id: "datacollect_task",
type: "tasks::DataCollect",
missions: ["datacollect"],
),
(
id: "sink",
type: "tasks::ExampleSink",
),
],
cnx: [
(src: "src", dst: "autonomy_task", msg: "i32", missions: ["autonomy"]),
(src: "src", dst: "datacollect_teak", msg: "i32", missions: ["datacollect"]),
(src: "autonomy_task", dst: "sink", msg: "i32", missions: ["autonomy"]),
(src: "datacollect_task", dst: "sink", msg: "i32", missions: ["datacollect"]),
],
)
Modular config
Robot configs can get messy fast. That’s why Copper now supports Modular Config: the ability to split configuration files into clean, reusable modules.
Each config module can define tasks, connections, logging, and hardware parameters, and can be included with parameter overrides (e.g., same motor config, different pins). This makes configs more maintainable, DRY, and easier to scale across platforms and variants.
Perfect for teams managing multiple robots or hardware layouts.
Here is an example:
// main_config.ron
(
tasks: [],
cnx: [],
monitor: (
type: "cu_consolemon::CuConsoleMon",
),
logging: (
file: "robot.copper",
level: "debug",
),
includes: [
(
path: "basic.ron", // see the included file below.
params: {},
),
(
path: "motor.ron", // see the included file below
params: {
"id": "left",
"pin": 4,
"direction": "forward",
},
),
(
path: "motor.ron",
params: {
"id": "right",
"pin": 5,
"direction": "reverse",
},
),
],
)
// basic.ron
(
tasks: [
(
id: "source",
type: "FlippingSource",
config: {
"rate": 10,
},
),
],
cnx: [],
)
// motor.ron
(
tasks: [
(
id: "motor_{{id}}",
type: "cu_rp_gpio::RPGpio",
config: {
"pin": {{pin}},
"direction": "{{direction}}",
},
),
],
cnx: [
(src: "source", dst: "motor_{{id}}", msg: "cu_rp_gpio::RPGpioPayload"),
],
)
All those have been release as of v0.8.0.
Full examples are in the example directory.
Any question? Join us on discord!
As usual, if you like what we are doing, drop a ⭐ on our github repo !