2021年1月8日金曜日

Pythonでルンバを操作してみた。

 ルンバ980でもROIが使えるらしいことがわかったので久しぶりにルンバで遊んでみることに。

980のROIポートはダスト容器取り外しボタンの右側のパーツを上に引っ張ると現れる。こんなところについていたのか…770のときはminiDIN 7Pが取っ手の下についていたけど。ちなみに980はmicroUSBになっている。

microUSB端子にケーブルを指してPCとつなぐとUSBシリアルデバイスとして自動でドライバがインストールされた。(インターネットに繋がっていればWindows Update経由で自動で入るらしい)

コマンドは昔と変わっていないらしいので550のROIの資料を確認しながらとりあえず前後左右に動けるようなものを作ってみた。pyserialを使用しているので入ってない場合はpip install pyserialでインストール必要かも。

import tkinter as tk
from tkinter import messagebox
import tkinter.ttk as ttk
import struct
import serial
from serial.tools import list_ports
import time

after_id = None


        
def busConnect():
    global bus,ser
    ser = serial.Serial()
    ser.baudrate = 115200
    ser.timeout = 0.1       # タイムアウトの時間
    ser.port = bus
    ser.open()
    #print("open " + ser.port )
    initdata = [128, 131] #start,safe mode
    ser.write(bytes(initdata))
    
    return 1

def busDisconnect():
    global bus,ser
    ser.close()
    ser = None
    
def busButton(event):
    global bus,ser
    if ser is None:
        result = busConnect()
        if result == 1:
            buttonBus.config(text = "切断")
    else:
        busDisconnect()
        buttonBus.config(text = "接続")
        
def PortSelected(event):
    global bus
    bus = PortList.get()
    buttonBus.config(state="normal")
        
def roombaMove(left,right):#モータのPWM値を±255で指定
    global ser
    senddata = [146,((right & 0xFF00) >> 8),(right & 0xFF),((left & 0xFF00) >> 8),(left & 0xFF)] 
    if ser.is_open:
        ser.write(bytes(senddata))
        print(bytes(senddata))

def buttonPress(right,left):
    roombaMove(right*var_scale.get(),left*var_scale.get())
    
def key_event(event):
    key = event.keysym
    if key == "w":
        right = 1
        left = 1
    if key == "s":
        right = -1
        left = -1
    if key == "a":
        right = -1
        left = 1
    if key == "d":
        right = 1
        left = -1
    roombaMove(right*var_scale.get(),left*var_scale.get())
    
def key_stop(event):
    roombaMove(0,0)

bus = None
ser = None

ports = list_ports.comports()    # ポートデータを取得
devices = [info.device for info in ports]

root = tk.Tk()
root.title("Roombaテストするやつ Ver0.1β")
root.geometry("300x300")
root.option_add('*font', 'FixedSys 14')

ComPort = tk.Label(text='Port:')
ComPort.place(x=20, y=20)

#コンボボックスを設置
PortList = ttk.Combobox(root, values = devices,width=10,state='readonly')
PortList.set('Select')
PortList.place(x=80, y=20)
PortList.bind("<<ComboboxSelected>>", PortSelected)

# ボタンの追加
buttonBus = tk.Button(text='接続', width=6,state="disable")
buttonBus.place(x=200, y=15)
buttonBus.bind('<ButtonRelease-1>', busButton)

buttonF = tk.Button(text='↑', width=6, command = lambda: buttonPress(1,1))
buttonF.place(x=100, y=80)
buttonS = tk.Button(text='STOP', width=6, command = lambda: buttonPress(0,0))
buttonS.place(x=100, y=120)
buttonB = tk.Button(text='↓', width=6, command = lambda: buttonPress(-1,-1))
buttonB.place(x=100, y=160)
buttonL = tk.Button(text='←', width=6, command = lambda: buttonPress(-1,1))
buttonL.place(x=30, y=120)
buttonR = tk.Button(text='→', width=6, command = lambda: buttonPress(1,-1))
buttonR.place(x=170, y=120)

var_scale = tk.IntVar()
scale = ttk.Scale(root, from_=30, to=255, variable=var_scale)
scale.place(x=80, y=220)
labelScale = tk.Label(text='Speed')
labelScale.place(x=100, y=250)

root.bind("<KeyPress>", key_event)
root.bind("<KeyRelease>", key_stop)

root.mainloop()

とりあえずWASDを使ってキーボードでも動かせるようにしてみた。ちょっとそこら辺の実装がテキトーなので一旦キーを離してから他のボタンを押さないとちょっとおかしな動作になる。今回はテストなので治すのが面倒だからいいや…

あとはスピードのスライドバーを多少動かさないと動かないかも。ルンバを通常モードに戻す場合は持ち上げればいいっぽい。

USBになったことによってESP32とかのマイコンに直結するのはちょっとやりにくくなったかもしれない。miniDINのときは電源も取れたし。

0 件のコメント:

コメントを投稿