Заставить серводвигатели двигаться более плавно с помощью джойстика?
Поэтому я делаю штуковину типа "турель", используя два серводвигателя, управляемых джойстиком. Код, который я запускаю, работает, однако он очень резкий и не очень хорошо перемещается, особенно по диагональным линиям. Мой код выглядит следующим образом:
#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 ответ
Сервоприводы маленькие и легкие и стараются как можно быстрее перейти в положение, о котором вы им говорите. Джойстики также могут очень быстро менять значения, и они также могут быть затруднены. В результате ваши сервоприводы постоянно совершают множество маленьких быстрых движений, которые могут заставить револьверную головку дергаться.
Я могу придумать два варианта, и вы можете сделать оба:
Сгладьте входы джойстика с помощью фильтрации нижних частот. Обычно это просто означает использование средневзвешенного значения текущих и предыдущих значений. Идея состоит в том, чтобы устранить плохие показания или два, которые могут произойти из-за грязных контактов в потенциометре.
Сгладить движение. Вместо того, чтобы мгновенно пытаться переместить сервоприводы прямо в текущее положение джойстика, переместите их в целевое положение. На каждой итерации цикла они будут приближаться к целевой позиции, а не пытаться прыгнуть туда почти мгновенно.
Для #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
}
}
}
Обратите внимание на задержку, которая функционально зависит от угла, на который он движется - это "сгладит" сервопривод и уменьшит дрожание (хотя и не устранит его полностью).