In this chapter of the Zero to Maker workshop, we'll be getting different microcontrollers and computers to talk to each other, learning why that's useful for your projects, and looking at some easy ways to do it wired and wirelessly. If you're new to this workshop, we'll be taking you on a fast-paced and practical journey to learn a wide variety of maker skills so that you have the tools and knowledge to make anything. So follow along as we develop our own projects and share insights into the process. So let's start with the motivation. Why would we want multiple boards talking to each other? Well, it gives us freedom in our projects. Let's take a look at some examples why.
My project is Leo, an indoor omnidirectional robot, and at the centre of it all is a Raspberry Pi 4, which is a small computer. Now that board wouldn't be a good fit to control all the motors, and it doesn't have enough pins to do that. It literally doesn't have enough resources to do what I want. So how about I get a Pico and dedicate that to the task of controlling the motors, because it's really good at doing that. And then I can just get the boards to work together. On top of that, I also needed to control some servos, and let's say hypothetically my code on that Pico controlling the motors is really terrible and wasn't able to also control the servos, why don't I just get another Pico and make it control the servos and then connect it together and get all of that working together. So when you know you have the ability to get all your boards working together, you have the design freedom to dedicate and divvy up tasks like this.
For my project, Plant Pulse, which is an automated plant monitoring and watering system, right there you can see the need for two boards, one inside dedicated to handling and processing that data and relaying that data to the internet, and another dedicated to collecting sensor data. On top of this, the outside board will have limited access to power, so I now have the design freedom to set up that system to be extremely power efficient. We can spend all day going over examples of our previous projects where having multiple boards working together is a really big bonus, but at the end of the day, it's a maker's skill that gives you freedom in your system design. So now that we want multiple boards to work together, how can we do it? Well, we're going to need something called a communication protocol, which is just an agreed set of rules that boards use to communicate with. It's useless if one board is speaking French, another English, and yet another is using sign language.
Let's start with the simplest and most common, UART, or Universal Asynchronous Receiver Transmitter. Yeah, transmitter? Yeah. So I'm using UART in my project to connect all of my boards together. It uses only two wires, one to send data on and another to receive on, and technically a third because they have to share a common ground. So why do they use data here? Well, first of all, it's extremely common, but the most important reason is that it's very easy to code yourself from scratch, especially in MicroPython. So in my project, I'm using UART to get my Pi and my Pico to work together as one system. So first of all, we need to connect the boards together, and we're going to need two wires. Tx and Rx, and there's a lot going on here, but long story short, this wire comes from the Pico, and I've got my Tx and my Rx here, but I also have a third pin, and this is the ground coming from the Pico because both boards need to share a common ground.
And on the back of this screen, I've got my Raspberry Pi, and all I need to do is plug Tx into Rx and Rx into Tx, like so, of the Raspberry Pi, and also make sure they share a common ground, like so. That's all ready to go. So I've taken the code from the Pico and the Pi here on the right, and I've just stripped it down to just the UART communication parts. And this code might differ from board to board slightly, as you can see there's a bit of a difference between the Pi and the Pico, but generally it's pretty straightforward and follows roughly the same structure. Both the boards start by importing the libraries needed, UART for the Pico and Serial for the Pi, and then we set up our instance of UART, and we tell it what pins we're actually using to make these connections, and then on the Pi, all we're going to do is we're going to say .write, and then whatever message we want there.
Now that little B there is something specifically for the Pi, and you don't need it if you were sending it on the Pico, it's just the slight differences that you may encounter. And then we're just going to go to sleep, print a slightly different message, and go to sleep and just keep doing that. And then on the Pico, all we're going to say is, if there's anything coming through UART, we'll store it in a message and print it out. And if I go ahead and run that code on the Pico, and then run that code on the Pi, you can see that our UART messages are being sent through just this wire here, which is really darn cool. And just to see this all put together and in action, I've got the full code for the Pi here, and it's got the exact same elements in it. We import the library we need, we set up the UART peripheral, and then here we say, if the W key is pressed, call the send command, and then in the send command, we use .write to send UART messages with the RPMs and the speeds that we want for the modus.
And the same deal on this Pico code. It's really long, but most of that is for dealing with the modus. All we do is we import the library we need, we set up our UART peripheral, and then down here in our while true loop, all we're doing is message, if there is a UART message, we'll check it and set the modus speeds based on that. And here's that whole system in action. The Pi 4 detects keyboard inputs, sends a command via UART to the Pico, the Pico reads that and sets the modus accordingly. And both of these boards are behaving and working together as one big system. And if you want to learn how to use UART, we have an entire guide for the Pico linked on the course page, but there's also lots of other wired com protocols. You might've heard of SPI or I2C, and these are often used to connect sensors and other modules to your boards, and I actually use I2C to do just that with a three-axis accelerometer. But I didn't write the program myself, I used a library, which is a pre-written bit of code because writing it myself would have been a bit of a challenge, which is why UART is so great. It's just easy.
And you might've also heard of CAN bus, which is used in a lot of things like vehicles. And chances are your windscreen wipers in your car are controlled by a CAN bus, and it may be another alternative to UART. I've used CAN bus once or twice before, but unless the project calls for it, UART is usually good enough and a lot easier to implement. But what if we don't want all of those messy wires? Well, there's lots of ways that we can connect devices wirelessly, and one tried and trued method is to add dedicated wireless hardware. This is kind of like connecting a long invisible wire between your boards, and there are lots of methods and protocols that we can use. And as always, we have some links on the workshop page to get you started with these. First up, Bluetooth is an option. It's the same technology used for your wireless headphones and mouse. It may not be the best choice, as there are more reliable and streamlined technologies out there, but it's definitely worth something keeping in mind.
If all you're after is an easy-to-use and accessible way to start some wireless communications, the PiicoDev Transceiver makes things really easy. It can be added to any MicroPython board and has a range of up to 100 meters, and it just allows you to send data between two boards. LoRa, or long-range radio, is also worth a mention. It's low-power and can send small amounts of information over a long distance, about one to 20 kilometers, and with professional hardware, you can send that hundreds of kilometers. And there are a few ways to set up LoRa. You can through direct peer-to-peer with one device talking to another, or we can build a mesh community of devices with something like MeshTastic, and a step further is connecting it to the internet with something called LoRaWAN. And you can also directly add an internet connection to our device using a cellular connection. Think 4G, 5G, LTE, just like your phone. This might be a good option for very remote devices that need to send a lot of data like video streams or files, but this setup can be a bit more complex and going over the internet presents security risks.
So we can add hardware, but many microcontrollers nowadays come with wireless capabilities inbuilt. Microcontrollers like the PicoW here can host a simple webpage over its own Wi-Fi network without having any additional hardware. We actually used this on our mid-semester project for Fab Academy, which was an Esky on wheels, and the Pico served a webpage with sliders and buttons on it that we could use to control the robot with. This method is often better for connecting your phone or computer to a microcontroller. It's a little harder and inefficient to connect a Pico to another Pico using webpages. If you want to use Wi-Fi to connect boards together though, MQTT might be your friend, but it needs an existing wireless network and a broker to manage the flow of data. There are free online brokers like Adafruit.io, or you can host your own on a computer or a Raspberry Pi. Shout out Home Assistant.
So for my project, I had a lot of wireless options, but for Plant Pulse, I didn't use any of these. ESP32 boards can use something called ESPNow, which allows you to connect two boards together using their wireless capabilities, and it doesn't require any additional hardware like Bluetooth, LoRa, or 4G. It's a stripped-back and streamlined protocol, unlike serving a webpage over Wi-Fi, and it's all offline. It doesn't need an existing network like MQTT does. Plus, we get the bonus of using less power thanks to all of the above. ESPNow sounds great, but let's use it. I've got my transmitter or node here, and I've got my receiver or hub. So let's take a look at the code. An ESPNow is a lot like UART. There's not too much we have to do before we're able to communicate. So again, we import all of the modules that we need. We set up our wireless communications here and started ESPNow, and we don't know where we need to transmit to. So we set our receiver's MAC address as a peer, and then we're able to send information after just nine lines of code. That's pretty good.
On the receiving end, it's pretty much the same. We import everything that we need. We set up our communications just like before, and we're listening for all messages. So we don't need to set up a peer. From there, we just listen. When we finally get one, we'll print it out in the shell below. Let's run them and see the boards talk to each other. We'll start our receiver first, followed by our transmitter. And all those messages have come across. We've got starting first, followed by all of our numbers, and then the end message. And this is ESPNow implemented in my final project. It uses the same structure as our examples before, but I've wrapped it up nicely in their own little libraries, and it's passing through those sensor values. Well, we hope that gave you some insights and solutions for getting two boards communicating with each other, either wired or wirelessly. And again, we'll have links to guides and resources on how to set all of those up if you're interested. Happy making.
Makers love reviews as much as you do, please follow this link to review the products you have purchased.