Wirelessly Controlling the Pico ARP with the Mini Controller for Pico

Overview

In this blog we are going to look at how to wirelessly control the Kitronik Autonomous Robotics Platform for Pico with the Kitronik Mini Controller for Pico. We will use two Raspberry Pi Pico W's, one in the ARP buggy and the other in the Mini Controller.

The library and example code which we look through, can be found on our GitHub repo.

How It Works

As we are using two Pico Ws we can communicate wirelessly between the two. One of the Pico Ws will set itself up as the server which can be connected to. The other Pico W will be the client and connect to the server. Once connected, the two Pico Ws will be able to send and receive messages between them.

Kitronik Mini Controller and ARP with Pico Ws

 

This allows us to setup one Pico W with the Mini Controller as the client, which sends commands to the other when we press the buttons. The other Pico W we'll setup with the ARP buggy as the server, which will receive commands from the other and move the buggy.

Mini Controller for Pico Code

Kitronik Mini Controller with Pico W

 

 

Import Libraries

Before we start using the Mini Controller we first need to import some libraries that we are going to need. We'll use the KitronikPicoWClient class from the PicoWNetworking library to handle our wireless connection with the ARP buggy. We'll use the secrets dictionary from the secrets library to store the SSID and password for our wireless connection. We'll use the KitronikMiniControllerPico class from the KitronikMiniControllerPico library to help us access the components on our Mini Controller.

from PicoWNetworking import KitronikPicoWClient
from secrets import secrets
from KitronikMiniControllerPico import *

Setup the Mini Controller for Pico

With the libraries imported, we can setup our Mini Controller. We'll initialise our Mini Controller using the KitronikMiniControllerPico class and store this object in the controller variable.

# Setup Mini Controller for Pico
controller = KitronikMiniControllerPico()

Let's also create some flag variables that will help us keep track of when our buttons are being held down. We will call these flags upClicked, for example, to store when the Up button is being pressed. We can set them all to be False to start off with as our buttons aren't being pressed yet.

# Create flags for button presses
# Want to send the command once, when the button is initially pressed
upClicked = False

Setup the Wireless Connection

We'll setup our wireless connection using the PicoWNetworking library to help us. We are going to set the Mini Controller as the client meaning it will connect to the ARP buggy. To do this we want to initialise an object called client using the KitronikPicoWClient class. We'll pass the server's SSID and password from the secrets dictionary as the two inputs for the client constructor. This will tell the client class which device we want to connect to.
# Setup network connection with Pico ARP
# Client - Connect to soft AP setup by the server
client = KitronikPicoWClient(secrets["ssid"], secrets["password"])

Next we need to wait until we have connected to the server. We can wait for the connection to be made using a while loop which checks the status of our wireless connection. The loop will continue to repeat while the client has not established a connection with the server.

# While not connected, waiting for connection
while not client.isWifiConnected():
    pass

Now we have the client wirelessly connected to the server we need to setup a way to communicate with the server. We want to surround the next section of code in a try catch block. Inside the try block the Pico W will try and run the code. If any errors occur when running this code, then we will catch those errors and handle them in a suitable way. For our code, we could have an error while communicating with the server. If this happens, we want to close the connection with the server.

Inside of the try block, let's start by opening a communication channel with the server using the connectToServer function on the client. After our client has connected let's turn the onboard LED on to show we have full wireless communication available. At the end of the try block, we'll want to disconnect from the server to close the wireless communication.

try:
    # Connect to the server to open a communication channel
    client.connectToServer()
    # Turn LED on to show its connected
    led.on()

    # The rest of our code will go here

    # Close connection
    client.disconnect()
except Exception as e:
    # Error occurred, close connection
    client.disconnect()

Communicate with the ARP Buggy

For our communication with the ARP buggy we are going to put this inside of an infinite loop. This means our loop will continue repeating forever. We can use a while loop with the condition set to True to make an infinite loop. At the start of our loop we want to create the message variable and set it to be an empty string.

    # Loop forever
    while True:
        # Clear message
        message = ""

Next we are going to detect button presses on our Mini Controller. We'll add these inside of the infinite loop to continuously check when a button is being pressed. An example of this is our Up button. We'll check when the Up button is being pressed using an if statement and using the Up.pressed() function as the condition. Then when the Up button on our Mini Controller is being pressed down, the code inside of the if statement will execute.

Inisde our if statement we are going to check that the upClicked flag has not been set, or is False. When the upClicked flag is True we know that we have already detected the current button press. This allows us to only send the command to the ARP buggy a single time each button is pressed, and stops us from overloading the wireless connection with commands.

When we know this button press has not been detected yet, we want to set the up flag to True and set the message variable to have the Forward command to move the ARP buggy forward.

        if controller.Up.pressed():
            # When Up pressed and up flag isn't set
            if not upClicked:
                # Set the up flag and send Forward command
                upClicked = True
                message = "Forward"

At the end of the button detection if statements, we want to have an else statement. This will allow us to reset our button flags and send the Stop command to stop the ARP buggy moving around. Inside of the else statement we need to check when the upClicked flag is True. When it is, we are going to set the upClicked flag to False and set the message variable to have the Stop command.

        else:
            # Clear any button flags and send Stop command
            if upClicked:
                upClicked = False
                message = "Stop"

So far we haven't sent any commands to our ARP buggy. We'll add this to the end of our infinite loop and start by checking whether the message variable is empty. This if statement checks when the message variable is not empty, and means that we have a command stored inside of message.

When we have a command to send, we can use the client function called sendToServer which takes a single input for the message we want to send to the server. As we want to send our command, we'll use the message variable as the input for the function to tell the ARP buggy what to do.

        # When we have a command in message
        if message != "":
            # Send command to server
            client.sendToServer(message)

Pico Autonomous Robotics Platform Code

Kitronik ARP with Pico W

 

Import Libraries

Before we start using the ARP buggy we first need to import some libraries that we are going to need. We'll use the KitronikPicoRobotBuggy class from the PicoAutonomousRobotics library to help us access the components on our ARP buggy. We'll use the KitronikPicoWServer class from the PicoWNetworking library to handle our wireless connection with the Mini Controller. We'll use the secrets dictionary from the secrets library to store the SSID and password for our wireless connection.

from PicoAutonomousRobotics import KitronikPicoRobotBuggy
from PicoWNetworking import KitronikPicoWServer
from secrets import secrets

Setup the Autonomous Robotics Platform Buggy

With the libraries imported, we can setup our ARP buggy. We'll initialise our ARP buggy using the KitronikPicoRobotBuggy class and store this object in the buggy variable.

# Setup Pico Autonomous Robotics Platform Buggy
buggy = KitronikPicoRobotBuggy()

Let's also create a speed variable to store current speed of our buggy. We'll set this to 50% to start off with.

# Set the buggy speed to 50%
speed = 50

Setup the Wireless Connection

We'll setup our wireless connection using the PicoWNetworking library to help us. We are going to set the ARP buggy as the server meaning it will receive the connection from the Mini Controller. To do this we want to initialise an object called server using the KitronikPicoWServer class. We'll pass the SSID and password from the secrets dictionary as the two inputs for the server constructor. This will start the server using the SSID and password provided, allows devices to connect to it using those values.
# Setup network connection with Mini Controller for Pico
# Server - Start soft AP for client to connect to
server = KitronikPicoWServer(secrets["ssid"], secrets["password"])

Next we need to wait until the server has set itself up, and is available for devices to connect to. We can wait for it to turn on using a while loop which checks the status of our wireless connection. The loop will continue to repeat while the server is not fully setup.

# While not turned on, waiting for access point
while server.isAPConnected() == False:
    pass

Now the server is available for wireless connections we want to listen for the client to open a communication channel. This will allow the client and server to send messages to each other. We want to surround the next section of code in a try catch block. Inside the try block the Pico W will try and run the code. If any errors occur when running this code, then we will catch those errors and handle them in a suitable way. For our code, we could have an error while communicating with the client. If this happens we want to close the connection with the client.

Inside of the try block, let's start by listening for the client to open a communication channel using the listenForClient function on the server. After our server has opened a communication channel let's turn the onboard LED on to show we have full wireless communication available. At the end of the try block, we'll want to disconnect from the client to close the wireless communication.

try:
    # Listen for the client to open a communication channel
    server.listenForClient()
    # Turn LED on to show its connected
    led.on()

    # The rest of our code will go here

    # Close connection
    server.disconnect()
except Exception as e:
    # Error occurred, close connection
    server.disconnect()

Communicate with the Mini Controller

For our communication with the Mini Controller we are going to put this inside of an infinite loop. This means our loop will continue repeating forever. We can use a while loop with the condition set to True to make an infinite loop. At the start of our loop we want to create the message variable and set it to be an empty string.

After this we want to receive the command from our Mini Controller. We will receive a message from the client by using the server function called receiveFromClient. This function returns the string message that has been received by the server and we'll store this in the message variable. The message variable will store the command we have been sent by the Mini Controller.

    # Loop forever
    while True:
        # Clear message
        message = ""
        # Receive command from client
        message = server.receiveFromClient()

Next we are going to check which command we have received in the message variable. To do this we'll use if statements to test the contents of message against our known commands. The first one will be the Forward command and checking when message is equal to it.

When we have received the Forward command in message we simply want to turn both motors on going forward at our current speed.

        if message == "Forward":
            # When Forward command received, move buggy forward
            buggy.motorOn("l","f",speed)
            buggy.motorOn("r","f",speed)

At the end of checking for known commands we want to use an else statement which essentially acts as our Stop command. Inside the else statement we are going to turn off both motors on the buggy, to stop any movement.

        else:
            # When we don't receive an above command
            # Assume Stop command and turn off motors
            buggy.motorOff("l")
            buggy.motorOff("r")

Conclusion

In this blog we have learnt how to use the wireless networking on the Pico W's to control the ARP buggy using the Mini Controller. Now that we have seen how we can add the basic functionality, you can now customise this code to make your own fun projects using the ARP buggy and Mini Controller.

You can also check out the GitHub repo to see the full example code project.

Leave a comment

All comments are moderated before being published