Плавное сервомоторное движение роботизированной руки: постоянный ответ и решение

Это не является и не будет дубликатом. Это нить, предназначенная для того, чтобы поделиться твердым солитоном, который я придумал, с остальной частью сообщества и обновлять его по мере оптимизации ad hoc. Поэтому я посетил сообщество StackExchange Arduino community, чтобы проверить, есть ли лучший способ сделать движение сервопривода более плавным, поскольку если мы придаем новое положение сервоприводу, прикрепленному к руке, он движется как атакующая каратистка.

Я нашел эти темы:

Плавная библиотека сервоуправления (Дат-ха предоставил фрагмент кода, который я предлагаю здесь исправить)

Я тоже проверил это: Мой Сервомотор Не Будет Двигаться Плавно

Я сам отвечу и обновлю этот поток, так как я делаю полный код arm, работающий правильно, и включаю инструкции для остальных людей, чтобы сэкономить время. Я до сих пор не добавил конденсатор, предложенный в потоках, но сделаю это как можно скорее.

, 👍0

Обсуждение

Как объяснено в ответах, функция задержки блокирует выполнение кода до тех пор, пока задержка не закончится, @Coder9390


3 ответа


Лучший ответ:

4

Ваше оригинальное решение использует блокирующий код (циклы for с вызовами delay() в них). Конечно, это работает, но это может легко привести вас к неприятностям, когда вы расширяете проект с помощью большего количества функций (поскольку ничего другого нельзя сделать во время движения датчика). Поэтому я бы предложил способ отказаться от всех блокировок для циклов и задержек, чтобы другой код мог работать во время движения сервопривода. Для этого мы можем использовать функцию millis() и принцип кодирования из примера BlinkWithoutDelay, который поставляется вместе с Arduino IDE.

#include <Servo.h>

Servo servo1;
int set_angle = 0;
int current_angle = 90; // setting starting angle to 90 degrees
unsigned long servo_timestamp = 0;
#define SERVO_INTERVAL    10   // changing the servo position every 10ms, defines the speed of the servo

void setup()
{
    servo1.attach(11);  // connect Servo to pin 11
    pinMode(A0, INPUT); // Connect potentiometer or Joystick x or y pin to A0 input
}

void loop(){
    if(millis()-servo_timestamp > SERVO_INTERVAL){
        servo_timestamp += SERVO_INTERVAL; // increment our timestamp by the servo interval
        // Measure the new set_angle only, if we really want to move the sensor
        int val1 = analogRead(A0); // Read the potentiometer position
        set_angle = map(val1, 0, 1023, 0, 180); // Map the value to be used with servo

        // Increment or decrement the current angle according to the set_angle
        // and don't change it, when we already are at the set_angle
        if(set_angle > current_angle){
            current_angle++;
        } else if(set_angle < current_angle){
            current_angle--;
        }
        // Write the new angle to the servo
        servo1.write(current_angle);
    }
}

Чтобы узнать больше о неблокирующем стиле кодирования с помощью функции millis(), вы можете поискать его в Google и посмотреть пример BlinkWithoutDelay. Есть много ресурсов для этого в Интернете. Комбинация timestamp и оператора millis() if выполняет код внутри оператора if на регулярном интервале SERVO_INTERVAL. Там мы считываем потенциометр и вычисляем новую уставку для угла поворота сервопривода. Затем мы увеличиваем или уменьшаем текущий угол на 1 в зависимости от заданного угла. А потом напишем новый угол к серво.

Вы можете изменить скорость, изменив SERVO_INTERVAL или in-/decrementing current_angle более чем на 1.

Код вне оператора if по-прежнему работает на полной скорости. Таким образом, в течение (чуть менее) 10 мс, когда сервокод не работает, вы можете выполнить другой код. Кроме того, этот код будет реагировать немедленно, когда блокирующий код сначала позволит сервоприводу работать в заданном положении и только затем снова изменится.

Примечание: Приведенный выше код не тестируется. Его цель-показать принцип. Могут быть небольшие ошибки, которых я не видел.

,

Спасибо, что показали мне окрестности. Серьезно. Я понятия не имел, что эта штука существует. Так что в случае, если нам понадобится сделать больше, чем это, мой способ действительно был бы очень хлопотным, так как мне нужно было бы добавить код в оба оператора if, что сделало бы его действительно тяжелее, чем должно быть. Я думаю, что ваше предложение лучше. Не говоря уже о том, что это решение делает работу оптимальной, в то время как мое создает задержки, которые будут мешать другим вещам. Когда я найду время, я протестирую его и включу ваш код со ссылкой в ОП. Слава богу!, @George Eco


0
  #include <Servo.h>
    Servo servo1;
    int previousangle1;
    int dc; 
    void setup()
      {
        dc = 10;    // Delay calibration 
        servo1.attach(11);  // connect Servo to pin 11
        pinMode(A0, INPUT); // Connect potentiometer or Joystick x or y pin to A0 input
        previousangle1 = 90; // Initialize position to 90 degrees (180 degree servo)
      }
    
    void loop()
      {     
           
      int val1 = analogRead(A0); // Read the potentiometer position
      int angle1 = map(val1, 0, 1023, 0, 180); // Map the value to be used with servo
    
      if(angle1>previousangle1)
      {
        for(int i=previousangle1; i<=angle1; i++)
        {
          servo1.write(i); //turn servo by 1 degrees
          delay(dc);        //delay for smoothness
        }
      }
      // Fix: This needed to be an else if 
      // Original piece of code had it as a second stand alone if
      else if(angle1<previousangle1)
      {
        for(int j=previousangle1; j>=angle1; j--)
        {
          servo1.write(j); 
          delay(dc);        
        }
      }
      delay(dc);  
      previousangle1 = angle1; 
      }

Теперь вам нужно сделать похожий код с разными переменными для всех 4 сервоприводов. Мне все еще нужно проверить добавление конденсатора, чтобы он работал еще лучше.

Исходный код взят отсюда: https://arduino.stackexchange.com/a/29970/76974

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

,

3

Вот результаты моделирования кода от Chrisl

Код (такой же, как и другой ответ)

#include <Servo.h>

Servo servo1;
int set_angle = 0;
int current_angle = 90; // setting starting angle to 90 degrees
unsigned long servo_timestamp = 0;
#define SERVO_INTERVAL    10   // changing the servo position every 10ms, defines the speed of the servo

void setup()
{
    servo1.attach(11);  // connect Servo to pin 11
    pinMode(A0, INPUT); // Connect potentiometer or Joystick x or y pin to A0 input
}

void loop(){
    if(millis()-servo_timestamp > SERVO_INTERVAL){
        servo_timestamp += SERVO_INTERVAL; // increment our timestamp by the servo interval
        // Measure the new set_angle only, if we really want to move the sensor
        int val1 = analogRead(A0); // Read the potentiometer position
        set_angle = map(val1, 0, 1023, 0, 180); // Map the value to be used with servo

        // Increment or decrement the current angle according to the set_angle
        // and don't change it, when we already are at the set_angle
        if(set_angle > current_angle){
            current_angle++;
        } else if(set_angle < current_angle){
            current_angle--;
        }
        // Write the new angle to the servo
        servo1.write(current_angle);
    }
}

Вы можете настроить код и увидеть изменения онлайн - Ссылка на моделирование arduino

,