Заставить серводвигатели двигаться более плавно с помощью джойстика?

Поэтому я делаю штуковину типа "турель", используя два серводвигателя, управляемых джойстиком. Код, который я запускаю, работает, однако он очень резкий и не очень хорошо перемещается, особенно по диагональным линиям. Мой код выглядит следующим образом:

#include <Servo.h>
#define LASER 11

int x = 0;

Servo servo_1;  // create servo object to control a servo
Servo servo_2;

// Arduino pin numbers
const int SW_pin = 2; // digital pin connected to switch output
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output

int butt;
int joy_val;

void setup() {
  pinMode(SW_pin, INPUT);
  digitalWrite(SW_pin, HIGH);
  servo_1.attach(9);// attaches the servo on pin 9 to the servo object
  servo_2.attach(10);
  pinMode(LASER, OUTPUT);
  digitalWrite(LASER, HIGH);
  Serial.begin(9600);
}

void loop() {
  joy_val = analogRead(X_pin); // reads the value of joystick (between 0-1023)
  joy_val = map(joy_val, 0, 1023, 0, 180); // servo value between 0-180
  servo_1.write(joy_val); // sets the servo position according to the joystick value
  delay(150);

  joy_val = analogRead(Y_pin); // reads the value of joystick (between 0-1023)
  joy_val = map(joy_val, 0, 1023, 0, 180); // servo value between 0-180
  servo_2.write(joy_val); // sets the servo position according to the joystick 
value
  delay(150);
  delay(15);

  butt = digitalRead(SW_pin);

  if (butt == LOW){
    x = true;
  }

  if (x == true){
    digitalWrite(LASER, LOW);
    Serial.print(x);
  }
}

Буду очень признателен за любой совет или помощь, я довольно новичок в Arduino:)

1 ответ

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

Я могу придумать два варианта, и вы можете сделать оба:

  1. Сгладьте входы джойстика с помощью фильтрации нижних частот. Обычно это просто означает использование средневзвешенного значения текущих и предыдущих значений. Идея состоит в том, чтобы устранить плохие показания или два, которые могут произойти из-за грязных контактов в потенциометре.

  2. Сгладить движение. Вместо того, чтобы мгновенно пытаться переместить сервоприводы прямо в текущее положение джойстика, переместите их в целевое положение. На каждой итерации цикла они будут приближаться к целевой позиции, а не пытаться прыгнуть туда почти мгновенно.

Для #2 есть пара подходов, которые я люблю использовать.

Один из них - просто использовать средневзвешенное значение текущей позиции сервопривода и целевой позиции. Если вы перемещаете джойстик на значительное расстояние, турель будет быстро поворачиваться, но замедляться по мере приближения к заданному положению.

Другой заключается в использовании физической модели. Представьте себе создание вектора силы, который указывает от текущего положения сервоприводов к целевому положению джойстиков и пропорционален расстоянию между ними. Примените эту силу к текущей точке. Также примените "силу трения", которая противостоит скорости текущей точки. Численно интегрируйте скорость и положение в петле. Если вы внезапно переместите джойстик в новое положение, турель будет ускоряться к нему, а затем замедляться по мере приближения к нему. Регулировка констант, используемых для вычисления сил, позволит вам контролировать, насколько "тяжелым" кажется механизм.

Я поставил задержку пропорциональную скорости сервопривода. Попробуйте это (взято из моего руководства: Основы и управление серводвигателем Arduino):

#include <Servo.h>
#include <math.h>

Servo servo_1; // servo controller (multiple can exist)

int servo_pin = 3; // PWM pin for servo control
int joy_pin_x = A0; // pin for x-dir joystick
int joy_pin_y = A1; // pin for y-dir joystick
int offset_x = 0; // subtracting the initial joystick x-location
int offset_y = 0; // subtracting the initial joystick y-location
int pos = 90;    // servo starting position aligned with joystick
int prev_deg = 0; // bound for reducing jitter
int x_prev = 0; // bound for reducing jitter
int y_prev = 0; // reducing jitter

void setup() {
  servo_1.attach(servo_pin); // start servo control
  Serial.begin(9600);
  servo_1.write(pos); // move to center (joystick neutral)
  Serial.println("Positioned at 90 Degrees");  
  offset_x = analogRead(joy_pin_x); // initial joystick x-val
  offset_y = analogRead(joy_pin_y); // initial joystick y-val
}

void loop() {
  int x_val = analogRead(joy_pin_x)-offset_x; // relative joystick x
  int y_val = analogRead(joy_pin_y)-offset_y; // relative joystick y
  if (abs(x_prev-x_val)<10 and abs(y_prev-y_val)<10){
    // reduce jitter
  } else {
    x_prev = x_val;
    y_prev = y_val;
    float deg = 180-(int(atan2(x_val,y_val)*(180.0/PI))+90); // angle calc
    if (abs(deg-prev_deg)>2 and deg>0 and deg<180){
      servo_1.write(deg); // move servo to joystick location
      delay(abs(deg-prev_deg)*(10.0/6.0));
      prev_deg = deg;
      Serial.println(deg); // print out degree
    }
  }
}

Обратите внимание на задержку, которая функционально зависит от угла, на который он движется - это "сгладит" сервопривод и уменьшит дрожание (хотя и не устранит его полностью).

Другие вопросы по тегам