Skip to content

Bus (Wired) address Communication

First, I watched this tutorial covering how to connect two Raspberry Pi Picos together and make them communicate with each other. One pico will send the message “hello” to the other Pico, which is trying to receive the message. I thought the tutorial was hard as I could not get the Picos to work even after hours of trying.

Wrong boards

At first, I decided to use a Raspberry Pi Pico board with a XIAO board by connecting the RX pin of the XIAO to the TX pin of the Pico board, and vice versa. The TX and RX pins represent the master and sub class on the UART communication tool. I also uploaded the code onto Thonny, which can be found here.

After talking with Mr. Dubick, my instructor, about failing to have a connection between the boards, he mentioned that I am trying to wire a Pico to a XIAO. However, in the video, the person was showing me how to connect 2 Picos. So, what I am doing does not match with the tutorial.

Therefore, I switched to 2 Xiao boards.

Xiao board trouble

Unfortunately, I did not have access to 2 separate Xiao seeed cables, so I resorted to connecting the power pins of the 2 boards together through a breadboard. I also installed MicroPython on both boards and connected to Thonny through different COM ports.

When doing this, I also couldn’t connect get 2 windows to open in Thonny. Then, Dylan Ferro told me that I have to uncheck the option for only allowing one instance of Thonny under the options tab:

Uncheck the options tab

However, it turned out that this only worked for Windows. So, I could not use my Mac for this tutorial. Now that I have 2 windows, I connected the shell in each window to a Xiao.

On Windows, the code still did not work, and Dylan explained that I have to save the easy_comms library to the computer itself. I did that, but all I got was the initialization of the code, and no actual indication of a reception of the message sent by Pico 1 to Pico 2:

Error

As seen in the picture, the program stops after outputting “ahoy”.

Analogy by Teddy Warner

Fab Academy alumni Teddy Warner examined my program and gave me an analogy comparing the 2 boards to 2 people having a conversation. The problem that I have right now is that one person is alone in a room, trying to listen to the other person in another room. Also, they are talking at different times, so it is impossible for them to hold a conversation at the same time.

Therefore, the solution is to run the 2 programs on both Xiaos at the same time. He mentioned that the timing has to be right.

Editing the code

Following Teddy’s explanation, I took a look at the Easy_comms library that the tutorial provided:

from machine import UART, Pin
from time import time_ns

class Easy_comms:

    uart_id = 0
    baud_rate = 9600
    timeout = 1000 # milliseconds

    def __init__(self, uart_id:int, baud_rate:int=None):
        self.uart_id = uart_id
        if baud_rate: self.baud_rate = baud_rate

        # set the baud rate
        self.uart = UART(self.uart_id,self.baud_rate)

        # Initialise the UART serial port
        self.uart.init()

    def send(self, message:str):
        print(f'sending message: {message}')
        message = message + '\n'
        self.uart.write(bytes(message,'utf-8'))

    def start(self):
        message = "ahoy\n"
        print(message)
        self.send(message)

    def read(self)->str:
        start_time = time_ns()
        current_time = start_time
        new_line = False
        message = ""
        while (not new_line) or (current_time <= (start_time + self.timeout)):
            if (self.uart.any() > 0):
                message = message + self.uart.read().decode('utf-8')
                if '\n' in message:
                    new_line = True
                    message = message.strip('\n')
                    # print(f'received message: {message}')
                    return message
            else:
                pass
                #print("No message recieved")

I noticed that in the first few lines, there was a timeout variable set to 1000 milliseconds or 1 second. I tried to change that time to 3000 so that there could be more time between the 2 boards to establish a connection.

However, that did not work at all.

Working UART Connection

Getting really frustrated, I went to Mr. Dubick again and asked for help. He suggested me to go through the tutorial and rewatch it carefully.

I did as told and carefully traced the code line by line. Then, I made some further modifications to the code, which could be found here.

But most importantly, I changed my wiring. Instead of using a breadboard, I connected the UART line like this:

W/o breadboard

Interestingly, I only connected one TX pin to the other xiao’s RX pin, instead of wiring the connection in both ways. However, when I uploaded the code, the connection was made:

Milling

You can find the milling procedure here.

Wireless

Next, it is time to conduct the wireless connection between 2 Pico Ws, in which I used this tutorial.

I connected 2 Raspberry Pi Pico Ws (the ones that support wireless communication) to my computer through different COM ports:

Working video

At first, I could not get both pico Ws to connect to their respective COM ports:

Failure to connect

I restarted Thonny and it worked, connecting one Pico W to Com 45 and the other to com 46. Learning from UART, I also made sure to do this in 2 separate windows.

Code

There are 3 parts to the code.

There is a secret.py file that contains the ssid and password of the wireless network, which in this case, is my personal hotspot.

There is a server.py:

# Webserver to send RGB data
# Tony Goodhew 5 July 2022
import network
import socket
import time
from machine import Pin, ADC
from secret import ssid,password
import random
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    time.sleep(1)

# Handle connection error
if wlan.status() != 3:
    raise RuntimeError('network connection failed')
else:
    print('connected')
    status = wlan.ifconfig()
    print( 'ip = ' + status[0] )

# Open socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]

s = socket.socket()
s.bind(addr)
s.listen(1)

print('listening on', addr)

# Listen for connections
while True:
    try:
        cl, addr = s.accept()
        print('client connected from', addr)
        request = cl.recv(1024)
        print(request)
        # Do not unpack request
        # We reply to any request the same way
        # Generate 3 values to send back
        r = random.randint(0,255)
        g = random.randint(0,255)
        b = random.randint(0,255)
        # Join to make a simple string with commas as separators
        rgb = str(r) + "," + str(g) + ","+str(b)

        response = rgb # This is what we send in reply

        cl.send(response)
        print("Sent:" + rgb)
        cl.close()

    except OSError as e:
        cl.close()
        print('connection closed')

There is also a client.py code block for the other Pico:

# Program to read RGB values from a local Pico Web Server
# Tony Goodhew 5th July 2022
# Connect to network
import network
import time
from secret import ssid, password
import socket

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while not wlan.isconnected() and wlan.status() >= 0:
    print("Waiting to connect:")
    time.sleep(1)

# Should be connected and have an IP address
wlan.status() # 3 == success
wlan.ifconfig()
print(wlan.ifconfig())

while True:
    ai = socket.getaddrinfo("172.20.10.7", 80) # Address of Web Server
    addr = ai[0][-1]

    # Create a socket and make a HTTP request
    s = socket.socket() # Open socket
    s.connect(addr)
    s.send(b"GET Data") # Send request
    ss=str(s.recv(512)) # Store reply
    # Print what we received
    print(ss)
    # Split into RGB components
    l = len(ss)
    ss = ss[2:l-1]     # Strip to essentials  
    p = ss.find(",")   # Find first comma
    r = int(ss[0:p])   # Extract RED value
    ss = ss[p+1:]      # Remove red part
    p = ss.find(",")   # Find comma separator
    g = int(ss[0:p])   # Extract GREEN value
    b = int(ss[p+1:])  # Extract BLUE value
    print(r,g,b)       # Print RGB values
    print()
    # Set RGB LED here
    s.close()          # Close socket
    time.sleep(0.2)    # wait

Installing packages

Next, I installed 2 libraries on the Pico boards. They are the pystone_lowmem package and the urequests package. These form the cornerstones of wireless communication used on the Picos.

Server.py

First, I ran

import pystone_lowmem
pystone_lowmem.main()

in the shell user interface. It worked and the speed of the Pico was shown:

IP address display

Then, I ran the server.py script and see if it could be connected to my phone’s hotspot. Apparently, it failed to connect.

Server failure

As seen, Thonny tells me that network is not a module. I searched the problem up on Google and one solution I came across was seeing if the .uf2 file was the right kind. This suddenly struck me as the right solution because I actually forgot to install the file for the Pico Ws, which is different than the package for the regular Pico.

The mistake I made was assuming that the package was already installed.

So, I decided to install the files and put the Picos into Bootloader mode so that the local devices showed up on the computer:

Local devices

After downloading the .uf2 file from the MicroPython documentation, I moved a copy into each of the devices (E and F).

I ran the server.py program again and it still failed:

Server failed to connect again

But I think it was because it takes a few seconds for the Pico to connect to my phone. After confirming that my hotspot established a connection,

Phone connected

I ran the server.py program again and it worked.

First board worked

The program displayed the IP address of the Pico.

Client.py

Moving on to client.py, I ran the other Pico’s program and waited for a connection to form.

This particular connection will send random RGB values from one Pico to the other, which outputs the transmitted RGB values.

At first, client.py failed:

Client failed

But as it was with the server.py, it takes a second for the connection to form. This was the finished product:

As you can see, the program works flawlessly.


Last update: January 15, 2024