This started as a Rust port of some robot firmware that I was writing, but ended up being better than the original firmware. Neat. The concept is to receive instructions from a serial link, drive the robot, and eventually include closed-loop control to maintain heading and speed across four bad motors and even worse encoders. Then I'll start working on some object detection.
After using the "four bad motors and even worse encoders" for too long, I completely rebuilt the chassis to not be a literal toy. It still looks like junk, just, more professional junk. The base unit is now a single sheet of plywood, instead of the layered acryllic sheets from before (pictures soon!). The reasoning for this was to make wire routing simpler, since I can now put all components on one flat plane instead of carving channels into layers of acrylic. The original chassis was based on a toy (The DFRobot Baron) which could realistically only mount the original plasticky motors. The new chassis uses "shopping cart dynamics" where it has two powered wheels in the rear, and two casters in the front. It is still a diff drive robot. The new chassis was also intended to be extremely cheap, and constructable out of parts that could be found at any hardware store, with the exception of the motors, which are much nicer. I will inevitably want to add more/better hardware, so cheap and cheerful is the way to go.
This system is intended to run on an STM32F4-Discovery
board. One of the newer ones with the 8MHz crystal oscillator. Other parts are:
- TB9051FTG Motor Driver x2
- Pololu 12V motor with 100:1 gearbox and 64 CPR encoder x2
- 70mm wheels x2
- wheel mount x2
- motor mount x2
TODO add other firmware-related devices here.
TODO also create an actual BOM in another repo in case anyone wants to replicate the entire robot
Comms are serialized in protobuf, (otomo-proto), using the prost crate. The reason I'm using protobuf and not something like postcard is due to the serial link being to a PC running ROS, so I wanted something that was more platform-independent, while also not being ROS-dependent
Message delimiting is accomplished using KISS-TNC. It is a simple protocol used to denote the start and end of messages, and uses a simple frame-escape method to handle when a value in the message is the same as the frame delimiter. See the kiss_encoding crate for details. The crate in this workspace is an ultra-simplified version of the KISS protocol to work for this project on an embedded system.
This firmware uses rtic to handle concurrency across interrupts. The USB isr will ingest the messages, then send them to a task where the motor driving will be done. A central heartbeat task takes all feedback from other tasks (encoders, IMU, IO, etc), then encodes and sends that info to the host device.
This firmware uses the otomo_hardware create (workspace) to move the hardware initialization outside of the init method in rtic. This was done to keep file size down, but eventually it should turn into a semi-HAL. I would prefer to keep the actual processing logic in the main otomo-rs crate, but the way rtic uses ISR's to create task dispatchers means that I will always have some hardware references in the main crate.
rtic 2.x has a crate called rtic-monotonics to support async timers within larger rtic applications. However, this is not done in a vendor-agnostic way, so there is a call in the main function to specifically initialise TIM2. This felt more reasonable rather than adding rtic-monotonics to otomo_hardware.
By default, the main crate uses defmt to log messages. However, there is a full implementation of the log crate, and the logging "agent" can be configured through cargo features.
- default:
defmt_logger
- serial:
serial_logger
(uses USART2, pins A2/A3)
- get HC05 up and running
- get communication running between phone and device
- get protobuf messaging working
- clean up init stuff <- lol that'll probably never gonna happen
- joystick to tank conversion
- read
crappymuch better encoders (use the QEI interface) - add PID library for speed control
- read from IMU to get heading
- heading-based input to control loop
- read from laser/ultrasonic/IR distance sensor
- log crate instead of defmt (configure through features)
- populate constants/thresholds at build time through config file
- just...better robot chassis hardware.
The user should install probe-rs
:
cargo install probe-rs --features cli
then run with:
cargo run -- --connect-under-reset
in one shell:
$ openocd -f interface/stlink-v2-1.cfg -f target/stm32f4x.cfg
And in another shell:
$ gdb-multiarch target/thumbv7em-none-eabihf/debug/otomo-rs -ex "target extended-remote localhost:3333"
$ ./flash.sh # -r for release build
For whatever reason the Saleae logic analyzers cause the stlink to be disconnected when plugged in. I have no idea why this is.