Синхронизация 2 колес у машинки

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Всем доброго, друзья! Продолжаю долго и упорно пилить свою машинку радиоуправляемую (робо-хоккей).

В целом всё ок- но никак не могу сделать синхронизацию 2 колес-чтобы машинка ехала строго вперед.

Переписал код, отвечающий за синхронизацию - уже раз 100 наверное :-))). И когда уже совсем задолбался-пишу сюда...

В общем, суть такая: на каждом колесе стоит 12-ти сегментный энкодер и оптический цифровой датчик-который это дело считывает. 

С какими трудностями столкнулся:

1) когда еще без попыток сихнронизации - просто сделал вывод на экран скоростей 2 двигателей - то стало видно, что скорость кардинально скачет на одном колесе и на соседних срабатываниях. Типичные прыжки  0-25-63-0 и т.д. То есть, система видит малейшие неточности в изготовлении колеса и даже малейшую "восьмерку" на нем.

Как боролся: брал 4 срабатывания- суммировал и делил на 4. В итоге получал некую среднюю скорость;

 

2) Много всего прочитал про прерывания и делал по разному:

вариант а): функция, вызываемая по прерыванию - только регистрирует время, когда оно произошло, а коррекция скорости происходит уже в главном методе loop (так рекомендуют делать);

вариант б): функция корректирует скорости двигателей - мне этот вариант кажется более простым и логичным- но с ним вылазит ошибка - система вываливается с ошибкой.

 

Пишет "Guru Meditation Error: Core  1 panic'ed (Coprocessor exception)"

Нашел примерно в суть этой ошибки- в том, что постоянно перезаписывается переменная и что то там с кучей.

Пробовал менять тип переменной, в которую пишется время (uint32_t)- на любой другой - не работает.

Короче говоря, по итогам всех мытарств- "поможайте чем можете" :-))))

 

P.S. корректировку скоростей веду по-умному, с помощью ПИД регулятора. Пытался применить известный GyverPID - но он у меня не завелся, по причине, что у меня Windows 7. А ему надо Windows 10 и более свежую Arduino IDE.

Вот сам код-вернее выжимки из него, относящиеся к вопросу):

 

  String state; //сюда будет писаться состояние, т.е. куда едет машинка в данный момент
 
  volatile long lasttime1 = 0;
  volatile long lasttime2 = 0;

  //Куда подключены оптические датчики энкодера:
  int SensorPin1 = 13;
  int SensorPin2 = 14;

  // подключаем контакты оптических датчиков к пину, в режим «INPUT»:
     pinMode (SensorPin1, INPUT);
     pinMode (SensorPin2, INPUT);

  
  // подключаем реакцию на прерывания - к пинам датчиков:
     attachInterrupt(digitalPinToInterrupt(SensorPin1), sensor_test, HIGH);   
     attachInterrupt(digitalPinToInterrupt(SensorPin2), sensor_test2, HIGH);   

Функция 1 датчика:
 
//ПАМЯТКА: тут перепутаны pwmChannel: по идее - первому датчику должен соответствовать pwmChannel, 
// а второму- pwmChannel2. Но нет! Всё наоборот: Sensor1 - pwmChannel2, Sensor2 - pwmChannel, 
//причина-мой локальный бардак :-)))

// Функция, запускающаяся при возникновении прерывания - с датчика 1:

void sensor_test ()
{
  detachInterrupt(SensorPin1);
  lasttime1 = millis();

    if (state.equals ("Forward")) //анализ ведем только для случая, если едем вперед
       {
           
          if (lasttime1>lasttime2)
          {
             ledcWrite(pwmChannel2, computePID (lasttime1,lasttime2, 1, 0, 0, 10, 0, 55)); //замедляем скорость быстрого двигателя. Пока все значения выставлены в ноль-чтобы настроить из ПИД-а хотя бы П  //ПАМЯТКА: 255 - максимум оборотов
          }
          else
          {
             ledcWrite(pwmChannel, computePID(lasttime2, lasttime1, 1, 0, 0, 10, 0, 55)); //замедляем скорость быстрого двигателя. Пока все значения выставлены в ноль-чтобы настроить из ПИД-а хотя бы П   //ПАМЯТКА: 255 - максимум оборотов 
          }


      
        }

  attachInterrupt(digitalPinToInterrupt(SensorPin1), sensor_test, HIGH);
}

 

Функция 2 датчика:
 
// Функция, запускающаяся при возникновении прерывания - с датчика 2:

void sensor_test2 ()
{
  detachInterrupt(SensorPin2);
  lasttime2 = millis();


    if (state.equals ("Forward")) //анализ ведем только для случая, если едем вперед
       {
           
          if (lasttime1>lasttime2)
          {
             ledcWrite(pwmChannel2, computePID (lasttime1,lasttime2, 1, 0, 0, 10, 0, 55)); //замедляем скорость быстрого двигателя. Пока все значения выставлены в ноль-чтобы настроить из ПИД-а хотя бы П   //ПАМЯТКА: 255 - максимум оборотов 
          }
          else
          {
             ledcWrite(pwmChannel, computePID(lasttime2, lasttime1, 1, 0, 0, 10, 0, 55)); //замедляем скорость быстрого двигателя. Пока все значения выставлены в ноль-чтобы настроить из ПИД-а хотя бы П   //ПАМЯТКА: 255 - максимум оборотов           
          }

      
        }

  attachInterrupt(digitalPinToInterrupt(SensorPin2), sensor_test, HIGH);
}

 

Код ПИД регулятора:

int computePID(float input, float setpoint, float kp, float ki, float kd, float dt, int minOut, int maxOut) {
  float err = setpoint - input;
  static float integral = 0, prevErr = 0;
  integral = constrain(integral + (float)err * dt * ki, minOut, maxOut);
  float D = (err - prevErr) / dt;
  prevErr = err;
  return constrain(err * kp + integral + D * kd, minOut, maxOut);
}

 

 

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Запостил и тут же увидел как минимум одну ошибку-у меня переменная времени заявлена как uint32_t  -а я кидаю ее на вход ПИД регулятора. А он принимает float. Может в этом глюк. Но это частности. Даже когда не глючит-никак не могу сделать синхронизацию колес почему то. Вроде тупая задача- но никак... :-)))

В строках 03-04 -в первом куске кода ошибка - там у меня обычно стояло 

  volatile uint32_t lasttime1 = 0;
  volatile uint32_t lasttime2 = 0;

Один черт неправильно :-). Надо попробовать на float поменять.

P.S. забыл сказать -система построена на ESP32.

kalapanga
Offline
Зарегистрирован: 23.10.2016

Извиняюсь, что ответ не по теме, но боюсь, что по теме и не будет с такой постановкой вопроса. К чему приведены эти огрызки кода, да ещё с комментариями типа "ой, тут что-то перепутано", "а тут временно подставлено", "а тут ошибка". Ладно хоть в последней строчке не забыли сказать про то, что это ESP32!

Напишите минимальный скетч с вашим способом коррекции хода, в котором машинка при включении просто едет вперёд. Без какого либо внешнего управления или других действий совсем. По нему может кто чего и подскажет. Лучше без библиотек Гайвера, иначе к нему и пошлют!

Logik
Offline
Зарегистрирован: 05.08.2014

//суть этой ошибки- в том, что постоянно перезаписывается переменная и что то там с кучей.

очень распастраненная проблема, когда решите - отпишитесь здесь обязательно! Вы спасете ИТ-индустрию.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Машинка симпатичная!

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Спасибо!

Никто дельного не написал по поводу синхронизации-сел сам. В 101-й раз пытаться допилить :-)))

b707
Offline
Зарегистрирован: 26.05.2017

mu_ssina пишет:

Никто дельного не написал по поводу синхронизации-сел сам. В 101-й раз пытаться допилить :-)))

почему же, в сообщении #1 вам вполне по делу написали. Задавайте вопросы нормально, приводите полный код - тогда будет хоть какая-то надежда на ответ.

А сейчас я все ваши вкладки с кодом даже открывать не стал, открыл первую - мне хватило

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

обижаться не надо.

от правильной постановки вопроса зависит  получение ответа .

ну и программу показать отформатированную и со строками.

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

mu_ssina
Offline
Зарегистрирован: 30.08.2013

vvadim пишет:

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

 

Всё-решил вопрос. Вопрос оказался даже не совсем в области алгоритмов: тупо перепутаны датчики крест-накрест в программе (мотор1 регулируем, ориентируясь на датчик2). 

А насчет гайвера кстати в первый раз слышу. А почему так? хреново пишет или что? 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

mu_ssina пишет:

А насчет гайвера кстати в первый раз слышу. А почему так? хреново пишет или что? 

Видите ли, Гайвер - талантливый блогер, но весьма посредственный программист.

Более того, доведение чего-то "до ума" требует некоторого времени, а блогеру нужно публиковать очередной репортаж.

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

http://arduino.ru/forum/proekty/konstruktsiya-vykhodnogo-dnya-prostoi-sp...

Первоначальный код действительно был написан за один выходной - можно посмотреть, тема создана в субботу вечером 1 сентября. А финальный код размещен только 26 октября, т.е. на "доведение до ума" потребовалось почти 2 месяца. Так вот блогер бы "доводить до ума" не стал, ограничившись первоначальным вариантом (в лучшем случае), а вместо этого занялся бы следующим проектом. В конце концов, чтобы снять видео совсем не обязателен работающий (а тем более - надежно работающий) проект. Достаточно лишь некоторых признаков работоспособности, из которых потом путем монтажа можно будет склеить любое видео.
mu_ssina
Offline
Зарегистрирован: 30.08.2013

Ок, понял...Спасибо за развернутый ответ!

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

andriano пишет:

Видите ли, Гайвер - талантливый блогер, но весьма посредственный программист.

С первым утверждением не вполне соглашусь, есть и поживее блохеры. Со вторым спорить не стану. Тут доверяю мнению программистов, поскольку сам, к сожалению, еще не дорос до права иметь свое в этой сфере. Но надо отдать ему должное, как популяризатору программизма среди малообразованного народонаселения:) Между сайтом ардуино.СС с кратким перечнем функций "языка wire" и книгами трупа страуса и Шилдта лежит огромный информационный вакуум. А вселенная, как известно, не терпит пустоты.