Параллельное сервоуправление?

У меня есть Arduino Nano & Я успешно управляю с него 4 сервоприводами, но потом мне пришло в голову, что я управляю ими последовательно, т.е. я устанавливаю 1 положение, затем следующее, затем следующее....

Я бы хотел, чтобы сервоприводы действовали параллельно, т. е. чтобы их движения могли происходить одновременно, но с разной скоростью или в разных положениях.

Возможно ли это, используя только 1 контроллер (может быть, какая-то настройка опроса/прерывания?) или мне нужно будет запускать отдельные контроллеры для каждого набора сервоприводов и усилителей? синхронизировать их?

EDIT: добавлен код на стороне ПК & дополнительный код Arduino

Код Python для ПК:

from Tkinter import *
import serial

usbport = 'COM5'
ser = serial.Serial(usbport, 9600, timeout=1)

def init():
    for servo in range(1, 5):
        print servo
        ser.write(chr(255))
        ser.write(chr(servo))
        ser.write(chr(90))

class App:

    def __init__(self, master):

        frame = Frame(master)
        frame.pack()
        self.scale1 = Scale(master, from_=0, to=180, command=lambda ev: self.getAngle(1), bd=5, bigincrement=2, length=360, width=30, label='Servo 1')
        self.scale1.set(90)
        self.scale1.pack(side=LEFT)
        self.scale2 = Scale(master, from_=0, to=180, command=lambda ev: self.getAngle(2), bd=5, bigincrement=2, length=360, width=30, label='Servo 2')
        self.scale2.set(90)
        self.scale2.pack(side=LEFT)
        self.scale3 = Scale(master, from_=0, to=180, command=lambda ev: self.getAngle(3), bd=5, bigincrement=2, length=360, width=30, label='Servo 3')
        self.scale3.set(90)
        self.scale3.pack(side=LEFT)
        self.scale4 = Scale(master, from_=0, to=180, command=lambda ev: self.getAngle(4), bd=5, bigincrement=2, length=360, width=30, label='Servo 4')
        self.scale4.set(90)
        self.scale4.pack(side=LEFT)
        self.centre = Button(frame, text="Centre All", command=self.centre)
        self.centre.pack(side=TOP)


    def getAngle(self, slider):
        if slider==1:
            ang = self.scale1.get()
        if slider==2:
            ang = self.scale2.get()            
        if slider==3:
            ang = self.scale3.get()
        if slider==4:
            ang = self.scale4.get()
        ser.write(chr(255))
        ser.write(chr(slider))
        ser.write(chr(ang))

    def centre(self):
        for servo in range(1, 5):
            ser.write(chr(255))
            ser.write(chr(servo))
            ser.write(chr(90))
        self.scale1.set(90)
        self.scale2.set(90)
        self.scale3.set(90)
        self.scale4.set(90)

init()
root = Tk()
app = App(root)
root.mainloop()

Код Arduino

*
 * ------------------------------
 *   MultipleSerialServoControl
 * ------------------------------
 *
 * Uses the Arduino Serial library
 *  (http://arduino.cc/en/Reference/Serial)
 * and the Arduino Servo library
 *  (http://arduino.cc/en/Reference/Servo)
 * to control multiple servos from a PC using a USB cable.
 *
 * Dependencies:
 *   Arduino 0017 or higher
 *     (http://www.arduino.cc/en/Main/Software)
 *   Python servo.py module
 *     (http://principialabs.com/arduino-python-4-axis-servo-control/)
 *
 * Created:  23 December 2009
 * Author:   Brian D. Wendt
 *   (http://principialabs.com/)
 * Version:  1.1
 * License:  GPLv3
 *   (http://www.fsf.org/licensing/)
 *
 */

// Import the Arduino Servo library
#include <Servo.h> 

// Create a Servo object for each servo
Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;

// Common servo setup values
int minPulse = 600;   // minimum servo position, us (microseconds)
int maxPulse = 2400;  // maximum servo position, us

// User input for servo and position
int userInput[3];    // raw input from serial buffer, 3 bytes
int startbyte;       // start byte, begin reading input
int servo;           // which servo to pulse?
int pos = 90;        // servo angle 0-180
int i;               // iterator

// LED on Pin 13 for digital on/off demo
int ledPin = 13;
int pinState = LOW;

void setup() 
{ 
  // Attach each Servo object to a digital pin
  servo1.attach(3, minPulse, maxPulse);
  servo2.attach(4, minPulse, maxPulse);
  servo3.attach(5, minPulse, maxPulse);
  servo4.attach(9, minPulse, maxPulse);

  // LED on Pin 13 for digital on/off demo
  pinMode(ledPin, OUTPUT);

  // Open the serial connection, 9600 baud
  Serial.begin(9600);
} 

void loop() 
{ 
  // Wait for serial input (min 3 bytes in buffer)
  if (Serial.available() > 2) {
    // Read the first byte
    startbyte = Serial.read();
    // If it's really the startbyte (255) ...
    if (startbyte == 255) {
      // ... then get the next two bytes
      for (i=0;i<2;i++) {
        userInput[i] = Serial.read();
      }
      // First byte = servo to move?
      servo = userInput[0];
      // Second byte = which position?
      pos = userInput[1];
      // Packet error checking and recovery
      if (pos == 255) { servo = 255; }

      // Assign new position to appropriate servo
      switch (servo) {
        case 1:
          servo1.write(pos);    // move servo1 to 'pos'
          break;
        case 2:
          servo2.write(pos);
          break;
        case 3:
          servo3.write(pos);
          break;
        case 4:
          servo4.write(pos);
          break;

        // LED on Pin 13 for digital on/off demo
        case 99:
          if (pos == 180) {
            if (pinState == LOW) { pinState = HIGH; }
            else { pinState = LOW; }
          }
          if (pos == 0) {
            pinState = LOW;
          }
          digitalWrite(ledPin, pinState);
          break;
      }
    }
  }
}

, 👍-1

Обсуждение

Как вы сейчас их контролируете? Кнопками или через USB с ПК? Или просто жестко запрограммированные движения? Какие типы сервоприводов вы используете? Сервоприводы, которые я обычно использую, имеют только 1 скорость и не дают никакой обратной связи. Под медленным движением вы имели бы в виду задержку между небольшими шагами вращения?, @Paul

Я предполагаю, что вы используете библиотеку для этого. Все библиотеки уже делают это за вас. Поскольку вам нужно постоянно отправлять данные о положении (раз в 20 мс) на сервопривод., @Gerben

Спасибо за ответы. Я внес изменения в ОП с добавлением соответствующего кода. Я управляю сервоприводами с ПК с помощью ползунков Tinker. Я думаю, что у меня здесь просто концептуальный блок. Буду ли я прав, если скажу, что приведенный выше код управляет сервоприводами последовательно (например, функция center() в коде Python, через который сервоприводы зацикливаются)?, @DrBwts

Код Python опрашивает сервоприводы последовательно/последовательно, но код Arduino выглядит параллельно. Arduino проанализирует строку и передаст команду коду сервопривода, передав управление обратно команде loop() до того, как сервопривод достигнет заданной позиции. Может быть, это ваш вопрос: «является ли servo.write(position) блокирующим вызовом?» Если да, то ответ отрицательный, это неблокировка, двигатели будут двигаться со скоростью двигателей до конечных положений независимо. Если вам нужно скоординированное движение по этой схеме, вы должны разбить движения и скоординировать их на стороне питона., @Dave X

На мой взгляд, ваш код уже делает то, что вы хотите. Просто вы не можете двигать ползунки «параллельно», потому что вы, как человек, слишком медлительны. Если вы хотите иметь возможность выполнять синхронизированные движения, вы можете поместить кнопку в пользовательский интерфейс, которая отправляет положения ползунков в Arduino вместо отправки их при изменении положения ползунков. Таким образом, вы можете установить скоординированные движения. Что касается скорости, вам придется замедлять движения, делая небольшие приращения, вместо того, чтобы устанавливать окончательное значение для сервопривода. Если вам это нужно, я могу написать несколько фрагментов кода для этого, @frarugi87


2 ответа


1

Код Python опрашивает сервоприводы последовательно/последовательно, но код Arduino выглядит параллельно. Arduino проанализирует строку и передаст команду коду сервопривода, передав управление обратно команде loop() до того, как сервопривод достигнет заданной позиции. Может быть, это ваш вопрос: «является ли servo.write(position) блокирующим вызовом?» Если да, то ответ отрицательный, это неблокировка, двигатели будут двигаться со скоростью двигателей до конечных положений независимо. Если вам нужно скоординированное движение по этой схеме, вы должны разбить движения и скоординировать их на стороне Python без обратной связи.

Например, если вы хотите перейти из позиции (90,90,90,90) в позицию (81,0,90,90), вам необходимо знать, что для завершения -90 требуется 900 мс (например). move и разбейте его на 10 сегментов по 100 мс, чтобы координировать шаги (-1,0,-10,0). Выполнение координации без обратной связи будет неудобным и может быть лучше обработано со стороны вашего Python/UI.

,

0

Вы можете использовать библиотеку интерполяции и выполнять интерполяцию между любым количеством сервоприводов. Канал YouTube Джеймс Брутон делает это на многих своих роботах, поэтому вы, вероятно, можете учиться на его коде. Также проверьте этот репозиторий GitHub:

https://github.com/luisllamasbinaburo/Arduino-Interpolation

,