-
Notifications
You must be signed in to change notification settings - Fork 57
Copper Release Notes
Major milestone: baremetal support lands across the stack, SD/eMMC logging backends, CMSIS-DAP probe workflow. RP2350 is the reference platform; examples and scripts are included.
-
Baremetal (no_std) end-to-end
Ported core crates and runtime tono_std
and added embedded tests to CI ([#444], [#446], [#447], [#449], [#450], [#451], [#452], [#453], [#454], [#455], [#456], [#457], [#458], [#459], [#460], [#461], [#466], [#467], [#468]) -
RP2350 Reference Example
examples/cu_rp2350_skeleton
a "blinky" example for Copper on its reference platform to get you started quickly. Pairs with docs and a formatting script for the Copper log partition on SDCards. ([#467], [#468]) -
RobotClock with Calibration (baremetal + host)
New calibrated clock that accepts an external reference (RTC/GPS/etc.) on embedded and desktop; raw counter access standardized. ([#478]) -
Logging straigth to a filesystem partition: SD / eMMC logging backends
Embedded backends for unified logging ([#473], [#474]) -
CMSIS-DAP probe workflow + defmt bridge
Probe defaults,cargo run
deploy loop via probe; bridged the Copper logging todefmt
for MCU-friendly debugging. ([#470]) -
Host vs Firmware split
Cleaner tree and CI: host utilities (incl.run-logreader
) live outside firmware paths. ([#476]) -
More tolerant log reader
No longer panics on unclosed logs; returns an error instead. ([#477])
-
Stabilized std/no_std/sim combos and removed legacy
host
feature in favor of explicitstd
flags where applicable. ([#462]) -
Config & runtime refactors for embedded storage backends in
CuApplication
. ([#472])
Point release improving simulation control, fixing task indexing bugs, and refreshing several dependencies for long-term maintenance.
-
run_in_sim
for Sources & Sinks ([#431])
Override Copper’s default sim stubbing for hardware endpoints. Useful when your sim must keep talking to external middleware (ROS bridge, Zenoh, etc.).( tasks: [ ( id: "ros_bridge", type: "tasks::RosBridgeSink", run_in_sim: true, // real sink runs even in sim ), ] )
- Task output index calculation fixed to select the correct output slot. ([#426])
-
Index into output arrays now uses
node_id
rather thanoutput_position
. ([#430]) - Threadpool use-after-move resolved by cloning the pool correctly; improves stability for background tasks. ([#416])
- cu-monitor empty status crash removed legacy workaround that caused crashes. ([#415])
- Crates.io metadata corrected for publication. ([#414])
- CI: disabled Windows CUDA runner until upstream action is fixed. ([#424])
-
ron
→ 0.11.0 (API changes adapted). ([#427]) -
pyo3
→ 0.26.0 (ported to new API). ([#429]) -
cached-path
→ 0.9.0. ([#428]) -
nalgebra
→ 0.34.0. ([#420]) -
cudarc
→ 0.17.0. ([#419]) - GitHub Actions:
Jimver/cuda-toolkit
0.2.26 → 0.2.27. ([#425]) - GitHub Actions:
actions/checkout
v5. ([#423])
This release is primarily driven by user requests. It introduces a full transform library (à la tf2 for ROS), new keyframes in the logs, background tasks, a log checker, and a set of runtime and logging tuning parameters to better adapt to constrained environments.
The task API now uses finer-grained lifetimes for input and output types. This provides greater flexibility when testing tasks and was necessary to support the implementation of background tasks:
Old API:
impl<'cl> CuSrcTask<'cl> for FlippingSource {
type Output = output_msg!('cl, RPGpioPayload);
fn process(&mut self, clock: &RobotClock, output: Self::Output) -> CuResult<()> {
self.state = !self.state; // Flip our internal state and send the message in our output.
output.set_payload(RPGpioPayload {
on: self.state,
creation: Some(clock.now()).into(),
actuation: Some(clock.now()).into(),
});
Ok(())
}
}
There are two changes required to port your tasks:
- The lifetime has moved from
<'cl>
on the task struct to<'m>
on theInput
andOutput
types. - The
process
method now takes explicit references:&
for input and&mut
for output.
impl CuSrcTask for FlippingSource {
type Output<'m> = output_msg!(RPGpioPayload);
# ^^^^
fn process(&mut self, clock: &RobotClock, output: &mut Self::Output<'_>) -> CuResult<()> {
# ^^^^ ^^^^
self.state = !self.state; // Flip our internal state and send the message in our output.
output.set_payload(RPGpioPayload {
on: self.state,
creation: Some(clock.now()).into(),
actuation: Some(clock.now()).into(),
});
Ok(())
}
}
The cu_transform
crate provides real-time spatial and velocity transformations for Copper, with support for hierarchical frames, interpolation, and zero-allocation caching.
Huge thank you to @makeecat for this feature!
- Homogeneous matrix representation of 3D transforms
- Time-stamped pose updates and interpolated lookups
- Hierarchical transform tree with parent-child frames
- Velocity computation via transform differentiation
- Rigid-body velocity frame transformations
- High-performance caching for repeated transform/velocity queries
- Zero-allocation for real-time performance
use cu_transform::{StampedTransform, TransformTree, Transform3D};
use cu29::clock::CuDuration;
let mut tree = TransformTree::<f32>::new();
tree.add_transform(StampedTransform {
transform: Transform3D::default(),
stamp: CuDuration(1000),
parent_frame: "world".try_into()?,
child_frame: "robot".try_into()?,
})?;
let pose = tree.lookup_transform("world", "robot", CuDuration(1000))?;
use cu_transform::TransformTree;
use cu29::clock::CuDuration;
let velocity = tree.lookup_velocity("world", "robot", CuDuration(1500))?;
let linear = velocity.linear_velocity();
let angular = velocity.angular_velocity();
This component is ideal for real-time robotic applications needing fast, correct spatial and motion reasoning across dynamic coordinate frames.
- background tasks: we now have a best effort asynchronous task type. Be careful to use memory handles if you feed them a large amount of data has the input and output need to be copied to allow the asynchronism to work. How to use it? just add background: true to any CuTask (not Src nor Sink).
(
tasks: [
(
id: "task1",
type: "tasks::ExampleTask",
background: true, // that's it
),
]
The result will be set in a random future CopperList so for the downstream tasks keep a close eye on the input.tov
field to know from where this message is coming from.
Note: We have not implemented the deterministic replay yet for those, but it will come in an upcoming release.
- logreader fsck: we now have a cool tool to not only check for the consistency of a Copper log and giving you some explanation of any corruption, it gives out some cool statistics about the logs:
pal ➜ cu_caterpillar (master) cargo run -r --bin cu-caterpillar-logreader logs/caterpillar.copper fsck
The log checked out OK.
=== Statistics ===
Total time -> 1.481 s
Total used size -> 14,120,984 bytes
Logging rate -> 9.09 MiB/s (effective)
# of CL -> 20,303
CL rate -> 13,708.96 Hz
CL total size -> 10,384,994 bytes
# of Keyframes -> 3
KF rate -> 2.03 Hz
KF total size -> 28 bytes
# of SL entries -> 162,433
SL total size -> 3,735,962 bytes
- Added a runtime rate target configuration (#410): Copper can be too fast, especially with the introduction of background tasks. We added a way to rate limit the CopperList creation, exactly like a frame rate limiter would work in games because probably your robot doesn't need 500KHz refresh rates normal use cases.
For example limit at 100Hz:
(
runtime: (
rate_target_hz: 100,
),
tasks: [
- Adds a way to disable logging for some tasks. (#407)
With the determinism built in Copper, you might not want to log everything. We added a way to disable the logging of any task output. It will keep the metadata of the output though (Time of Validity, Status string ....)
tasks: [
( // Normal
id: "task0",
type: "tasks::ExampleSrc",
),
(
id: "task1",
type: "tasks::ExampleTask",
logging: (
enabled: false, // HERE, no more logging for this one
)
),
- Keyframes (#369): Now Copper is able to record "keyframe" ie. the serialized state of all the tasks during runtime, sim or resim. This will allow nifty debugger features.
- force Serialize implementation on CuMsg: This guarantees that the log reader can at least reexport the messages to all the SerDe backends.
- cu-dorabench: a new benchmark more geared toward bandwith more than just latency.
- CuStampData: a lot of robotics data needs to be timestamped and this is also true for the CuMsg between tasks. We have generalized this concept so you can use a contained with a time of validity and arbitrary metadata for your own internal use in your tasks and libraries.
// CuMsg is now defined as
type CuMsg<P> = CuStampData<P, CuMsgMetadata>;
// And now TOV (the time of validity for this temporal data) is directly accessible in the main object instead of the metadata
let mut m: CuMsg<u32> = CuMsg::new(12);
m.tov = CuDuration(1000).into();
// You can define temporal data types for yourself for example
type MyTemporalData = CuStampData<f64, ()>;
// And use them directly as a field in your tasks.
- resim implemented for cu-caterpillar (#364): added that to our venerable example to test out various logger features easily.
-
cargo cubuild (#365): helps you debug when a change causes a code compilation error in the generated code. Just use that instead of
build
and it will insert the generated code at the macros spot and compile it. - CuCompactString: Better log and debug output showing the string nicely.
- Unified Logger Poisoned lock (#390): We had a cascading error when the main thread would panic and drop the logger.
- Task DAG in the Monitoring UI is slow (#391): Thanks to Matthew Ashton-Knochel from working with tui-nodes folks to optimise the direct rendering mode of it.
- Restored the original log debug behavior (#381): if nothing is specified -> debug builds enable log-debug, -> release buids enable log-info. if anything is specified, it will repect the user's choice.
- Unconditionally install ctrl-c handler (#375): instead of relying on user's code to handle that as it can cause easy log corruption.
- Fix CuCompactString initialization CuListsManager (#409): a zero init of the copper list created status strings that are all 24x
\\0
. This fixes it with a correct initialzation that set them at length 0 instead. It was wasting a bunch of log space for no reason.
- socket2 -> 0.6.0
- cuda-toolkit -> 0.2.26
- gstreamer & gstreamer-app -> 0.24
- rerun -> 0.24
- glam -> 0.30.x
- thiserror -> 2.x
This release has been focused on Zenoh and ROS2 interoperability, modular configuration for larger robots with a new support for the notion of "mission" (aka mode like autonomy mode, datacollect mode etc..)
-
Copper to ROS2 Integration: We now support streaming Copper data directly to ROS2 (rwm_zenoh). This includes a working example bridging Copper tasks to ROS2 nodes and a translation layer for Copper message representations. See PR #348.
-
Zenoh Sink: Added a
zenoh_sink
component to forward Copper messages to any other Zenoh participant with the serialization of your choice. Thanks to @kamibo (#316). -
Missions System: You can now define and generate missions from RON, with automatic default fallback. Missions are properly serialized, structured, and support reuse through includes. (#337, #294)
-
Modular Configuration System: Copper now supports reusable and parameterized config files. This feature introduces relative/absolute file includes, parameter substitution using
{{param}}
syntax, and well-defined merging rules. You can now split large config files into logical components and reuse templates with different parameters.
Example templates are included under themodular_config_example
directory.
Thanks to @makeecat (#328) -
Memory Pool Monitoring UI: Copper's monitoring console
cu-consolemon
now includes a dedicated page to visualize memory pool usage in real time. It displays total preallocated memory, in-use buffers, memory handles in flight, and the allocation rate. This provides better observability into buffer-heavy pipelines using CopperLists and memory pools.
Thanks to @makeecat for implementing this! (#190)
-
CuRateLimit Task: A new
CuRateLimit
task lets you easily throttle any message flow without modifying the producing task. See #343. -
Copper Application Trait: Introduced a trait to generalize Copper applications. Enables grouping and dynamic handling of mission-defined applications. (#345)
-
Nix Setup: Introduced Nix setup for Linux, supporting CUDA / non-CUDA environment. Thanks to @makeecat! (#332)
-
Compile-time log-level macro: Copper now supports compile-time log filtering for logs. This feature lets you fully disable logging macros at compile time by enabling only the relevant features in
Cargo.toml
. It introduces alog-level
field inCuLogEntry
, and updates serialization, formatting, and documentation accordingly. Thanks to @makeecat! (#318) Example usage:
[dependencies]
cu29 = { version = "0.7.0", features = ["log-level-debug"] }
-
CuGraph Separation: Graph-related functionality has been extracted into its own module to reduce coupling between configuration and execution layers. (#334)
-
Bevy 0.16 Support: Copper is now compatible with Bevy 0.16, including updated patches for asset loading and avian3d. Thanks to @makeecat (#303).
-
Support for iceoryx2 v0.6.1: Iceoryx2 backend updated and patched accordingly. (#338)
-
Dockerization of ros-caterpillar:
ros-caterpillar
has been fully containerized to deal with OS dependency hell. It is now portable and future-proof. (#348)
-
iceoryx2-bb-log
bumped to 0.6.1 (#340) -
uom
bumped to 0.37.0 (#339) -
Other crates:
cached-path
,iyes_perf_ui
,faer
,ron
,petgraph
,nix
, etc. updated to support Bevy 0.16 and latest Rust editions.
This release added a set of feature useful to develop autonomy algorithms on Drone (MSP). We also have a solid set of quality of life improvements derived from real usage.
- bincode after 4 years stuck at the 2.0.0-rc3 decided to release the 2.0.0 and it broke the API. This release updates all our API calls. The good news is that decoding in memory pools are now supported, it will be useful.
- gstreamer support
You can define arbitraty gstreamer pipeline and hook it as an appsink to Copper are a SrcTask [#239]
This for example a source that will get the camera from your robot, stream it to a host on your network for live display but also convert it to GRAY8 and inject it to the Copper task graph.
(
id: "video",
type: "cu_gstreamer::CuDefaultGStreamer",
config: {
"pipeline": "v4l2src device=/dev/video9 ! image/jpeg,width=1920,height=1080 ! tee name=t t. ! queue ! jpegdec ! videoconvert ! appsink name=copper t. ! queue ! jpegparse ! rtpjpegpay ! udpsink host=192.168.1.73 port=5000",
"caps": "video/x-raw, format=GRAY8, width=1920, height=1080",
},
),
- Dynamic Threshold. A quick 0 copy implementation using an integral image. [#244]
- April Tag support. It can give you the relative pose of tags from images. [#246]
(
id: "pos",
type: "cu_apriltag::AprilTags",
config: {
"tag_family": "tag16h5",
"tag_size": 0.14,
"fx": 1513.93,
"fy": 1513.93,
"cx": 946.84,
"cy": 557.819,
},
),
- MSP (MultiWii Serial Protocol)
This is a communication protocol used on drones with INAV, cleanflight, betafligh [#248]
- Added 2 new robotics standard messages: Transform3D and Pose [#245]
They can be transformed back and forth with into()
from Faer and Nalgebra so you can integrate that to your robotics algorithms smoothly.
let pose = Transform3D {
mat: [
[1.0, 2.0, 3.0, 4.0],
[5.0, 6.0, 7.0, 8.0],
[9.0, 10.0, 11.0, 12.0],
[13.0, 14.0, 15.0, 16.0],
],
};
- The
Cu29
crate has a new global debug_macro feature to be able to see any generation (runtime, structured logging, SOAs etc...) [#247] - PyO3 (the python bindings for log reading) is now an optional feature [#240] Thanks Mike Kaliman!
- The Input order in the tuples of tasks receiving messages from more than one taask is now determined by their order of connection [#251] Thanks @hscoelho!
- Better feedback when a task sends an error to the runtime. Ie. now it actually triggers a debug! with the error description instead of just giving you the result of the monitoring behavior.
- CuTime now support Copy which makes clock forwarding more immediate.
- Bevy perf-ui is back (overlay for bevy) and can be used in your simulations (see cu-balancebot) [#263] Thanks @AS1100K!
And finally special thanks to @makeecat for the ongoing help on the CI/CD that starts to be a complicated piece of machinery at this point.
-
Images support: We added the API to make a pool instance and bind is as a [u8] for an image buffer, see below about Memory Pools.
-
Video For Linux 2 support: We built a V4L2 source so you can read images directly from you video system on Linux. The component is named
cu_v4l
here are an example of parameters to can set in your RON file:
config: {
"device": 0, // The /dev/video0 device
"width": 3840, // Width asked
"height": 2160, // Height asked
"fps": 30, // image rate
"fourcc": "NV12", // buffer format
"buffers": 4, // how many buffers you want to allocate
"timeout_ms": 500, // time before giving up on trying to get a frame
}
4k.capture.mp4
-
Computer Vision: Kornia API support: Kornia is an awesome Computer Vision set of algorithms. The 2 projects cooperated to we can map Copper images to Kornia and Kornia can accept them with 0 copy! Check out the Kornia-rs project. Big thanks to the creator of this project Edgar Riba for his support!
-
0-Copy Heterogeneous Memory Pools: Said wut?
Before this release anything the tasks would touch (as input or output) would have been needed to be copied in the CopperList ie. the backing structure that makes Copper so fast and low latency with no synchronization etc. Building a complex robot is the art of having not only low latency like this but also large throughput: this is the large throughput side of Copper for modern computer architectures!
You can create large memory buffers pools either in main host memory or on a "device" for example a GPU (this is what heterogeneous memory means) and Copper will give you memory handles that you can use to:
- pass the memory to another task
- pass the memory to the accelerator that can use it (for example CUDA kernels see below)
- pass the memory to a DMA backed driver (see the new V4L driver below)
For you developer, it means that you can safely stream multi-megabytes structures (Images, Matrices, PointClouds etc..) at no cost and you also buffer them in tasks if you need to keep them for a few cycle more (for temporal alignment for example).
-
New Basic Livox Lidar Tele15 Driver:
Thanks to @luc-k1 from Konboi One.
- New Debug log pane in cu-consolemon: Before that you had to choose between the cool TUI and the text log (that was hidden behind) but thanks to @AS1100K effort we now have a tab that can capture your debug logs! (it is only enabled if you want them as they are expensive to build and if the app is build in debug mode).
- Pcap replay support: for drivers reading data from the network, it is very common to build a test set from network capture. This is a little tool that help driver developer to inject those capture and build a small test data set to validate their driver.
- Quicksort on PointCloud SOA ts: Sorting by time of validity allows the points to get merged more efficiently.
2 lidar sources getting merged.
- Prelude: we drastically simplified the imports for Copper, now you just need to do:
use cu29::prelude::*;
And you are good to go for starting Copper, creating tasks, etc...
-
More flexible project generation: The template will ask you which version of Copper you want to generate your project for.
-
Log parameter in RON: Added the section_size parameter in the RON file. It is useful to tune your logging throughput.
-
Builder pattern for the Copper Application: we made the CopperContext official and change the app init to be with a cool builder pattern like:
let mut application = CaterpillarApplicationBuilder::new()
.with_context(&copper_ctx)
.build()
.expect("Failed to create application.");
Thanks to @hscoelho for this one!
-
Log disable: Now you can disable task logging completely (if you know you won't need the data). Thanks to @AS1100K!
-
Better feedback on configuration snafu: We improved the clarity of the messages given to the user with a line number if possible in case of misconfiguration... Thanks again to @AS1100K!
-
Full dependency update: Enjoy the latest Bevy, the latest Rerun, the latest everything thanks to @makeecat. This includes the new picker that has been integrated to Bevy.
-
Logger Parameters Consistency: We now check if the various parameters of the unified logger makes sense ie. section not larger than slabs etc.. that avoids a lot of user confusion.
-
Clippy escaped our CI/CD again but thanks to an heroic effort from @makeecat we have a major improvement on our CI/CD to cross check all the platforms, features and configurations.
-
-= op on CuTime, it is useful to compute quickly time offsets.
-
ScopedAllocCounter: we improved their use by exposing a sane public API so you can check if you or one of your dependency is allocating in a given scope. Thanks to Zac8668
-
X11 support for Bevy on Linux: Apparently some people have not migrated to Wayland yet :P. Thanks @Paulotten
-
Missing ./logs would make cu-balancebot-sim crash: thanks @vsenn for reporting this.
-
Microsoft Windows Compatibility is finally complete #129: So many thanks to @Lishen_ for the unwaivering bruteforce port.
-
Rerun visualization for pointclouds #131: Added an example to start and feed rerun visualization with our standard pointcloud
-
BalanceBot Simulation perf overlay #137: Now you can activate the
perf-ui
feature to see if the bevy side of the simulation is working well in a diag overlay. -
Iterators For SOAs (Struct of arrays) #134: SOAs can generate an iterator for a quick SOA to AOS transform and natural API.
-
BalanceBot Simulation Issues #137: Resolved a waste of resources on
balancebot-sim
(the bevy entities were created over and over). Thanks to @Nashenas88 for spotting the issure and the initial fix. -
Pointcloud payload and Hesai structs visibility fix #132 & #133: Snafu as they were published with no client crates.
-
Multiple gammar fixes #125: Thanks to @AnyTimeTraveler for all the corrected Frenglish.
-
Deterministic Log Replay: Copper can now replay a log through your code in a deterministic fashion ie. if your tasks are deterministic, it will always output the same output from the same input! See the balancebot-resim for example.
-
Aligner Task #114: Added an aligner task that synchronizes multiple inputs by aligning matching time windows, facilitating coordinated data processing. This is particularly useful for sensor fusion.
-
❗ Lifecycle Trait Removal #115: Removed the lifecycle trait to simplify task implementation and decouple passed types, streamlining the codebase. To build a minimum task a user needed to implement one method from the CuTaskLifecycle trait (new) and at least the process method from they flavor of tasks. This was forcing the implementation of 2 mandatory traits which is not necessary or useful for the user. Now we moved all the lifecycle methods in the tasks trait to only have to implement 2 traits (the task and Freezable, the serialization of its state)
-
Named Output Mapping on CopperLists #121: Implemented mapping of Copperlist indices to named outputs from tasks, allowing users to access task outputs symbolically without relying on execution order.
-
CuTimeRange Introduction #106: Introduced
CuTimeRange
to represent messages containing multiple Time of Validity (TOV) instances, such as sequences of images or IMU measurements. -
Windows Compatibility #110: Enhanced compatibility by adding a mock for
cu_ads7883
, enabling compilation on Windows platforms. -
Dependency Updates #104: Performed a general dependency bump post-release to incorporate the latest improvements and fixes.
-
Faster SOA ops: adding len to the public API allows quicker preallocations.
-
f32 shortcut for dimensions and reflectivity for Lidars: simple from f32 makes it easier to not deal too much with the units.
-
BalanceBot Simulation Stability #118: Resolved a core dump issue on exit for
balancebot-sim
by enforcing specific graphics backends, ensuring clean termination. -
CuCompactStr Serialization #119: Fixed serialization and deserialization issues with
CuCompactStr
to ensure correct data handling. -
Project Generation Fix #120: Addressed issues in project generation by adding
crate::
forcumsgs
generation, ensuring correct module resolution. -
Unused Code Cleanup #121: Removed unused imports and methods to maintain code cleanliness and reduce potential maintenance overhead.
-
Test Stability #107: Ignored hardware-dependent tests and added
test --workspace
to CI/CD to enhance test reliability across different environments.
- Iceoryx2 Support #87: Introduced Iceoryx2 support. Iceoryx2 is the successor to Iceoryx in pure Rust. The Copper support included a source component to receive messages, a sink component to send messages.
- Hesai XT32 Support #101: Added the preliminary support for the Hesai XT32. If you have the actual HW handy, feel free to provide us the feedback!
- First standard Lidar Message Design #99: For now in SOA out or the lidar sensors it allows SIMD optimizations for the first operations that are usually a frame transform.
-
Variable-Length SoAs #100: Improved
SoA
(Structure of Arrays) to support variable lengths on top of their fixed size in the Copper List. - CI Improvements #98: Integrated clippy warnings into CI, thanks to makeecat
-
BalanceBot Simulation Reset #86: Improved the
reset_sim
functionality for the balance bot. Thanks to makeecat. - Publishing Fixes #103: Resolved various publishing issues and added dry-run validations to avoid disruptions.
- Simulation API Support: With sim-mode=true in the main Copper macro, Copper will generate for you all the callbacks at all the tasks states it is going through (Start, Preprocess, Process, etc...). Combined with the already mockable Clock it allows a very easy integration with a virtual environment.
- BalanceBot Simulation #69: Built on that and leveraging Bevy and Avian3D for realistic motion dynamics, we made a little demo of our little real world demonstrator. The real world code and the sim code are 100% identical.
-
Config Embedding #78: Embedded the default
copperconfig.ron
directly into the Copper executable, simplifying deployment for the main case (just one executable to copy and that's it!!). If the file is present, it will take precedence over the embedded version. We also do log the actual config used in the logs so you can come back to it in doubt.
- Cross-Platform Compatibility for Mocking #75: Enhanced feature flags to better support various platforms, particularly macOS, enabling testing with mocked hardware dependencies. The full repo now compile under CI/CD on MacOS and Linux (previously it we could only compile and test the Core)
- Terminal Restoration #73: Fixed issues with terminal states not restoring properly upon exit, preventing corruption and enhancing the overall stability of simulator sessions.
- Print Output Cleanup #80: Streamlined console logging to minimize redundant or unnecessary print statements, making debugging output more manageable.
- Git LFS Migration #76: Moved heavy assets to a CDN to mitigate GitHub LFS limitations, reducing operational overhead and streamlining asset distribution.
- Asset CDN Integration #35: Transitioned assets to a content delivery network to avoid the super costly Github LFS.
- Improved Documentation #82: Expanded and refined documentation across modules, enhancing clarity for new users and developers.
- Logging Value Enhancements #80: Fine-tuned value logging to increase logging granularity and simplify troubleshooting in complex simulation states.
- Feature Flag Revamp #75: Restructured feature flags to better support debugging and cross-platform configurations, especially for macOS compatibility.
A Minor release with 2 new components and some fixes.
-
New cu-pid task: this is the first algorithm we publish. It is from the balancebot, a generalized PID controller logic you can reuse in your projects, see the readme in the crate.
-
New cu-consolemon monitoring: this is a TUI for Copper showing the information exposed by the new monitoring interface released in 0.3.0.
- Added
Mul
toCuDuration
for easy time offset computations.
-
Tree Reorganization:
- Major reorganization of the repository structure for improved clarity and maintainability.
-
Logging Fixes:
- Resolved an issue where
OnceLock
was not releasing the unified logger, preventing a clean shutdown of the logger. - Addressed an issue with a double close in the logger during shutdown.
- Resolved an issue where
This alpha release introduces substantial improvements to the Copper framework's monitoring capabilities and API flexibility.
- New multisource and optional input API: The Copper engine now supports multiple and optional inputs/outputs (see PR #44).
This is a breaking change.
Now you can link 2 tasks to one in the RON file like this:
tasks: [
(
id: "balpos",
type: "cu_ads7883::ADS7883",
),
(
id: "railpos",
type: "cu_rp_encoder::Encoder",
),
(
id: "pidctrl",
type: "pidtask::PIDTask",
config: {
[...]
},
),
(
id: "motor",
type: "cu_rp_sn754410::SN754410",
[...]
),
],
cnx: [
// vvvvvvvvvv same dest!
(src: "balpos", dst: "pidctrl", msg: "cu_ads7883::ADSReadingPayload"),
(src: "railpos", dst: "pidctrl", msg: "cu_rp_encoder::EncoderPayload"),
(src: "pidctrl", dst: "motor", msg: "cu_rp_sn754410::MotorPayload"),
],
)
To help you manage the types that are generated, we are giving a set of macros to help you matching the correct input / output types:
impl<'cl> CuTask<'cl> for PIDTask {
// This tasks takes 2 inputs!
// They are given in the order of task declaration
// the input_msg! macro build a (&CuMsg<ADSReadingPayload>, &CuMsg<EncoderPayload>) tuple under the hood.
// it also works with 1 input and then you will get a straight &CuMsg<> immutable ref.
// For technical Rust reasons, you need to explicitely tie the lifetime ('cl means copperlist if you are curious: the internal structure of copper for messages)
type Input = input_msg!('cl, ADSReadingPayload, EncoderPayload);
// same thing but as an output this is a &mut CuMsg<MotorPayload>
type Output = output_msg!('cl, MotorPayload);
fn process(
&mut self,
clock: &RobotClock,
input: Self::Input, // here this is now straight the input type, it is a little simpler.
output: Self::Output,
) -> CuResult<()> {
let (bal_pos, rail_pos) = input; // you can unpack the tuple directly those are resp. &CuMsg<ADSReadingPayload> and &CuMsg<EncoderPayload>
let bal_tov = bal_pos.metadata.tov.expect("we should have had a message here!"); // the messages are now optional depending on the context they could be expected or really optional.
// we have a new method called set_payload for the output
output.set_payload(MotorPayload { power: 0.0 }); // If you don't do that it will send away a message with a None payload
- Monitoring System: The monitoring framework is now fully integrated, allowing real-time stats collection and cumulative statistics (see PRs #49, #50, and #51). We can imagine complex decision trees happening at that stage for complex robots and various degraded modes.
The monitoring component is really similar to a task, but with specialized callbacks:
// This is in the RON file, just add a monitor entry like this:
tasks: [
(
id: "task0",
type: "tasks::ExampleSrc",
),
[...]
],
cnx: [
(src: "task0", dst: "task1", msg: "i32"),
[...]
],
monitor: (type: "ExampleMonitor") // here, add a config entry if necessary
)
struct ExampleMonitor {
tasks: &'static [&'static str], // We give you the task ordinal to task id mapping (so it is stable as long as you don't change your task ids.
}
impl CuMonitor for ExampleMonitor {
// We pass you the config you gave in the RON file exactly like for the tasks.
fn new(_config: Option<&ComponentConfig>, taskids: &'static [&str]) -> CuResult<Self> {
Ok(ExampleMonitor { tasks: taskids })
}
fn start(&mut self, clock: &_RobotClock) -> CuResult<()> {
// callbacked when all the tasks, start called.
}
fn process_copperlist(&self, msgs: &[&CuMsgMetadata]) -> CuResult<()> {
// This is callbacked at the end of the processing of a copper list (basically near when the CL is getting serialized to disk after a success.
// The metadata gives you all the timings you need to check if your robot is still behaving nominally.
for t in msgs.iter().enumerate() {
let (taskid, metadata) = t;
debug!("Task: {} -> {}", taskid, metadata);
}
Ok(())
}
fn process_error(&self, taskid: usize, step: CuTaskState, error: &CuError) -> Decision {
// This is called back if any task reports an error at any step (start, process, ...)
// You can then match that taskid and compute a decision for your robot: Abort, Ignore, Shutdown (see the cu28/monitoring.rs file for semantic details.
Decision::Ignore
}
fn stop(&mut self, clock: &_RobotClock) -> CuResult<()> {
// call when the stack is stopping
Ok(())
}
}
- Real-time cumulative stats for
CuDurations
. See cu29/monitoring.rs we built an histogramming feature for timings this is super useful for monitoring components. Here is the list of everything you get it is not only pretty comprehensive but it is fixed size on memory so it should be pretty swift for any real time monitoring needs or UIs.
// on the CuDurationStatistics struct
pub fn min(&self) -> CuDuration;
pub fn max(&self) -> CuDuration;
pub fn mean(&self) -> CuDuration
pub fn percentile(&self, percentile: f64) -> CuDuration;
pub fn stddev(&self) -> CuDuration;
pub fn jitter_min(&self) -> CuDuration;
pub fn jitter_max(&self) -> CuDuration;
pub fn jitter_mean(&self) -> CuDuration;
pub fn jitter_stddev(&self) -> CuDuration;
pub fn jitter_percentile(&self, percentile: f64) -> CuDuration;
- Serialization / Deserialization Bug on Value (#42). A code reformat shuffled the serialization IDs Oo.
-
Virtual Output for Sinks (#53):
- before that there was no mean to monitor sinks (or hacks you might have seen on the incoming message). Now the stack behind the scene generates a () empty message for each sink you you get the perf number cleanly for them even if they don't output anything.
-
Balance Bot Demo (#46):
- a more complete example of a real robot demo we will bring at conferences.
- And a bunch of cleanup / doc improments.
We are pleased to announce the release of Copper v0.2.3, which includes several new features, enhancements, and bug fixes. Below is a summary of the key changes in this release:
- SN754410 Driver Support #40: Added a new driver for the SN754410 motor driver. This driver allows easy integration with motor control applications, providing robust support for H-bridge motor control on a wide range of systems. This driver is fully compatible with the BalanceHAT.
- ADS7883 Driver #39: Introduced a driver for the ADS7883, a 12-bit SPI ADC. This addition includes comprehensive documentation in the README to facilitate setup and integration. The ADS7883 driver is also compatible with the BalanceHAT.
- macOS Development Support #25: Copper can now be developed on macOS! The CI/CD pipeline has been updated to support macOS, ensuring cross-platform compatibility for all users.
- cu29_clock Enhancements #32: Added a division feature to the cu29_clock, allowing more granular time management and synchronization within the Copper runtime.
- Structured Log Index File in Debug Mode #30: Removed the requirement for an index file in debug mode within struct_log, simplifying the debugging process ie. only the config and the executable needs to be deployed for the debug build and you get a standard debug text logging.
- Logging Slabs Addition #24: The current unified logger works with big memory mapped files. Initially we thought we could rely on the mmap resize feature of the kernel api but it just doesn't work. We are reverting into building "slabs", ie dividing the data logger into large files. Those files can be concatenated and read or directly read from the log exporter.
- Compilation Feedback Adjustments #33: Moved compilation feedback from standard output to standard error to better align with conventional logging practices.
- Flush and Core Dump Fixes #29: Resolved issues where changes after a section flush could cause a core dump, improving the stability of the logging system.
- CI/CD Pipeline Enhancements #25: Added macOS support to the CI/CD pipeline, ensuring better cross-platform compatibility.
- Removed 'Continue on Error' in CI/CD #36: Addressed a CI/CD issue where the pipeline was green while failing Oo.
-
Unified Logger Refactor #27: Refactored the Unified Logger to introduce a dual-slab logging system, improving performance and eliminating the need for remap/resize operations.
-
Runtime Loop Enhancements #21: Added a new notion of loops in the runtime plan, setting the stage for more flexible and powerful runtime behavior.
If you're looking to build your own interfacing with the SN754410 or ADS7883 drivers, we share detailed connectivity schematics with a Raspberry Pi to help you get started.
We recommend updating to this latest version to take advantage of these improvements. As always, please refer to the updated documentation and release notes for detailed information on how to integrate these changes into your projects.
If you have any questions or need further assistance, feel free to reach out to our support team.