Shop OBEX P1 Docs P2 Docs Learn Events
Servo control via radio + Raw REPL — Parallax Forums

Servo control via radio + Raw REPL

Using Raw REPL it is possible to to talk with your microbit over a serial interface, this demo uses that feature to control a servo motor from a PC with two microbits communicating over radio.

The GUI is built from python 3 on a Windows PC but will work on a Mac also. The GUI code looks fairly daunting but can be split into widget creation, serial interface control, initializing and exiting Raw REPL and the method that transmits the micro python code to the microbit. At the moment there is very little in the way of error trapping but it works well enough to show the example.

The method that sends the micropython code is "write_py_code" and takes any valid microbit instruction as a string, the demo controls a servo but can be modified to communicate and control many other devices.

The transmitter needs no programming the GUI takes care of it, the receiver has a 10 line program for basic control of the servo.

RECEIVER

from microbit import *
import radio
radio.on()


pin16.set_analog_period(20)

while True:
    incoming=radio.receive()   # 26 to 128
    if incoming != None:
        value=int(incoming)
        pin16.write_analog(value)
    incoming=None

GUI

from tkinter import *
from tkinter import ttk
from threading import *
import threading
import serial.tools.list_ports
import time
from tkinter import messagebox

root=Tk()
var1=StringVar()

count = 0

event = threading.Event()

root.title("Servo Control")

screen_width= root.winfo_screenwidth()
screen_height= root.winfo_screenheight()

root_width=500
root_height=485

root.resizable(False,False)

x_location=(screen_width/2) - (root_width/2)
y_location=(screen_height/2) - (root_height/2)

root.geometry(f"{root_width}x{root_height}+{int(x_location)}+{int(y_location)}")
root.configure(bg="light blue")

port_list=[]
ports = list(serial.tools.list_ports.comports())
baud_list=[9600,19200,38400,57600,115200,]

for p in ports:
    port_list.append(p.name)

ser = serial.Serial()

def port_open(my_port):

    my_port=my_port

    if not ser.isOpen():

        ser.port=my_port
        ser.baudrate=combobox2.get()

        ser.open()
        time.sleep(2)

        raw_repl()

def port_close():
    if ser.isOpen():
        ser.close()

def thread_start():
    t1=Thread(target=write_slider,daemon=True)
    t1.start()

def thread_break():
   event.set()
   exit_raw_repl()
   port_close()

def raw_repl():
    ser.timeout=0.5
    for i in range(3):
        ser.write(b"\r\x03")
        time.sleep(0.01)
    ser.write(b"\r\x01")
    input_string=ser.read(400)
    txt.insert(END,input_string)

    initialize_uBit()

def exit_raw_repl():
    ser.timeout=2
    ser.write(b"\r\x02")
    input_string=ser.read(400)
    txt.insert(END,input_string)

def initialize_uBit():
    write_py_code("from microbit import *")
    write_py_code("import radio")
    write_py_code("radio.on()")
    thread_start()

def write_py_code(py_code):
    ser.write(py_code.encode("utf-8"))
    ser.write(b"\x04")
    response=ser.read_until(b"\x04>")

def write_slider():
    new_val=0
    slide_1.set(77)

    while True:
        if event.is_set():
            break
        time.sleep(0.005)
        s1=slide_1.get()

        old_val=s1 

        if old_val != new_val:
            write_py_code(f"radio.send(str({s1}))")

        new_val=old_val

def clear():
    txt.delete("1.0",END)

def close_app():
    root.destroy()

def on_closing():

    if messagebox.askokcancel("Quit", "Are you sure you want to exit?"):

       close_app()

root.protocol("WM_DELETE_WINDOW", on_closing)


comms_frame=LabelFrame(root,text="Comms")
comms_frame.grid(row=0,column=0,padx=10,pady=5,sticky="w")

command_frame=LabelFrame(root,text="Commands")
command_frame.grid(row=0,column=1,sticky="nw",pady=5)

btn1 = Button(comms_frame, text='OpenPort',bg="light gray",command=lambda:port_open(ports_cmb.get()),width=15)
btn1.grid(row=0,column=0,pady=5,padx=5)                                 
btn2 = Button(comms_frame, text='ClosePort',bg="light gray",command=lambda:thread_break(),width=15)
btn2.grid(row=1,column=0,pady=5,padx=5)   
btn3 = Button(comms_frame, text='Clear',bg="light gray",command=lambda:clear(),width=15)
btn3.grid(row=0,column=2,pady=5,padx=5)   

slide_1 = Scale(root, from_= 28, to= 128,orient=HORIZONTAL,length=350)
slide_1.grid(row=3,column=0,columnspan=2)

txt=Text(root,width=60,height=15,relief="sunken",borderwidth=5)
txt.grid(row=2,column=0,columnspan=2,padx=5,pady=5)

ports_cmb = ttk.Combobox(comms_frame,values=port_list,width=6)
ports_cmb.grid(row=0,column=1,pady=5,padx=10)
ports_cmb.current(0)    
combobox2 = ttk.Combobox(comms_frame,values=baud_list,width=6)
combobox2.grid(row=1,column=1,pady=5,padx=10)
combobox2.current(4) 

root.mainloop()

Sign In or Register to comment.