Hey all; I'm fairly new to Rust (seven months give or take; JavaScript is my daily driver) and I've been working on a custom-built, 3D-printed robot car https://github.com/botinaboxer/codercar
for the better part of the last year and a half.
Introduction
I've tried a lot of different avenues - NODE-RED, Python with MQTT and PiGPIO, Johnny-Five.js and Cylon.js, and a couple of others. Honestly I've had a blast learning how to interface with hardware using high-level languages, but, well...
It got to the point where (either for my lack of pre-planning, premature excitement, or whatever) I just couldn't take it - I needed a better way of coding everything up.
And so I turned to Rust, after a bit of soul searching and a lot of helpful advice. It's great, really. I love the ecosystem (Cargo, Rustup, rustc, crates - the whole shebang). And I'm finally getting somewhere with it.
Using the RPPAL library from golemparts, I was able to control the GPIO pins on my Raspberry Pi Zero W using Rust. That allowed me to use the attached L9110s motor controllers to get my CodeRcar moving. But I needed a front-end, since I didn't want to be using a CLI program for this, and I am more versed in front-end web development than in CLI/TUI interface development.
So I created codercar-controller, a Vue front-end application (built in Nuxt) with USB controller support. It is not finished, and I'm currently re-writing it using Quasar, but that's a discussion for another place.
Basically, it communicates with the Raspberry Pi Zero W via WebSockets, and I made codercar-rust as the back-end running on the Pi.
It uses tokio-tungstenite
at the moment for managing the websockets, and serde
to serialize and parse the JSON object representing the current status of a game controller plugged into the computer running the front-end (which incidentally, could be the Pi itself, but let's say I'm using my laptop).
And now to the present
So here's the deal. It works, and it works pretty well in my opinion. It can move forwards, backwards, left, and right, and the input lag is basically non-existent (at least for a little robot; I never noticed anywhere near this performance with NODE-RED and/or Python...)
However, now I'm looking to introduce an Arduino into the mix. Connected via USB to the Pi, the Arduino has an HC-SR04 ultrasonic distance sensor, a 8x8 LED matrix, and potentially other screens/sensors connected to it.
Maybe I'm barking up the wrong tree or unintentionally limiting myself here, but here's my dilemma.
I'd like to be able to have an async event loop running (probably ever 100 milliseconds, since I've tested that to be a good compromise between speed and freedom to do/wait for a bunch of robot stuff).
That loop should be able to do the following, based on my preliminary idea:
- Read incoming data from the Arduino (Nano) over USB
- That data would primarily be sensor data like from an ultrasonic sensor or maybe an accelerometer/gyroscope like an MPU6050
- Read incoming data from the front-end (via websockets; mostly game controller state)
- Make sense of the current situation
- Perform appropriate commands (send data back to the Arduino, move motors/toggle GPIO pins, etc.)
- Send data back to the front-end (like the sensor data so it can be graphed realtime - incidentally I'm still trying to figure that out, but that's a way easier problem to solve)
So, yeah...
Thing is, I really don't know how to code that all up in Rust. https://github.com/sdroege/async-tungstenite/blob/master/examples/interval-server.rs
is an example that looks promising if you know what I mean , using async-tungstenite (which is a bit different from tokio-tungstenite which I'm using right now, but not much so. I'd rather use the async variant personally).
I'd like to be able to use something like that for the event loop, then find libraries for stuff like serial communication (RPPAL might be useful for that though, since it has UART support). In theory it doesn't seem too difficult. In practice, I'm rather overwhelmed.
I haven't found a good solution to this problem, and I've been searching on-and-off for the better part of a year. Maybe I'm just not familiar enough with Rust, but I can't seem to wrap my mind around what I need to do here.
It's just, I'm kinda at an impass here. Maybe I should just use Python, but frankly I don't like it. JavaScript is too heavy for this type of thing, at least according to my tests. C is, well... C, and any other alternative is either Haskell (which I honestly wouldn't mind using for something, just not this) or something far worse. I really want Rust for this - it's the theoretically-perfect solution.
My Verdict
I think I'm on the right track here. I don't think I'm completely crazy, and I'll probably figure it out eventually. It's just going to take a lot more work, and that's fine by me. As much as I might seem (and am) frustrated by all this, I chose to take on this project, and I've had a ton of fun/learned a bunch in the process.
I just feel like I'm getting to a turning point here. I'm close; I can feel it.
Anyway, if you'd like more details about the CodeRcar project, want to talk about Rust/Raspberry Pis/Arduinos/robotics in general, that's cool.
If you have any tips or pointers, or want more information pursuant to what my actual problem is here, that's cool too.
Thanks for taking the time to read this post; hopefully it was helpful/informative/intriguing in some way, and I hope you have a great day or night or whatever.