LoginSignup
2
4

More than 1 year has passed since last update.

Python + Arduino でGUIからロボットアームを制御してみた

Posted at

はじめに

ロボットアームキットを組立てて動かしてみました。
GUIを作って簡単に動かせるようにしました。

構成

・ロボットアームキット
DiyStudio 6自由度ロボットアームDIYキット

・PCA9685
HiLetgo PCA9685

・外部電源
SUCCUL ACアダプター 5V 4A
Kabenjee DC電源コネクタ ジャック コネクタ

・Arduino
ELEGOO Arduino用UNO R3スターターキット
ELEGOO 120pcs多色デュポンワイヤー

組立、配線

ロボットアームの組立ては同封の説明書を参考に組み立てます。
(組み立てる時はサーボモータの原点位置を把握して、動かしたときに干渉しないように注意します。)

サーボモータ、PCA9685、Arduinoの配線はこちらの方を参考にさせてもらいました。
サーボモータドライバ(PCA9685)とArduinoを用いて複数(12個)のサーボモータ(mg996r)を動かす

模式図
グラフィックス1.png

実機
IMG.jpg

プログラム

・動作環境

Windows10 Home
Python 3.7.2
Arduino IDE 1.8.13
Arduino Uno R3

・Arduino
Arduinoに書き込むコードはこちらの方を参考にしました。
Arduinoで複数のサーボを動かす(PCA9685)

servomotor_ide.ino
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

#define MIN 150
#define MAX 600

Adafruit_PWMServoDriver PWM_SERVO = Adafruit_PWMServoDriver(0x40);

void setup() {
  Serial.begin(9600);
  PWM_SERVO.begin();
  PWM_SERVO.setPWMFreq(50);
}

void loop() {
  if(Serial.available()> 1){
    int SERVO_NUMBER;
    int SERVO_ANGLE;
    SERVO_NUMBER = Serial.read();
    if(SERVO_NUMBER > 199){
      SERVO_ANGLE = Serial.read();
      if(SERVO_NUMBER==200){SERVO_MOVE(0, SERVO_ANGLE);}
      if(SERVO_NUMBER==201){SERVO_MOVE(1, SERVO_ANGLE);}
      if(SERVO_NUMBER==202){SERVO_MOVE(2, SERVO_ANGLE);}
      if(SERVO_NUMBER==203){SERVO_MOVE(3, SERVO_ANGLE);}
      if(SERVO_NUMBER==204){SERVO_MOVE(4, SERVO_ANGLE);}
      if(SERVO_NUMBER==205){SERVO_MOVE(5, SERVO_ANGLE);}
    }
    delay(200);
  }
}

void SERVO_MOVE(int ch, int ang){
  ang = map(ang, 0, 180, MIN, MAX);
  PWM_SERVO.setPWM(ch, 0, ang);
}

・Python
GUIの作成にはtkinterを利用しました。
arduinoとはシリアル通信を利用します。pyserialをpipでインストールします。
pipの使い方

pyserial 3.5

pythonコード

module_GUI_servo.py
import tkinter as tk
import serial, time
from functools import partial

# シリアル通信準備
print("Open Port")
ser =serial.Serial("COM3", 9600)
time.sleep(1.5)

# ウィンドウの作成
body = tk.Tk()
body.title("robot_control_GUI") 
body.geometry("700x550") 

#servo_0--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# 上2ボタンの押したときの動作
x_position_servo_0 = 60
def botan_up_2(servo_num):
    if int(label_servo_0_angle["text"]) < 170:
        #ラベルの値を取得してint型に変換して、+10して返す
        label_servo_0_angle["text"] = int(label_servo_0_angle["text"]) + 10
    servo_move(servo_num,int(label_servo_0_angle["text"]))

# 上2ボタンの作成
bota_up_2 = tk.Button(text ='▲▲',width = 7,height = 3,command = partial(botan_up_2,0))
bota_up_2.place(x=x_position_servo_0,y=0)

# 上1ボタンの押したときの動作
def botan_up(servo_num):
    if int(label_servo_0_angle["text"]) < 179:
        #ラベルの値を取得してint型に変換して、+1して返す
        label_servo_0_angle["text"] = int(label_servo_0_angle["text"]) + 1
    servo_move(servo_num,int(label_servo_0_angle["text"]))

# 上1ボタンの作成
bota_up = tk.Button(text ='▲',width = 7,height = 3,command = partial(botan_up,0))
bota_up.place(x=x_position_servo_0,y=60)

# 下1ボタンの押したときの動作
def botan_down(servo_num):
    if int(label_servo_0_angle["text"]) > 0:
        #ラベルの値を取得してint型に変換して、-1して返す
        label_servo_0_angle["text"] = int(label_servo_0_angle["text"]) - 1
    servo_move(servo_num,int(label_servo_0_angle["text"]))

# 下1ボタンの作成
bota_down = tk.Button(text ='▼',width = 7,height = 3,command = partial(botan_down,0))
bota_down.place(x=x_position_servo_0,y=120)

# 下2ボタンの押したときの動作
def botan_down_2(servo_num):
    if int(label_servo_0_angle["text"]) > 10:
        #ラベルの値を取得してint型に変換して、-10して返す
        label_servo_0_angle["text"] = int(label_servo_0_angle["text"]) - 10
    servo_move(servo_num,int(label_servo_0_angle["text"]))

# 下2ボタンの作成
bota_down_2 = tk.Button(text ='▼▼',width = 7,height = 3,command = partial(botan_down_2,0))
bota_down_2.place(x=x_position_servo_0,y=180)

# 「servo_0」の角度の表示
label_servo_0_angle = tk.Label(text="90", borderwidth=2, relief="sunken")
label_servo_0_angle.place(x=x_position_servo_0, y=240, width=60, height=20)

# 「servo_0」ラベルの作成
label_servo_0 = tk.Label(text="servo_0") 
label_servo_0.place(x=x_position_servo_0,y=260)
#----------------------------------------------------------------------------------------------------------

#servo_1----------------------------------------------------------------------------------------------------------
# 上2ボタンの押したときの動作
x_position_servo_1 = 150
def botan_up_2(servo_num):
    if int(label_servo_1_angle["text"]) < 170:
        #ラベルの値を取得してint型に変換して、+10して返す
        label_servo_1_angle["text"] = int(label_servo_1_angle["text"]) + 10
    servo_move(servo_num,int(label_servo_1_angle["text"]))

# 上2ボタンの作成
bota_up_2 = tk.Button(text ='▲▲',width = 7,height = 3,command = partial(botan_up_2,1))
bota_up_2.place(x=x_position_servo_1,y=0)

# 上1ボタンの押したときの動作
def botan_up(servo_num):
    if int(label_servo_1_angle["text"]) < 179:
        #ラベルの値を取得してint型に変換して、+1して返す
        label_servo_1_angle["text"] = int(label_servo_1_angle["text"]) + 1
    servo_move(servo_num,int(label_servo_1_angle["text"]))

# 上1ボタンの作成
bota_up = tk.Button(text ='▲',width = 7,height = 3,command = partial(botan_up,1))
bota_up.place(x=x_position_servo_1,y=60)

# 下1ボタンの押したときの動作
def botan_down(servo_num):
    if int(label_servo_1_angle["text"]) > 0:
        #ラベルの値を取得してint型に変換して、-1して返す
        label_servo_1_angle["text"] = int(label_servo_1_angle["text"]) - 1
    servo_move(servo_num,int(label_servo_1_angle["text"]))

# 下1ボタンの作成
bota_down = tk.Button(text ='▼',width = 7,height = 3,command = partial(botan_down,1))
bota_down.place(x=x_position_servo_1,y=120)

# 下2ボタンの押したときの動作
def botan_down_2(servo_num):
    if int(label_servo_1_angle["text"]) > 10:
        #ラベルの値を取得してint型に変換して、-10して返す
        label_servo_1_angle["text"] = int(label_servo_1_angle["text"]) - 10
    servo_move(servo_num,int(label_servo_1_angle["text"]))

# 下2ボタンの作成
bota_down_2 = tk.Button(text ='▼▼',width = 7,height = 3,command = partial(botan_down_2,1))
bota_down_2.place(x=x_position_servo_1,y=180)

# 「servo_1」の角度の表示
label_servo_1_angle = tk.Label(text="90", borderwidth=2, relief="sunken")
label_servo_1_angle.place(x=x_position_servo_1, y=240, width=60, height=20)

# 「servo_1」ラベルの作成
label_servo_1 = tk.Label(text="servo_1") 
label_servo_1.place(x=x_position_servo_1,y=260)
#----------------------------------------------------------------------------------------------------------

#servo_2----------------------------------------------------------------------------------------------------------
# 上2ボタンの押したときの動作
x_position_servo_2 = 240
def botan_up_2(servo_num):
    if int(label_servo_2_angle["text"]) < 170:
        #ラベルの値を取得してint型に変換して、+10して返す
        label_servo_2_angle["text"] = int(label_servo_2_angle["text"]) + 10
    servo_move(servo_num,int(label_servo_2_angle["text"]))

# 上2ボタンの作成
bota_up_2 = tk.Button(text ='▲▲',width = 7,height = 3,command = partial(botan_up_2,2))
bota_up_2.place(x=x_position_servo_2,y=0)

# 上1ボタンの押したときの動作
def botan_up(servo_num):
    if int(label_servo_2_angle["text"]) < 179:
        #ラベルの値を取得してint型に変換して、+1して返す
        label_servo_2_angle["text"] = int(label_servo_2_angle["text"]) + 1
    servo_move(servo_num,int(label_servo_2_angle["text"]))

# 上1ボタンの作成
bota_up = tk.Button(text ='▲',width = 7,height = 3,command = partial(botan_up,2))
bota_up.place(x=x_position_servo_2,y=60)

# 下1ボタンの押したときの動作
def botan_down(servo_num):
    if int(label_servo_2_angle["text"]) > 0:
        #ラベルの値を取得してint型に変換して、-1して返す
        label_servo_2_angle["text"] = int(label_servo_2_angle["text"]) - 1
    servo_move(servo_num,int(label_servo_2_angle["text"]))

# 下1ボタンの作成
bota_down = tk.Button(text ='▼',width = 7,height = 3,command = partial(botan_down,2))
bota_down.place(x=x_position_servo_2,y=120)

# 下2ボタンの押したときの動作
def botan_down_2(servo_num):
    if int(label_servo_2_angle["text"]) > 10:
        #ラベルの値を取得してint型に変換して、-10して返す
        label_servo_2_angle["text"] = int(label_servo_2_angle["text"]) - 10
    servo_move(servo_num,int(label_servo_2_angle["text"]))

# 下2ボタンの作成
bota_down_2 = tk.Button(text ='▼▼',width = 7,height = 3,command = partial(botan_down_2,2))
bota_down_2.place(x=x_position_servo_2,y=180)

# 「servo_2」の角度の表示
label_servo_2_angle = tk.Label(text="90", borderwidth=2, relief="sunken")
label_servo_2_angle.place(x=x_position_servo_2, y=240, width=60, height=20)

# 「servo_2」ラベルの作成
label_servo_2 = tk.Label(text="servo_2") 
label_servo_2.place(x=x_position_servo_2,y=260)
#----------------------------------------------------------------------------------------------------------

#servo_3----------------------------------------------------------------------------------------------------------
# 上2ボタンの押したときの動作
x_position_servo_3 = 330
def botan_up_2(servo_num):
    if int(label_servo_3_angle["text"]) < 170:
        #ラベルの値を取得してint型に変換して、+10して返す
        label_servo_3_angle["text"] = int(label_servo_3_angle["text"]) + 10
    servo_move(servo_num,int(label_servo_3_angle["text"]))

# 上2ボタンの作成
bota_up_2 = tk.Button(text ='▲▲',width = 7,height = 3,command = partial(botan_up_2,3))
bota_up_2.place(x=x_position_servo_3,y=0)

# 上1ボタンの押したときの動作
def botan_up(servo_num):
    if int(label_servo_3_angle["text"]) < 179:
        #ラベルの値を取得してint型に変換して、+1して返す
        label_servo_3_angle["text"] = int(label_servo_3_angle["text"]) + 1
    servo_move(servo_num,int(label_servo_3_angle["text"]))

# 上1ボタンの作成
bota_up = tk.Button(text ='▲',width = 7,height = 3,command = partial(botan_up,3))
bota_up.place(x=x_position_servo_3,y=60)

# 下1ボタンの押したときの動作
def botan_down(servo_num):
    if int(label_servo_3_angle["text"]) > 0:
        #ラベルの値を取得してint型に変換して、-1して返す
        label_servo_3_angle["text"] = int(label_servo_3_angle["text"]) - 1
    servo_move(servo_num,int(label_servo_3_angle["text"]))

# 下1ボタンの作成
bota_down = tk.Button(text ='▼',width = 7,height = 3,command = partial(botan_down,3))
bota_down.place(x=x_position_servo_3,y=120)

# 下2ボタンの押したときの動作
def botan_down_2(servo_num):
    if int(label_servo_3_angle["text"]) > 10:
        #ラベルの値を取得してint型に変換して、-10して返す
        label_servo_3_angle["text"] = int(label_servo_3_angle["text"]) - 10
    servo_move(servo_num,int(label_servo_3_angle["text"]))

# 下2ボタンの作成
bota_down_2 = tk.Button(text ='▼▼',width = 7,height = 3,command = partial(botan_down_2,3))
bota_down_2.place(x=x_position_servo_3,y=180)

# 「servo_3」の角度の表示
label_servo_3_angle = tk.Label(text="90", borderwidth=2, relief="sunken")
label_servo_3_angle.place(x=x_position_servo_3, y=240, width=60, height=20)

# 「servo_3」ラベルの作成
label_servo_3 = tk.Label(text="servo_3") 
label_servo_3.place(x=x_position_servo_3,y=260)
#----------------------------------------------------------------------------------------------------------

#servo_4----------------------------------------------------------------------------------------------------------
# 上2ボタンの押したときの動作
x_position_servo_4 = 420
def botan_up_2(servo_num):
    if int(label_servo_4_angle["text"]) < 170:
        #ラベルの値を取得してint型に変換して、+10して返す
        label_servo_4_angle["text"] = int(label_servo_4_angle["text"]) + 10
    servo_move(servo_num,int(label_servo_4_angle["text"]))

# 上2ボタンの作成
bota_up_2 = tk.Button(text ='▲▲',width = 7,height = 3,command = partial(botan_up_2,4))
bota_up_2.place(x=x_position_servo_4,y=0)

# 上1ボタンの押したときの動作
def botan_up(servo_num):
    if int(label_servo_4_angle["text"]) < 179:
        #ラベルの値を取得してint型に変換して、+1して返す
        label_servo_4_angle["text"] = int(label_servo_4_angle["text"]) + 1
    servo_move(servo_num,int(label_servo_4_angle["text"]))

# 上1ボタンの作成
bota_up = tk.Button(text ='▲',width = 7,height = 3,command = partial(botan_up,4))
bota_up.place(x=x_position_servo_4,y=60)

# 下1ボタンの押したときの動作
def botan_down(servo_num):
    if int(label_servo_4_angle["text"]) > 0:
        #ラベルの値を取得してint型に変換して、-1して返す
        label_servo_4_angle["text"] = int(label_servo_4_angle["text"]) - 1
    servo_move(servo_num,int(label_servo_4_angle["text"]))

# 下1ボタンの作成
bota_down = tk.Button(text ='▼',width = 7,height = 3,command = partial(botan_down,4))
bota_down.place(x=x_position_servo_4,y=120)

# 下2ボタンの押したときの動作
def botan_down_2(servo_num):
    if int(label_servo_4_angle["text"]) > 10:
        #ラベルの値を取得してint型に変換して、-10して返す
        label_servo_4_angle["text"] = int(label_servo_4_angle["text"]) - 10
    servo_move(servo_num,int(label_servo_4_angle["text"]))

# 下2ボタンの作成
bota_down_2 = tk.Button(text ='▼▼',width = 7,height = 3,command = partial(botan_down_2,4))
bota_down_2.place(x=x_position_servo_4,y=180)

# 「servo_4」の角度の表示
label_servo_4_angle = tk.Label(text="90", borderwidth=2, relief="sunken")
label_servo_4_angle.place(x=x_position_servo_4, y=240, width=60, height=20)

# 「servo_4」ラベルの作成
label_servo_4 = tk.Label(text="servo_4") 
label_servo_4.place(x=x_position_servo_4,y=260)
#----------------------------------------------------------------------------------------------------------

#servo_5----------------------------------------------------------------------------------------------------------
# 上2ボタンの押したときの動作
x_position_servo_5 = 510
def botan_up_2(servo_num):
    if int(label_servo_5_angle["text"]) < 50:
        #ラベルの値を取得してint型に変換して、+10して返す
        label_servo_5_angle["text"] = int(label_servo_5_angle["text"]) + 10
    servo_move(servo_num,int(label_servo_5_angle["text"]))

# 上2ボタンの作成
bota_up_2 = tk.Button(text ='▲▲',width = 7,height = 3,command = partial(botan_up_2,5))
bota_up_2.place(x=x_position_servo_5,y=0)

# 上1ボタンの押したときの動作
def botan_up(servo_num):
    if int(label_servo_5_angle["text"]) < 59:
        #ラベルの値を取得してint型に変換して、+1して返す
        label_servo_5_angle["text"] = int(label_servo_5_angle["text"]) + 1
    servo_move(servo_num,int(label_servo_5_angle["text"]))

# 上1ボタンの作成
bota_up = tk.Button(text ='▲',width = 7,height = 3,command = partial(botan_up,5))
bota_up.place(x=x_position_servo_5,y=60)

# 下1ボタンの押したときの動作
def botan_down(servo_num):
    if int(label_servo_5_angle["text"]) > 0:
        #ラベルの値を取得してint型に変換して、-1して返す
        label_servo_5_angle["text"] = int(label_servo_5_angle["text"]) - 1
    servo_move(servo_num,int(label_servo_5_angle["text"]))

# 下1ボタンの作成
bota_down = tk.Button(text ='▼',width = 7,height = 3,command = partial(botan_down,5))
bota_down.place(x=x_position_servo_5,y=120)

# 下2ボタンの押したときの動作
def botan_down_2(servo_num):
    if int(label_servo_5_angle["text"]) > 10:
        #ラベルの値を取得してint型に変換して、-10して返す
        label_servo_5_angle["text"] = int(label_servo_5_angle["text"]) - 10
    servo_move(servo_num,int(label_servo_5_angle["text"]))

# 下2ボタンの作成
bota_down_2 = tk.Button(text ='▼▼',width = 7,height = 3,command = partial(botan_down_2,5))
bota_down_2.place(x=x_position_servo_5,y=180)

# 「servo_5」の角度の表示
label_servo_5_angle = tk.Label(text="0", borderwidth=2, relief="sunken")
label_servo_5_angle.place(x=x_position_servo_5, y=240, width=60, height=20)

# 「servo_5」ラベルの作成
label_servo_5 = tk.Label(text="servo_5") 
label_servo_5.place(x=x_position_servo_5,y=260)
#----------------------------------------------------------------------------------------------------------

def servo_move(servo_num,servo_angle):
    #servoは200からカウントすることとする
    #サーボ番号と角度がバッティングすることはない
    count_servo = 200 + servo_num
    servo_id = (count_servo).to_bytes(1, 'big')
    servo_angle = (servo_angle).to_bytes(1, 'big')
    ser.write(servo_id)
    ser.write(servo_angle)

#実行内容記述_終了-----------------------------------------------------
# イベントループ
body.mainloop()

print("Close Port")
ser.close()

GUI
ボタンをクリックするごとに動くようにしました。
キャプチャ.PNG

ボタンを押したときの移動量

button angle
▲▲ +10
+1
-1
▼▼ -10

各サーボの角度

servo min max default
servo_0 0 179 90
servo_1 0 179 90
servo_2 0 179 90
servo_3 0 179 90
servo_4 0 179 90
servo_5 0 59 0

servo_5は60度ぐらいで閉じるようにしました。
グラフィックス2.png

終わりに

GUIから動かしている記事が少なかったので、やってみました。
GUIで動かせると直感的に操作できるので、簡単に動かせるようになりました。

参考

arduino ide ポートの指定
Arduinoライブラリのインストール
arduino Adafruit_PWMServoDriver

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4