I grow tomatoes in my greenhouse in the summer. I have an irrigation timer for the tomatoes but setting the right amount of water is a bit of a guessing game and doesn't take the weather into account. And if we're not at home then there's nobody to monitor and tweak the water supply. But I like tinkering with technology, especially a mix of software and hardware, so making this smarter is my project for the first part of this year. I'll use moisture and temperature sensors, a solenoid-actuated water valve and a Raspberry Pi to drive it all. I never like to do things the easy way however; building something has to involve technologies I'm not familiar with, so I've decided to write the control software in Rust.
My first challenge is powering the whole thing. There's no electricity supply in my greenhouse so it needs to run on battery. Luckily there's a 45Ah lead-acid battery from an old car lying in my garage doing nothing and the Raspberry Pi model B, which is what I'll be using, needs up to 1W to run so that's a theoretical maximum run time of over 400 hours. I really want it to run all summer though so I bought a 10W solar panel, which comes with a controller to which you wire the panel, the battery and the load and it takes care of the rest. This will supply enough energy on its own to run continually, even in a typically cloudy Scottish summer. The battery will just provide storage for hours of darkness.
It still being winter here I decided to tackle the software prerequisites this week. If I want to write code in Rust I needed a cross-compiler targeting the BCM2835 processor, which has an ARMv6 instruction set with hardware floating point. In the language of GCC toolchains this is known as
arm-unknown-linux-gnueabihf. I used to write embedded code for a living, so cross-compiling toolchains are nothing new to me, but what struck me is how easy it has become in the past decade.
With rustup installed, adding the target is as simple as
rustup target add arm-unknown-linux-gnueabihf
You also need a compatible GCC toolchain (
binutils mainly) for linking. My development laptop is running Arch Linux, and the toolchain I need is available in the AUR repository at version 8.2.1 of GCC, so this was a matter of
yaourt -S arm-linux-gnueabihf-gcc
After a few steps of aborting on unknown GPG keys, and adding these keys with
gpg --recv-keys <key-id>
then the toolchain was installed. There's one final step to associate the Rust target with the GCC toolchain. Create or edit
~/.cargo/config and add
[target.arm-unknown-linux-gnueabihf] linker = "arm-linux-gnueabihf-gcc-8.2.1"
To test it I used
cargo to create a new hello world project and compiled it with
cargo build --target arm-unknown-linux-gnueabihf
Then after copying the resulting binary to the Raspberry Pi I tried running it. It printed "Hello World!" on the terminal!
I'm still learning Rust however, so I thought I'd try the guessing game tutorial in chapter 2 of The Rust Programming Language book. When I copied this to the Raspberry Pi and ran it, there was a dynamic linking error about an unsupported version of GLIBC. Oh no! I'm building on Arch and running on Raspbian, which is derived from Debian. I'm going to hit all sorts of library version problems, aren't I? So I decided to keep things consistent by installing Arch on the Raspberry Pi too. One of the things I really like about Arch Linux is the wiki, which is an amazing resource for all kinds of information and instructions. A quick search there revealed that of course there is an Arch Linux on ARM project, which provided the package download and installation instructions.
After rebooting the Raspberry Pi with its new installation, and a few final setup steps, I copied the guessing game binary over a second time and tried it. It works!
- I can manually bring up wifi on the Raspberry Pi (with the official USB wifi adapter) but I've not managed to get it to start on boot yet. I hope to add a camera and also produce some nice graphs of data over time, so wifi will be needed.
- Investigate accessing the Raspberry Pi GPIO from Rust.
- Get the moisture sensors working
- Get the external temperature/humidity/barometric pressure sensor working
- Build a relay circuit to activate the solenoid water valve and get that working
- Start thinking about a program design