pythonpyserialraspberry-pi-pico

Call a function on Raspberry Pi Pico from PC using pyserial


I have a small python file in Raspberry Pi Pico that can control servos via PCA9685 servo controller:

import time
from adafruit_servokit import ServoKit
import busio
import board
import time
kit = ServoKit(channels=16, i2c=(busio.I2C(board.GP1, board.GP0)))

def rotateservo():
    kit.servo[0].angle = 100
    time.sleep(1)
    kit.servo[0].angle = 0
    time.sleep(1)
    kit.servo[0].angle = 180

The function works fine when called from Pico. I am looking for a way to call the function from a PC using pyserial

import serial
ser = serial.Serial('COM5', 115200, timeout=timeout)
ser.write('rotateservo()'.encode())
ser.close()

This simply outputs the number 13 which I assume is the length of the string. How do I call a function on Pi Pico using pyserial?


Solution

  • Here is a way to do this. I have this running on a Pico W:

    import select
    import sys
    from machine import Pin
    import utime
    
    gpio_no = 'LED'
    led = Pin(gpio_no, Pin.OUT)
    
    # setup poll to read USB port
    poll_object = select.poll()
    poll_object.register(sys.stdin,1)
    
    def blink(length):
        led.value(1)
        utime.sleep(length)
        led.value(0)
        utime.sleep(0.2)
        
    def function_1():
        print("Executing function 1")
        blink(0.2)
    
    def function_2():
        print("Executing function 2")
        blink(0.2)
        blink(0.2)
    
    blink(1)
    print("Started looking")
    while True:
        # check usb input
        if poll_object.poll(0):
            #read as character
            ch = sys.stdin.read(1)
            if ch == "1":
                function_1()
            elif ch == "2":
                function_2()
            else:   
                print (ch, "Received. Was expecting 1 or 2")
                blink(1)
    

    If it receives a '1' it executes function_1, which briefly flashes the LED once and also sends a message back. If it receives a '2' it briefly flashes the LED twice and sends an other message back. For all other characters it does a longer (1 second) flash, and sends a different message.

    Here is the code to run in Python on a PC (replace COM7 with the port number you are using).

    import serial
    import time
    
    ser = serial.Serial('COM7', 9600, write_timeout=0)
    
    to_send = ['1', '2', '3']
    
    for a in to_send:
        bytes_sent = ser.write(bytes(a, 'UTF-8'))
        print(f"Sent {bytes_sent} bytes ({a})")
        line = ser.readline()
        print(f"Received: {line.decode('UTF-8') }")
        time.sleep(1)
    
    ser.close()
    
    print("done")
    

    It uses the pyserial module, and sends a '1', a '2' and a '3' at one second intervals. These are picked up by the Pico, which flashes in response, and sends text back to the PC confirming what it has received. This is the PC printout:

    Sent 1 bytes (1)
    Received: Executing function 1
    
    Sent 1 bytes (2)
    Received: Executing function 2
    
    Sent 1 bytes (3)
    Received: 3 Received. Was expecting 1 or 2
    
    done
    

    When setting this up you need to run the Pico program as main.py (running from the Pico). Once it is running you need to take Thonny off the serial port, or you will not be able to access it from the Python code. To do this, click on Thonny bottom-right, and set it to anything but the COM port you are using (for example 'Local Python').