Потенциометр + Servo в фиксированных положениях.

wgaint
Offline
Зарегистрирован: 15.03.2015

Всем привет.
Есть задача фиксировать серву в 7-ми положениях, в зависимости от положения потенциометра. Получился код:

#include <Servo.h> 
 
Servo myservo;  
int val; 
int vol = 0;   // переменная для приема данных и отправки на серв
 
void setup() 
{ 
myservo.attach(5);   
} 
 
 
void loop() 
{ 

val = analogRead(0); // считываем уровень на 0-м пине 0-1024
val = val/10; //округляем
//всего 7 положений сервы от 0 до 90 градусов:
if (val <= 13) {myservo.write(0);}
else if (val > 13 && val <= 29  ) {myservo.write(15);}
else if (val > 29 && val <= 44) {myservo.write(30);}
else if (val > 45 && val <= 58) {myservo.write(45);}
else if (val > 58 && val <= 74) {myservo.write(60);}
else if (val > 75 && val <= 88) {myservo.write(75);}
else if (val > 90){myservo.write(90);}
    delay(350);                       // ждем чтобы серв докрутил
   
}

На Proteuse мотор ведет себя как то не совсем адекватно. Углы не те, что заданы.

Посколько реальное железо пока летит, прошу посмотреть код на предмет ошибок-подводных камней. Спасибо.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

17 строка  val = map(val, 0, 1023, 0, 179); // scale it to use it with the servo (value between 0 and 180)

и у вас "полный" оборот потенциометра будет 0-180, но уже в градусах. Так самому понятнее будет.

А на " докрутку" можно и 20-50 давать. Дёргаться меньше будет.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

А на " докрутку" можно и 20-50 давать. Дёргаться меньше будет.А на " докрутку" можно и 20-50 давать.

...а можно посчитать исходя из скорооборотности сервы ( датаШит ) + нагрузка на вал - по максимуму угла отработки

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

val = analogRead(0); // считываем уровень на 0-м пине 0-1024

нет - считываем уровень на 0-м пине 0-1023

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

SU-27-16 пишет:

А на " докрутку" можно и 20-50 давать. Дёргаться меньше будет.

...а можно посчитать исходя из скорооборотности сервы ( датаШит ) + нагрузка на вал - по максимуму угла отработки

Всё не так, даже совсем не так.

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

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

Поэтому подав один импульс и если серва по каким-то причинам не доехала до желаемого нами положения,
то следующая попытка сделать зто произойдёт только тогда, когда прийдет второй импульс. Даже если через неделю.

Чаще подаём- быстрее доедем. И, доехав, будем дрожать вокруг конечной точки с каждым импульсом.

Но слишком часто тоже нельзя- надо чтобы "восстановился" внутренний одновибратор и был готов к перезапуску. Поэтому часто считается 20 миллисекунд- стандарт на период импульсов. Хотя и 5-10 обычно работает.

Всё это относится к "старым",  "аналоговым" сервам.
А как работают " цифровые" - не знаю и пока не хочу знать.... Цены у них не гуманные.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

SU-27-16 пишет:

 0-1023

Опять увидел призрак Leshak a... ;) Здоров ли? Или вырос до 32-ух бит?

P.S.  А как цифры в зелёный цвет красить? А  буквы как?

 

wgaint
Offline
Зарегистрирован: 15.03.2015

Немного обновил код. Попробовал избежать лишних дрожаний мотора и избыточного опроса потенциометра.

#include <Servo.h> 
 
Servo myservo;  
int valnew; // переменная для приема данных
int val = 0;   // переменная для отправки на серв
 
void setup() 
{ 
} 
void loop() 
{ 
valnew = analogRead(0); // считываем уровень на 0-м пине 0-1023
valnew = valnew/10; //округляем 
if (valnew != val) //если значение потенциометра изменилось
{
myservo.attach(5); //включаем серв на 5-м пине
val = valnew; //записываем новое значение управляющего сигнала
//всего 7 положений сервы от 0 до 90 градусов:
if (val <= 13) {myservo.write(0);}
else if (val > 13 && val <= 29  ) {myservo.write(15);}
else if (val > 29 && val <= 44) {myservo.write(30);}
else if (val > 45 && val <= 58) {myservo.write(45);}
else if (val > 58 && val <= 74) {myservo.write(60);}
else if (val > 75 && val <= 88) {myservo.write(75);}
else if (val > 90){myservo.write(90);}
delay(500);                       // ждем чтобы серв мог докрутить из крайнего положения в крайнее 90 градусов
myservo.detach() //отключаем чтобы не дрожал
} 
delay(500); //считывание с потенциометра раз в пол секунды 
}

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

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Вы можете сразу получать с аналогового входа чёткие значения от 0 до 7, смещением результата чтения на 7 бит, останутся соответсвенно 3 бита для 8 градаций.  analogRead(0)>>7.  Дальнейший код можно облегчить от двойного сравнения. (if val == 0;  и так далее)  Или перейти на свитч-кейс.

vvadim
Offline
Зарегистрирован: 23.05.2012

зачем всё это, если у сервы нормальное питание и сама не убитая то стандартный пример knob работает на ура

wgaint
Offline
Зарегистрирован: 15.03.2015

С использованием сдвига код:

#include <Servo.h> 
 
Servo myservo;  
int val; 
int valold = 0;   
 
void setup() 
{ 
myservo.attach(5);   
Serial.begin(9600);
} 
 
 
void loop() 
{ 

val = analogRead(0)>>7; // считываем уровень на 0-м пине. Сдвигаем лишние 7 бит.
//Оставшиеся 3 бита дают нам ряд от 0 до 7.
if (val != valold) //если потенциометр трогали 
{ 
valold = val;
Serial.println(val); // отправляем положение потенциометра на терминал
val = val*13; // рассчитываем угол поворота
myservo.write(val);
delay(500); 
}
delay(500); // опрос потенциометра 2 раза в секунду
} 

Ну и контороль на терминал