Tkinter (Python)でサーボモータの操作パネルを作る

以前、Qt4でサーボモータ用の操作パネルを作ったことがありますが、環境を変えるたびにQt4をインストールするのも面倒なので、 Pythonに標準で入っているTkinterというのもを使った同様の物を作ってみました。

www.oki-lab.net

操作自体はUbuntuで行って、モータはArduinoで動かします。PCとArduinoはシリアル通信としています。

PC側プログラム

import Tkinter as tk
from Tkinter import *
import ttk
import serial

class PanelItem():
    val=0
    myval= 0

    def __init__(self, val):
        self.val=val
        print ("MOTOR NO:"+str(self.val))

    def SetItem(self):
        self.myval = DoubleVar(value=90)
        self.myval.trace("w", self.value_changed)

        # Label
        label = tk.Label(frame, text="MOTOR"+str(self.val))
        label.pack(side="top")
        
        # Scale
        sc = tk.Scale(
            frame,
            variable=self.myval,
            orient=HORIZONTAL, 
            length=200,
            from_=0,
            to=180)
        sc.pack(side="top")
        
    def value_changed(self, *args):
        ser.write(str(self.val)+str(self.myval.get())+";")
        print("No:" + str(self.val) + ", value = %d" % self.myval.get())
    
if __name__ == '__main__':
    ser=serial.Serial("/dev/ttyUSB1",9600)
    
    root = tk.Tk()
    root.title("CONTROL PANEL")
    root.columnconfigure(0, weight=1);
    root.rowconfigure(0, weight=1);
    
    frame = ttk.Frame(root, padding=10)
    frame.pack()
    frame.columnconfigure(0, weight=1);
    frame.rowconfigure(0, weight=1);

    items=[]
    for i in range(2):
        items.append(PanelItem(i))
        items[i].SetItem()
    
    root.mainloop()

PC側のプログラムはスライダをモータの数だけ準備して、モータの角度をスライダで指定するようになっています。 コンポーネントはPanelItemというクラスにして、for文で追加できるようにしました。なお、今回のプログラムはpython2では動きますが、python3だと色々変える必要があるようです。

Arduino側プログラム

#include <Servo.h>

const int MOTOR_NUM=2;
Servo myServo[MOTOR_NUM];
String data;
int motorNo=0;
int angle=90;

void setup() {
  Serial.begin(9600);
  
  for (int i=0; i<MOTOR_NUM; i++){
    myServo[i].attach(i);
    myServo[i].write(90);
  }
}

void loop() {
  if(Serial.available()>0){
    data=Serial.readStringUntil(';');

    motorNo=data.substring(0,1).toInt(); //モータ番号 (最大9)
    angle=data.substring(1).toInt(); //モータ角度(0~180度)

    Serial.println(motorNo);
    Serial.println(angle);

    myServo[motorNo].write(angle);
  }
  
}

Arduino側はシリアル通信でモータ番号と角度を受信してそのとおりに動かすようになっています。受信した文字列の最初の一桁がモータの番号でそれ以降が角度になっています。

動作

実際の動作は下記のとおりです。Tkinterというものの存在を初めて知って、ググりながら見様見真似で作った割にちゃんと動いてくれたので満足です。