Week 10: Networking and Communications


Next I’m going to work out the communication between the different microcontrollers. For this I’m going to use the same boards that I used in input and output device assignments. The Time of Flight board (XIAO 0) sends data to two identical boards controlling servo motors: distance from 0 to 10cm controls XIAO 1 from 0 to 180 degrees and distance from 10 to 20cm controls XIAO 2 from 0 to 180 degrees.

The first thing is to set up a serial connection between the sensor board and the XIAO 1. To figure out how to do that I googled “circuitpython how to establish UART connection” and ended up in CircuitPython Essentials by Adafruit. From there I found out about busio library and looked for its documentation. The main functions ares shown below.

I began with the example code for reading the messages and pasted it to XIAO 1. I commented the servo code away for now.

In addition, Claude (by Kris) gave an example code for sending messages with write-function and that I pasted to the XIAO 0. For both, I added code for blinking the LED to make visible the connection when established.

Then I tested the program by powering up the ToF board with my phone charger and the servo board from the computer. The messages were sent but were somewhat unstable and cryptic.

Kris came to check and mentioned about the baud rate and when checking on that I realized that I hadn’t defined timeout for XIAO 1. I checked the busio documentation and timeout is 1 by default. So I set that to 0.1 to match XIAO 0 but it didn’t solve the messaging (or only slightly?).

Next I started checking on the code as they were copy-pasted from different sources, and the conversion from bytes to strings might cause the issue. I didn’t really understand the write-function and the message formatting ( uart.write(b”Hello/r/n”) ) to begin with. I added print(data) in the XIAO 1 code to view the message as it comes.

I understand this so that when the message comes as it is send, as b"Hello\r\n", the receiving code end is able to parse it correctly. But when the data is printed as longer line of symbols, the output message becomes cryptic. So the problem might not be in parsing data into string.


As I came back to this after the weekend and connected the XIAOs and got the connection established, the messaging suddenly work as supposed to so I don't know what was issue about.

Then I moved on to try to make the servo run based on the message. I couldn't get the code to understand the message with if statement 'if data_string == "Hello":'. With print(type(data_string)) I get info that it's a class that is a string.

I asked Gemini to explain me the write-function of busio library, because I didn't understand the formatting of the given code: what are "b", "/r" and "/n"? So basically b translates the string into a byte format and /r moves cursor back to left and /n begins a new line in the text (this one I actually knew).

So basically what is written inside the parenthesis is the message being sent, but it needs to be converted to byte-type, and there was nothing extra regarding the messaging protocol or such: they were only formatting the message.

Instead of figuring out the class/string type (which would've probably been solved by 'if data_string[0] == "Hello":'), I thought I could anyway update the XIAO 1 code to send 0 or 1 instead of "Hello". However, Gemini suggested to use string type as it's easier to debug apparently. Well, I went on with int-types anyway and asked how to send and receive it. To make number 1 into bytes I used uart.write(bytes([1])) and for data = uart.read(1) and number = data[0].

After a while of debugging (which was solved by having the mentioned lines in place) I was able to make the servo run 180 degrees based on the message (1 or 0) and turning back every second.

XIAO 0 (ToF/sending) code:

XIAO 1 (servo/receiving) code:

Then I moved on to include ToF to message sending. I went back to the Adafruit's sample code and copy-pasted that (excluding all the unnecessary print commands as shown below).

Then I began integrating it to the previous code used with messaging. I wanted to make it so that 18cm distance is 0 degrees and the servo moves 10 degrees on every cm that my hand moves closer. Here I converted the distance to string when sending it and converted back to int when receiving.

XIAO 0:

XIAO 1:

Now the XIAO 0 sends the distance in centimeters, which converts in the XIAO 1 code to int with the same code. Multiplying that by 10 and setting it as angle makes the servo move based on the proximity of my hand.

There was a "ValueError: Angle out of range" when my hand was too far so I added some limits to the angle given to the servo: it needs to be larger than 0 and smaller than 180

The servo is quite jumpy because it receives the angle in tenths, so I went back to send floating numbers as strings. I added "/n" to it so that readline method can be used in opening the messages.

XIAO 0

First this code gave TypeError: string argument without an encoding, but when I added "utf-8" along with the write-function, as given in an example by Gemini, the error disappeared. Then I used, as in Gemini's example, float(data.decode().strip()) to convert the byte type to floating number.

XIAO 0

XIAO 1

Now it moves a bit smoother as the angle is given in one degree accuracy.

Being ready to connect the second servo board and send messages over three boards, I can't do it as easily, because I lost all my electronics due to a stupid mistake (left the box on top of my car when I drove away). Now I'm in a decision should I start this experiment from the start to be able to document the last couple of hours of work, or continue with the next thing, i.e, my final project which has also networking (bluetooth) element to it.

I decided to go through how the communication would have been implemented if I still had my components at hand, and then document later how I implement a bluetooth connection with my final project.