Плавное сервомоторное движение роботизированной руки: постоянный ответ и решение
Это не является и не будет дубликатом. Это нить, предназначенная для того, чтобы поделиться твердым солитоном, который я придумал, с остальной частью сообщества и обновлять его по мере оптимизации ad hoc. Поэтому я посетил сообщество StackExchange Arduino community, чтобы проверить, есть ли лучший способ сделать движение сервопривода более плавным, поскольку если мы придаем новое положение сервоприводу, прикрепленному к руке, он движется как атакующая каратистка.
Я нашел эти темы:
Плавная библиотека сервоуправления (Дат-ха предоставил фрагмент кода, который я предлагаю здесь исправить)
Я тоже проверил это: Мой Сервомотор Не Будет Двигаться Плавно
Я сам отвечу и обновлю этот поток, так как я делаю полный код arm, работающий правильно, и включаю инструкции для остальных людей, чтобы сэкономить время. Я до сих пор не добавил конденсатор, предложенный в потоках, но сделаю это как можно скорее.
@George Eco, 👍0
Обсуждение3 ответа
Лучший ответ:
Ваше оригинальное решение использует блокирующий код (циклы 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
#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
Я отредактирую это, добавив код для остальных сервоприводов позже.
Вот результаты моделирования кода от 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
- Tower Pro MG996R сервопривод с высоким крутящим моментом 180 °, управляющий с помощью Arduino
- Как изменить скорость нескольких сервоприводов, работающих одновременно с модулем PCA9685?
- Питание нескольких сервоприводов от одной батареи. Чего не хватает в схеме?
- LM7805 сильно нагревается с четырьмя серводвигателями
- Запускаю робота с двумя передними датчиками, но он тормозит
- Как заставить сервопривод вращаться на угол больше 180°
- Пповорот сервопривода на 90 градусов
- Как синхронно управлять двумя сервоприводами?
Как объяснено в ответах, функция задержки блокирует выполнение кода до тех пор, пока задержка не закончится, @Coder9390