Прерывание и сервы

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

Есть две сервы управляемые потенциометрами и кнопками. Хочется одновременной работы серв. С потенциометрами всё нормально. А вот при движении серв в запомненное положение сначала движется одна , потом вторая. Почитал форум и гугл - нужны прерывания. А как и с чего начать не знаю. Выкладываю часть кода. Нужно при нажатии кнопки 7 обе сервы синхронно переводились в сохранённые положения, а при нажатии кнопки 8 возвращались обратно.

 

#include  <Servo.h>
#include <EEPROM.h>

Servo myservo1;
Servo myservo2;

int button1Pin = 2;            // save 1 
int button2Pin = 3;            // load 1 
int button3Pin = 4;            // motion 1
int button4Pin = 5;            // save 2
int button5Pin = 6;            // load 2
int button6Pin = 7;            // motion 2
int button7Pin = 8;            // load 1-2
int button8Pin = 11;           // motion 1- 2
int inputMode1 = 1;
int inputMode2 = 1;

int val;                       
int val2;
                               
int button1State;              
int button2State;
int button3State;
int button4State;
int button5State;              
int button6State;
int button7State;
int button8State;
int pot1pin = 0;
int pot2pin = 0;
int val3;
int val4;
int addr = 0;
byte value;
int pos = 0;
void setup() {  
  pinMode(button1Pin, INPUT);   
  pinMode(button2Pin, INPUT);
  pinMode(button3Pin, INPUT);
  pinMode(button4Pin, INPUT);
  pinMode(button5Pin, INPUT);   
  pinMode(button6Pin, INPUT);
  pinMode(button7Pin, INPUT);
  pinMode(button8Pin, INPUT); 
 
  myservo1.attach(9);
  myservo2.attach(10);  
  Serial.begin(9600);   
}
void loop(){  
  if(inputMode1) {
  val3 = analogRead(pot1pin);           
  val3 = map(val3, 0, 1023, 0, 179);   
  myservo1.write(val3);                 
  delay(15);
  }  
   if(inputMode2) {
  val4 = analogRead(pot2pin);           
  val4 = map(val4, 0, 1023, 0, 179);   
  myservo2.write(val4);                 
  delay(15); 
   }
  if(button1State == HIGH) {                        // button 1 save1        
  EEPROM.write(addr, val3);
  EEPROM.write(25, 1); 
  delay(100);  
  } 
 
  if(button2State == HIGH && EEPROM.read(25) == 1) {             // button 2  load1  
  inputMode1=0;    
  value = EEPROM.read(addr);
  delay(100);    
    for(pos = val3; pos < value; pos += 1)                    
  {                                                            
    myservo1.write(pos);                                       
    delay(30);                                                 
  } 
    for(pos = val3; pos > value; pos-=1)                     
  {                                
    myservo1.write(pos);                                        
    delay(30);                                                
  }  
  }  
  if(button4State == HIGH) {                 // button 3 motion1 
  inputMode1=1;  
    for(pos = value; pos < val3; pos += 1) 
  {                                  
    myservo1.write(pos);              
    delay(50);                       
  } 
    for(pos = value; pos > val3; pos-=1)    
  {                                
    myservo1.write(pos);             
    delay(50);                       
  }
  } 
  if(button5State == HIGH) {                                    // button 4 save2        
  EEPROM.write(addr, val4);
  EEPROM.write(55, 1); 
  delay(100); 
  }
  if(button6State == HIGH && EEPROM.read(55) == 1) {             // button 5  load2 
  inputMode2=0;    
  value = EEPROM.read(addr);
  delay(100);    
    for(pos = val4; pos < value; pos += 1)                     
  {                                                            
    myservo2.write(pos);                                     
    delay(30);                                                 
  } 
    for(pos = val4; pos > value; pos-=1)                       
  {                                
    myservo2.write(pos);                                        
    delay(30);                                                 
  }  
  } 
  if(button8State == HIGH) {                                      // button 6 motion2    
  inputMode2=1;  
    for(pos = value; pos < val4; pos += 1) 
  {                                  
    myservo2.write(pos);              
    delay(50);                       
  } 
    for(pos = value; pos > val4; pos-=1)    
  {                                
    myservo2.write(pos);             
    delay(50);                       
  }  
  }  
  if(button7State == HIGH && EEPROM.read(25) == 1, EEPROM.read(55) == 1) {   //load 1-2 
    inputMode1=0;
    inputMode2=0;    
   value = EEPROM.read(addr);    
    for(pos = val3; pos < value; pos += 1)                     
  {                                                           
    myservo1.write(pos);                                        
    delay(30);                                                 
  } 
    for(pos = val3; pos > value; pos-=1)                       
  {                                
    myservo1.write(pos);                                        
    delay(30);                                                 
  }
   for(pos = val4; pos < value; pos += 1)                    
  {                                                            
    myservo2.write(pos);                                         
    delay(30);                                                  
  } 
    for(pos = val4; pos > value; pos-=1)                      
  {                                
    myservo2.write(pos);                                        
    delay(30);                                                 
  }
  }

  if(button8State == HIGH) {                                      //  motion 1-2    
  inputMode1=1;  
  inputMode2=1;  
    for(pos = value; pos < val3; pos += 1) 
  {                                  
    myservo1.write(pos);              
    delay(50);                       
  } 
    for(pos = value; pos > val3; pos-=1)    
  {                                
    myservo1.write(pos);             
    delay(50);                       
  }   
   for(pos = value; pos < val4; pos += 1) 
  {                                  
    myservo2.write(pos);              
    delay(50);                       
  } 
    for(pos = value; pos > val4; pos-=1)    
  {                                
    myservo2.write(pos);             
    delay(50);                       
  }
  }
  }  
  



    
   





Может кто то поможет? 

Внутренние или наружные прерывания, какие таймеры использовать, пример кода.

 

step962
Offline
Зарегистрирован: 23.05.2011

 Я думаю, прерывания вам не помогут.

Ибо для стоящей перед вами задачи они не нужны.

Требуется изменение подхода к решению проблемы движения двух сиервоприводов.

Как вы делаете сейчас? Отрабатываете ПОЛНОЕ движение одной сервой, затем ПОЛНОЕ движение другой. В двух циклах:


for(pos = val1; pos < val3; pos += 1)                    
{                                                          
   myservo1.write(pos);                                       
   delay(30);                                                
}

for(pos = val2; pos < val4; pos += 1)                    
{                                                          
   myservo2.write(pos);                                       
   delay(30);                                                
}

а надо в одном:

int done=0;
pos1=val1;
pos2=val2;
while(done<3) {
// делаем шажок первой сервой ...
  if(pos1<val3) {                                                
    myservo1.write(pos1);                                       
    delay(30);                                                
    pos1++;
  }
  else done = done | 1;                                               
//  ... затем второй
  if(pos1<val4) {                                                
    myservo2.write(pos2);                                       
    delay(30);
    pos2++;
  }
  else done = done | 2;                                               
}

как-то так ...

leshak
Offline
Зарегистрирован: 29.09.2011

 А зачем вообще эти микрошаги? В постановке задачи цели "снизить скорость серв" - не упоминалась. А без этого можно сразу серве говорить "конечную позицию". И она пойдет крутится. В отличие от степпера серва не блокирует поток. Мы выдали pwm а дальше она сама пытается достичь с ним равновесия.

Вообщем тут случай когда "мудрение" во вред.

myservo1.write(newPos1);
myservo2.write(newPos2);
delay(200);// время за которое обе сервы успеют повернутся. Если блокировать скетч до поворота серв в позицию - не нужно, можно вообще выкинуть эту строку.

 

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

leshak пишет:

 А зачем вообще эти микрошаги? В постановке задачи цели "снизить скорость серв" - не упоминалась. А без этого можно сразу серве говорить "конечную позицию". И она пойдет крутится.

Обычно оно так. Но на практике есть механика, которая имеет массу, чтобы не расшатывать механику, снижают скорость, если снижение нежелательно, делают ускорение/торможение. IMHO.

maksim
Offline
Зарегистрирован: 12.02.2012

leshak пишет:

 А зачем вообще эти микрошаги? В постановке задачи цели "снизить скорость серв" - не упоминалась. А без этого можно сразу серве говорить "конечную позицию". И она пойдет крутится. В отличие от степпера серва не блокирует поток. Мы выдали pwm а дальше она сама пытается достичь с ним равновесия.

Вообщем тут случай когда "мудрение" во вред.

myservo1.write(newPos1);
myservo2.write(newPos2);
delay(200);// время за которое обе сервы успеют повернутся. Если блокировать скетч до поворота серв в позицию - не нужно, можно вообще выкинуть эту строку.

 

Запоминание позиций серво
 

leshak пишет:

Я бы делал так:
Выкинул нафиг val4, писал в память именно val3. В том виде какое оно получается после применения функции map, тогда при чтении с ним тоже ничего мудрить не нужно. Достал и, как есть, отправил на серву.
Скорость сервы делал бы так: завел переменную в которую запоминаю "где сейчас серва". Когда нужно повернуть в новую позицию - вычисляем разницу между нужным положением, и текущим. И поворачиваем "по чуть-чуть", с паузами. Например сечас она на 20-ти, а нужно 50. Значит даем командау 25, пауза, 30, пауза, 35, пауза, 40, пауза, 45, пауза, 50. При достаточно малом шаге и небольших паузах - будет эффект плановсти движение. Неторопливого.

leshak пишет:

Вообщем примерно так:
 

#define SERVO_STEP 5 // шаг сервы в градусах, на сколько поворачиваем "за один раз"
#define STEP_DELAY 200 // пауза между шагами в миллисекундах


int cPos=0;// текущие положение сервы

void setServo(int newPosition){
  myservo.write(newPosition); // выкрутили серву 
  cPos=newPosition; // запомнили положение сервы
}

void setServoSlow(int newPosition){
  if(newPosition==cPos)return ;// серва уже стоит в правильно положении, ничего не делаем

  if(newPosition>cPos){ // если нужно повернуть на больший градус
    for(int i=cPos;i<newPosition;i+=SERVO_STEP) {
      myservo.write(i);// шагнули
      delay(STEP_DELAY);// пауза
    }
  } 
  else { //если нужно на меньший угол повернуть, то же самое, только по чуть-чуть уменьшаем угол
    for(int i=cPos;i>newPosition;i-=SERVO_STEP){
      myservo.write(i);// шагнули
      delay(STEP_DELAY);// пауза
    }
  }

  setServo(newPosition);// запомнили новое положение и довернули, если шаг был не кратен разнице позиций
}

 

И везде в скетче, вместо myServo.write, дальше используем setServo(...) если нужно быстро установить значение сервы и setServoSlow() если медленно.

SERVO_STEP, и STEP_DELAY - подбираем на глаз. Что-бы была медленность, но не было видимой "дергнанности"

 

leshak
Offline
Зарегистрирован: 29.09.2011

 2Maksim: а чем смысл цитат? Пытаетесь подловить на противоположных высказываниях? Не вышло :)

leshak пишет:

А зачем вообще эти микрошаги? В постановке задачи цели "снизить скорость серв" - не упоминалась.

Тут ставилась задача "одновременности вращения", а в той ветки человек хотел "снизить скосроть". Логично что для разных задач используются разные решения? Микрошаги еще могут потребоваться если нужно что-бы сервы выходили на заданную позицию одномоментно. Даже если одной, для этого, нужно повернутся на 90 градусов, а другой на 5-ть. 

Но, обычно, стараются не усложнять задачу до тех пор пока "по другому никак". Так что если можно обойтись без микрошагов, пока нет 100% уверенности в их необходимости - лучше обойтись.

Кстати даже с микрошагами, в коде который привел step62, сообщение #1, второй скетч. delay тоже можно сделать "общим", что-бы они крутились "ну вообще одновременно". 

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

Микрошаги нужны (сейчас соберу схему и попробую в одном цикле) .

maksim
Offline
Зарегистрирован: 12.02.2012

Просто напомнить, что проэкт тот же. 

leshak
Offline
Зарегистрирован: 29.09.2011

vvadim пишет:

Микрошаги нужны (сейчас соберу схему и попробую в одном цикле) .

Вы, в стартовом посте употребили слово "синхронно". Имелось ввиду "просто могут крутится одновременно" или "должны начать и ЗАКОНЧИТЬ" движение одновременно?

И еще сервы поворачиваются занимают одну и ту же позицию или возможны ситуации когда "одна поворачивается с 10 до 40, а другуя с 30 до 180"?

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

Сервы поворачиваются на разные углы (каждая в зависимости от сохранённого положения и настоящего) и в любом направлении (по часовой стрелке, против, навстречу друг другу).

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

leshak
Offline
Зарегистрирован: 29.09.2011

 Попробуйте вот такой скетч:

#include  <Servo.h>


#define FULL_TIME 5000 // время за которое серва успевает повернутся на 180

Servo myservo1;
Servo myservo2;


boolean fl=false;
void setup(){
  
  myservo1.attach(9);
myservo2.attach(10); 
  
  myservo1.write(180);  //поворачиваем одну серву, что-бы рассинхронить их
  delay(FULL_TIME);
}

void loop(){
  // 
  if(fl){
    myservo1.write(0);
    myservo2.write(180);
  } else {
    myservo1.write(180);
    myservo2.write(0);
  }
  
    delay(FULL_TIME);// даем время на поворот
  fl=!fl; // меняем направление
}

На нем сервы движутся одновременно?

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

Да, сервы движутся одновременно.

В моём случае нужно одновременно прочитать из памяти запомненные положения серв и одновременно перевести их в эти положения. 

leshak
Offline
Зарегистрирован: 29.09.2011

 Ну... так в чем затруденение? Читайте два значения, делай два myservoX.write(NewValueX); И только потом общий, для них обоих, delay(X). Главное не втыкать делей между servo1.write и servo2.write и будут они одновременно ехать.

В сообщении #2 я же уже писал про это.

Или пример из предыдущего посмотрите 

myservo1.write(0);
myservo2.write(180);

вместо 0 и 180, подставте прочитанные из памяти значения - вот и пойдут они одновременно поворачиватся.

Другое дело что остановятся не обязательно одновременно. Но это уже следующий этап, тут уж "микрошаги" вкручивать" нужно будет.

leshak
Offline
Зарегистрирован: 29.09.2011

 Вот функция для кручения двух серв синхронно микрошагами. Начинаю и "кончают" одновременно.

 

#define STEP_DELAY 50 // пауза между шагами
#define STEP_NUMBERS 10 // на какое количество шагов разбивается каждое движение



int cPos1=0;// текущие положение первой сервы
int cPos2=0;// текущие положение второй сервы


void setup(){
  
  
  setTwoServoSlow(45,0); // первую поворачиваем на 45, вторая стоит
  
   delay(5000); //постоим
    setTwoServoSlow(10,60); // крутим обе одновременно одну в 10, вторую на 60
  
     delay(5000);
     setTwoServoSlow(180,90); // крутим обе одновременно одну в 180, вторую на 90
}


void setTwoServoSlow(int newPos1,int newPos2){
   for(int step=0;step<STEP_NUMBERS;step++){
     // вычисляем позиции серв для этого шага
      int pos1=map(step,0,STEP_NUMBERS-1,cPos1,newPos1);
      int pos2=map(step,0,STEP_NUMBERS-1,cPos2,newPos2);
      
      // устанавливаем позиции
      myServo1.write(pos1);      
      myServo2.write(pos2);

      delay(STEP_DELAY); // даем сервам повернутся
   }
   
   // запомнили новую позицию сервы
   cPos1=newPos1;
   cPos2=newPos2;
}




void loop(){
}

 

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

Не получается . Всё равно движение по очереди.

 if(button9State == HIGH ) {               
  EEPROM.read(25) == 1;
  EEPROM.read(55) == 1;    
    inputMode1=0;
    inputMode2=0;
    
   value1 = EEPROM.read(addr1);
   value2 = EEPROM.read(addr2);
  // myservo1.write(value1);
  // myservo1.write(value2);
  //delay(100);
  
    for(pos1 = val3; pos1 < value1; pos1 += 1)  {                                                          
    myservo1.write(pos1);                                 
    
  }
    for(pos2 = val4; pos2 < value2; pos2 += 1)  {                                                          
    myservo2.write(pos2);                                  
                                              
  }     
   
    for(pos1 = val3; pos1 > value1; pos1-=1)                       
  {                                
     myservo1.write(pos1);                                 
                                                   
  }   
    for(pos2 = val4; pos2 > value2; pos2-=1)                      
  {                                
    myservo2.write(pos2); 
  
  }
  
  }

 

leshak
Offline
Зарегистрирован: 29.09.2011

 > Всё равно движение по очереди.

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

По вашему коду, вы вналчае пробежались по всем шагам для первой сервы (и естественно в этот момент она начала крутится), ПОТОМ по всем шагам для второй. Я уже три примера дал где между myservo1.write и myservo2.write ничего нет. Если вы хотите одновременонсти, так и выдавайте команды на поворот одновременно.

Выкинте все после одинадцаттой строчки, в десятой поправте myservo1 на myservo2 и в 11-той можете увеличить delay что-бы обе точно успели довернутся. Убедитесь что они поворачиваются одновременно, в значения прочитанные из памяти. А уж потом танцуйте дальше (скорость, синхронность и т.п.) Раз не получается - идите инкрементными шагами. Не нужно сразу все пытаться сделать и крутить одновременно, и память читать, и кнопки обрабатывать....

Вначале одновременно закрутили, потом то же самое но прочитанное из памяти, потом то же самое но читать из памяти по кнопке..., потом "снизить скорость""

P.S. И выше я уже дал готовую функцию которую можно использовать.

leshak
Offline
Зарегистрирован: 29.09.2011

leshak пишет:

ну если вы крутите их по очереди, то естественно они и крутятся по очереди.

По вашему коду, вы вналчае пробежались по всем шагам для первой сервы (и естественно в этот момент она начала крутится), ПОТОМ по всем шагам для второй.

Кстати ровно о том же вам говорил STEP962 много постов назад.

STEP962 пишет:

Как вы делаете сейчас? Отрабатываете ПОЛНОЕ движение одной сервой, затем ПОЛНОЕ движение другой.

Но вы почему-то проигнорировали его пост.

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

step962 пишет:

 Я думаю, прерывания вам не помогут.

Ибо для стоящей перед вами задачи они не нужны.

Требуется изменение подхода к решению проблемы движения двух сиервоприводов.

Как вы делаете сейчас? Отрабатываете ПОЛНОЕ движение одной сервой, затем ПОЛНОЕ движение другой. В двух циклах:


for(pos = val1; pos < val3; pos += 1)                    
{                                                          
   myservo1.write(pos);                                       
   delay(30);                                                
}

for(pos = val2; pos < val4; pos += 1)                    
{                                                          
   myservo2.write(pos);                                       
   delay(30);                                                
}

а надо в одном:

int done=0;
pos1=val1;
pos2=val2;
while(done<3) {
// делаем шажок первой сервой ...
  if(pos1<val3) {                                                
    myservo1.write(pos1);                                       
    delay(30);                                                
    pos1++;
  }
  else done = done | 1;                                               
//  ... затем второй
  if(pos1<val4) {                                                
    myservo2.write(pos2);                                       
    delay(30);
    pos2++;
  }
  else done = done | 2;                                               
}

как-то так ...

Я этот вариант сразу попробовал, но не работает. Может я что то напутал.

leshak
Offline
Зарегистрирован: 29.09.2011

 >Я этот вариант сразу попробовал, но не работает. Может я что то напутал.

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

Его код выглядит, вообщем-то рабочим (если только вы не добавили, при пробе, к нему все что только возможно. И чтение, и кнопки и т.п.). Но даже если он где-то чуток ошибся в коде, текстом он вам вполне правильно объяснил ошибочность вашего подхода. А вы потом повторяли опять ту же самую ошибку.

P.S. И кстати вы, не всегда, но довольно частно, наступаете на одни и те же грабли. Вам дают какой-то код, а вы либо просто отмалчиваетесь/игнорируете, либо говорите "не работает" и ждете пока вас переспросят подробности (а ведь могут и не переспросить, а просто забить). Так вы резко понижаете шансы того что кто-то сможет вам помочь. Хорошо что хоть код который запускать пробовали уже начали давать без намека :)

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

В варианте STEP962  у меня всё зависло. Но его подход я понял и спасибо ему за это. Мне как чайнику просто тяжело многие вещи реализовать 

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

 Адаптировал код leshak из поста #13 - заработало!!!! Спасибо за помощ.

if(button9State == HIGH ) {   
   inputMode1=0;
   inputMode2=0;    
   EEPROM.read(25) == 1;
   EEPROM.read(55) == 1;  
   value1 = EEPROM.read(addr1);
   value2 = EEPROM.read(addr2);
   for(int step=0;step<STEP_NUMBERS;step++){
   pos1 = value1;
   pos2 = value2;
   pos1=map(step,0,STEP_NUMBERS-1,val3,value1);
   pos2=map(step,0,STEP_NUMBERS-1,val4,value2);
   myservo1.write(pos1);
   myservo2.write(pos2);   
   delay(STEP_DELAY);   
   }   
   }