Arduinoで複数のサーボを動かす(Pythonとのシリアル通信)

環境

Windows10 Pro
Python 3.7.7
Arduino IDE 1.8.12
Arduino Uno R3

バージョン確認(pip freeze)

インストールするのは「pyserial」のみ(pipで可能)

pyserial==3.4

モーションの作成

次のようなテキストファイルを用意する。
ファイル名は「motion.txt」、区切りはタブ。
1行ごとにサーボの角度が記載されている。(この場合サーボは3つ)

servo1	servo2	servo3
60	120	150
120	60	30
60	120	150
70	110	130
80	100	110
90	90	90

Pythonコード

import serial, time

with open('motion.txt') as f:
    lines = [s.strip() for s in f.readlines()[1:]]

print("Open Port")
ser =serial.Serial("COM3", 9600)
time.sleep(1.5)

for i in range(len(lines)):
    
    x = lines[i].split()
    x = [int(i) for i in x]
    x = [179 if i > 179 else i for i in x]
    x = [0 if i < 0 else i for i in x]

    #servoは201からカウントすることとする
    #servoの角度は0~179
    #サーボ番号と角度がバッティングすることはない
    servo_1_id = (201).to_bytes(1, 'big')
    servo_2_id = (202).to_bytes(1, 'big')
    servo_3_id = (203).to_bytes(1, 'big')

    servo_1_angle = (x[0]).to_bytes(1, 'big')
    servo_2_angle = (x[1]).to_bytes(1, 'big')
    servo_3_angle = (x[2]).to_bytes(1, 'big')

    ser.write(servo_1_id)
    ser.write(servo_1_angle)
    
    ser.write(servo_2_id)
    ser.write(servo_2_angle)

    ser.write(servo_3_id)
    ser.write(servo_3_angle)

    time.sleep(1)

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

Arduinoスケッチ

#include <Servo.h>

int const servo_count=3;

Servo myServo_1;
Servo myServo_2;
Servo myServo_3;

int servo_no;
int servo_angle;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  
  myServo_1.attach(9);
  myServo_2.attach(10);
  myServo_3.attach(11);

  myServo_1.write(90);
  myServo_2.write(90);
  myServo_3.write(90);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(Serial.available()> (2*servo_count-1)){
    for(int i=0; i<servo_count; i++){
      servo_no = Serial.read();
      if(servo_no > 200){
        servo_angle = Serial.read();
        if(servo_no==201){
        myServo_1.write(servo_angle);
        }
        if(servo_no==202){
        myServo_2.write(servo_angle);
        }
        if(servo_no==203){
          myServo_3.write(servo_angle);
        }
      }
    }
    delay(100);
  }
}