4 releases (breaking)
0.4.0 | Apr 20, 2023 |
---|---|
0.3.0 | Apr 19, 2023 |
0.2.0 | Apr 8, 2023 |
0.1.0 | Apr 8, 2023 |
#170 in Robotics
25 downloads per month
2MB
20K
SLoC
Contains (static library, 1MB) lib/librobotcontrol.a, (ELF exe/lib, 37KB) am335x-pru0-rc-encoder-fw, (ELF exe/lib, 36KB) am335x-pru1-rc-servo-fw
librobotcontrol-sys
A low-level library for robotics-related functionality on BeagleBone boards. You'll likely want to wrap whatever subset of functionality you're using in more idiomatic/safer rust.
See the rust API docs for the latest release here. See also the librobotcontrol
API docs and examples. Things are largely the same. Where you would call, e.g.
rc_button_init(...)
in C/C++, you'd call
unsafe { librobotcontrol_sys::rc_button_init(...) }
in rust.
Example
For an example, see examples/heading.rs
. This can be cross-compiled and deployed by connecting your BeagleBone and running:
# Add the target for cross-compilation
rustup target add armv7-unknown-linux-musleabihf
# Build, deploy & run on BeagleBone
make deploy-heading-example
Implementation details
Figuring all of this out was a huge pain in the ass. When researching, it seemed that others had suffered through similar challenges, so maybe expounding on a subset of the details will be helpful to others. People who just want to use the damn library don't need to know all these gory details.
Unlike the default setup for librobotcontrol
, this uses musl rather than glibc, which allows for a straight-forward cross-compilation story. But doing this is kind of tricky. Using librobotcontrol
's build setup would require extensive modification, and impose some very specific and difficult-to-setup toolchains on the host system. Creating a custom build setup using the cc
crate would prevent the former, but still suffer from the latter. After several days of trying to pull off a solution with either strategy, I gave up -- if only out of concern that, even if I figured it out, it would not be at all portable.
To avoid the above issues, we build librobotcontrol
on alpine via docker BuildKit. But newer versions of alpine use musl 1.2.x, which has 64-bit time on 32-bit machines, whereas musl 1.1.x which is statically linked by the libc crate uses 32-bit time on 32-bit machines, causing linking errors. There is a compatibility shim to address this specific issue, but it seemed easier and safer to just an older version of alpine that had musl 1.1.x. Assuming you have docker BuildKit and the appropriate VM setup (a big assumption!), regenerating the library is as simple as make lib/librobotcontrol.a
. You don't have to do this normally because the library is included.
We also want to build the bindgen bindings ahead of time, since doing so requires the library to be installed which is unlikely to be the case on the host machine. However, the older version of alpine does not have an apk
package for rust, and rustup doesn't offer a way to install for armv7-unknown-linux-musleabihf
-- which is sort of surprising since we can cross-compile rust code for it fine. So to build the bindings, there's a separate alpine container using a newer version that has an apk
package for rust.
That version of alpine also has a package for rustfmt
, but for some reason using it in tandem with bindgen-cli
causes the latter to never finish. So we just format the code on the host machine, after it's been copied out of the container. Rebuilding these bindings should be as simple as make src/bindings.rs
. But again, you don't have to do this normally since the bindings are checked in.
Most of the things exported by librobotcontrol
are not included in bindings.rs
, because it re-exports all sorts of stuff for which there is an equivalent rust variant that's safer, e.g. libm functions. I might've been over-zealous about filtering though, so feel free to open a PR to include a missing item that you need.
An earlier version of this library used c2rust to convert librobotcontrol
to rust, rather than trying all the shenanigans above. But I was worried about bugs from imperfect translation. And much to my horror, a bunch of stuff #include
'd -- even libc types -- were translated per module. So there was e.g. a copy of the FILE
type in every module, and they weren't compatible with one another as far as rust was concerned. Earlier versions of c2rust prevented this issue via its support for "refactorings", but that was removed in more recent versions to more easily modernize it for newer versions of rust, LLVM, etc. I tried manually refactoring, but that would've given me carpal tunnel.