1

My ultimate goal is to control a number of peripheral chips on a PCB from a GUI interface on a PC. To do so, my plan was to incorporate a RP2040 (and memory) on the PCB in order to hold all the python scripts and to program/monitor all the peripheral chips. Then, using a PC to interface with the RP2040, send commands over the serial port to execute specific python files on the pico. I realize that is a bit confusing, so the attached block diagram should help.


Block diagram

Starting on the left of the block diagram, I have a PC running a tkinter GUI. I am currently running the tkinter gui in Thonny. (eventually i would like it to be an executable, but that is beyond the scope of this post) The gui has a number of buttons to choose which python scripts to run. The PC is connected to the PCB through the USB cable. The USB data lines are routed to the RP2040's USB inputs (pins 47,48). The memory on the PCB holds a number of python scrips that correspond to the buttons in the GUI. Ideally, pressing a button on the PC would execute the corresponding py file on the pcb.


What I've got working so far: My real expertise lies in peripheral chips and PCB design, in this case the front end for a 2-18GHz transceiver, so bare with me if some of my python questions seem basic or misinformed. I've written and tested all the .py files on the pico's memory. To test those scripts I used Thonny to connect to my pico and simply ran (f5) the scripts with the peripherals connected to the right GPIOs. I was also able to get tkinter working and create functioning buttons that can execute commands. Using the pyserial module, I am also able to connected to the pico through the USB and write... strings. Not very useful, but a start.


import serial

ser = serial.Serial('COM3', 38400, timeout=1, parity=serial.PARITY_EVEN, rtscts=1)
s = ser.read(100)       # read up to one hundred bytes or as much is in the buffer

print(ser.name)                # check which port was really used
ser.write(b'ToggleLED.py')     # write a string
ser.close()                    # close port

Remaining task: The final task I have been failing miserably at the past 2 days has been actually trying to execute the .py files located on the pico's memory through the serial port. My unexperienced/naïve notion was to simply send a string with the files name, obviously not correct. Any thoughts on how to execute those py files using that pyserial module?


BTW, if there is a better solution, please feel free to share! Perhaps the files should be located on the PC and i send 1 command at time?

Jonas
  • 121,568
  • 97
  • 310
  • 388
SamiH
  • 11
  • 1
  • 2
  • What code are you running on the raspberry pi to respond to serial strings? Or are you interacting with a serial *terminal* on the raspberry pi? If you don't know, run `python -m serial.tools.miniterm --parity E --rtscts COM3 38400`, from a *command line*, which will open up a serial terminal with the same parameters. This should tell you if you end up in the terminal. – 2e0byo Sep 28 '21 at 16:11
  • What Python is on your RP2040? CircuitPython? MicroPython? Other? With CircuitPython, you could simply copy a new file to the Mass Storage class disk, and call it code.py, which CircuitPython will reboot and run when it sees it. If you don't want the "reboot" feature, you may want to monitor the serial port from a program on the RP2040. I don't recall if it supports subprocesses, but you could probably just `import` a file from the main file(which would require having all file names hardcoded in your main program) but that would be an approach. – RufusVS Sep 28 '21 at 16:54

2 Answers2

0

I can't say anything about your serial problems until you clarify just what is running on the pi (see my comment: I'll update this answer when you do), but re 'is there a better way': possibly.

Since the Pi is running a full operating system, there are a few options. You are basically creating a network connection to the Pi. Whilst this can be done over serial (with the Pi, presumably, acting as a fake USB serial device), it can also be done more conventionally over wifi or ethernet. Lastly, you could host your interface on the Pi and interact with it in a webbrowser, cutting the second computer out of the picture. Exactly which option you decide to take is up to you, and is really off topic here (though it might be on topic elsewhere on SE).

Sending commands to the pi and having it run scripts is Remote Procedure Call. You might want to lookup some of the protocols (like JSON-RPC) generally used to do that, but the basic approach will have code running on the pi:

def do_something():
    pass
def do_something_else():
    pass

functions = {"something": do_something, "something_else": do_something_else}

while True:
    cmd = get_input() # blocks until input comes
    if cmd in functions:
        reply(f"Running {cmd}")
        output = functions[cmd]()
        reply(f"{cmd} returned with output {output}")
    else:
        reply(f"Invalid command {cmd}")

This is schematic: exactly what get_input() on the pi is will depend on how you end up connecting, and what protocol (if any) you end up using. Notice that I have built in confirmation: you want to know if things work or fail.

Whilst you could store these commands in separate scripts and invoke them, if they are just python scripts there is no reason not to call the functions directly from the code running on the pi.

2e0byo
  • 5,305
  • 1
  • 6
  • 26
0

I've seen two different solutions to the question:

  1. With the Pi pico running the REPL (python shell), text strings can simply be sent from a python program running on the host (Windows or Raspberry Pi, etc., connected to the USB com port, with Thonny window closed), and sent to the pico as python commands. This approach is detailed in:

https://blog.rareschool.com/2021/01/controlling-raspberry-pi-pico-using.html

On the pico side, one just need to define a number of functions that will execute from the REPL. E.g.,:

from machine import Pin

# use onboard LED which is controlled by Pin 25
led = Pin(25, Pin.OUT)
# Turn the LED on
def on():
    led.value(1)
# Turn the LED off
def off():
    led.value(0)

Any string sent to the pico, such as

on()

will be executed accordingly.

  1. In the 2nd approach, the pico will read each line from the USB serial port and parse the line into command and additional parameters, to be compared against a list of predefined commands and executed accordingly. I did that using the Arduino Due, and I'm in the process of porting it to the pico (= no code to show yet :-().
Riceotter
  • 1
  • 1