Независимый поток данных от энкодера

Тема в разделе "Arduino & Shields", создана пользователем Константин_Ли, 24 июн 2019.

Метки:
  1. Использую в проекте абсолютный энкодер KY-040 цепляю его на 2 и 3 бинарный и использую прерывания для обработки. Энкодер идёт к dc мотору.
    Также, к ардуинке подключен gps модуль neo 6m и с определенной периодичностью идёт его опрос.
    Проблема же заключается в том, что когда я прогоняю мотор по кругу без gps модуля и смотрю на показания энкодера, я получаю одни цифры, а когда прогоняю то же самое только с опросом gps'ки, то выходят совсем другие значение (гораздо меньше). Видимо обмен данных с neo 6m каким-то образом влияет на частоту прерываний энкодера, но не пойму как. Помогите пожалуйста, как можно сделать так, чтобы и энкодер работал стабильно, и информация с gps поступала корректно?

    Вот весь код
    Код (C++):
    #include <Button.h>

    #include <TinyGPS++.h> //gps libraries
    #include <SoftwareSerial.h>

    #include <Cotsp.h>

    #include "GyverEncoder.h"

    Button BL(8);  //L
    Button BS(9);  //S
    Button BR(10); //R

    #define DIR 5
    #define PWM 6

    #define CLK 3
    #define DT 2

    //gps objs
    static const int RXPin = 12, TXPin = 11;
    static const uint32_t GPSBaud = 9600;
    TinyGPSPlus gps;
    SoftwareSerial ss(RXPin, TXPin);

    Cotsp cotsp;

    bool dr = true;
    int rp = 0; int heading;

    Encoder enc1(CLK, DT, 100);

    bool FS = true;
    bool mode = true;

    bool onSunrise = false;

    void isr() {
      enc1.tick();  // отработка в прерывании
    }

    static void updateGps() {
      while (ss.available())
        gps.encode(ss.read());
    }

    static void updateEnc() {
      enc1.tick();
      if (dr) rp++;
      else rp--;
      heading = rp / 173.81;
      if (heading >= 360) {
        rp = 0;
        heading = 0;
      }
      else if (heading < 0) {
        heading = 360 + heading;
      }
    }

    static void smartDelay(unsigned long ms) {
      unsigned long start = millis();
      do {
        updateGps();
      } while (millis() - start < ms);
    }

    static void printInf() {
      if (mode)
        Serial.println("Mode: following");
      else
        Serial.println("Mode: returning");
      Serial.println("Year: " + String(int(gps.date.year())) + "; month: " + String(int(gps.date.month())) + "; day: " + String(int(gps.date.day())) + "; hour: " + String(gps.time.hour()) + "; minute: " + String(gps.time.minute()) + "; hour.minute: " + String(gps.time.hour() + gps.time.minute() / 60.));
      Serial.println("Your coordinates: " + String( gps.location.lat()) + " " + String( gps.location.lng()));
      Serial.println("Azimuth (degrees): " + String(cotsp.azimuth));
      Serial.println("Altitude (degrees): " + String(cotsp.altitude));
      Serial.println("Sunset Time: " + String(cotsp.SunsetTime));
      Serial.println("Sunrise Time: " + String(cotsp.SunriseTime));
      Serial.println("Sunset azimuth: " + String(cotsp.SunsetAzimuth));
      Serial.println("Sunrise azimuth: " + String(cotsp.SunriseAzimuth));
      if (dr)
        Serial.println("Direction: right");
      else
        Serial.println("Direction: left");
      Serial.println("Heading: " + String(heading) + "; RP: " + String(rp));

    }

    static void RR() {
      dr = true;
      digitalWrite(DIR, HIGH);
      digitalWrite(PWM, LOW);
    }
    static void RL() {
      dr = false;
      digitalWrite(DIR, LOW);
      digitalWrite(PWM, HIGH);
    }
    static void SR() {
      digitalWrite(DIR, HIGH);
      digitalWrite(PWM, HIGH);
    }

    static bool checkGPS() {
      if (gps.charsProcessed() < 10)
        return false;
      return true;
    }

    static bool sw(double phi, double destphi) {
      double delta = destphi - phi;
      if (0 <= delta and delta <= 180 or - 360 <= delta and delta <= -180) {
        return true; //R
      }
      else {
        return false; //L
      }
    }

    void following() {
      updateEnc();


      while (!checkGPS()) {
        Serial.println("satellite search..");
        smartDelay(1000);
      }

      cotsp.UpdateSunCoordinates(gps.date.year(), gps.date.month(), gps.date.day(), gps.location.lat(), gps.location.lng(), gps.time.hour() + (gps.time.minute() / 60.));
      if (FS) {
        cotsp.UpdateSunsetCoordinates(gps.date.year(), gps.date.month(), gps.date.day(),  gps.location.lat(), gps.location.lng(), gps.time.hour() + (gps.time.minute() / 60.));
        cotsp.UpdateSunriseCoordinates(gps.date.year(), gps.date.month(), gps.date.day(),  gps.location.lat(), gps.location.lng(), gps.time.hour() + (gps.time.minute() / 60.));
        FS = false;
      }
      cotsp.azimuth = 1;
      dr = sw(heading, cotsp.azimuth);

      if (heading == int(cotsp.azimuth)) {
        SR();
        //mode = false;//!!!!!!
      }
      else if (dr) {
        RR();
      }
      else {
        RL();
      }

      if (cotsp.SunsetTime <= (gps.time.hour() + (gps.time.minute() / 60.))) {
        SR();
        mode = false;
      }

      while (ss.available())
        gps.encode(ss.read());

      printInf();
    }

    void returning() {
      if (onSunrise) {
        if (cotsp.SunriseTime <= (gps.time.hour() + (gps.time.minute() / 60.)))
          mode = true;
        smartDelay(1000);
      }
      else {
        updateEnc();

        dr = sw(heading, cotsp.SunriseAzimuth);

        if (heading == int(cotsp.SunriseAzimuth)) {
          SR();
          onSunrise = true;
        }
        else if (dr) {
          RR();
        }
        else {
          RL();
        }
      }
      while (ss.available())
        gps.encode(ss.read());

      printInf();
    }

    void setup() {
      Serial.begin(9600);
      Serial.println("start");

      ss.begin(GPSBaud);

      BL.begin(); BS.begin(); BR.begin();

      pinMode(DIR, OUTPUT);
      pinMode(PWM, OUTPUT);

      attachInterrupt(0, isr, CHANGE);
    }

    void loop() {
      if (BL.pressed()) {
        Serial.println("Rotate left");
        while (!BL.pressed()) {
          updateEnc();
          RL();
          Serial.println(String(heading) + "; " + String(rp));
        }
        Serial.println("Stop rotate left");
        SR();
      }

      if (BR.pressed()) {
        Serial.println("Rotate right");
        while (!BR.pressed()) {
          updateEnc();
          RR();
          Serial.println(String(heading) + "; " + String(rp));
        }
        Serial.println("Stop rotate right");
        SR();
      }

      if (BS.pressed()) {
        Serial.println("BS");
        while (!BS.pressed()) {
          if (mode) {
            following();
          }
          else {
            returning();
          }
        }
        SR();
        delay(100); //without this delay serial port for some reason does not work
        Serial.println("Stop rotate following");
      }
    }





     
     
    Последнее редактирование: 24 июн 2019
  2. b707

    b707 Гуру

    Выкладывайте код - скорее всего вы неправильно оправшиваете GPS
    в любом случае, без кода обсуждать в вашем вопросе нечего.
     
  3. parovoZZ

    parovoZZ Гуру

    GPS же по УАРТ работает? Это значит, что про прерывания на энкодере придется забыть.
     
  4. b707

    b707 Гуру

    пожалуй да
    ТС - ардуина не потянет две такие времязависимые задачи одновременно, как опрос энкодера с мотора и потока данных с GPS
     
  5. а есть ли какие-нибудь альтернативные решения?
     
  6. b707

    b707 Гуру

    если данные о оборотах мотора нужно снимать постоянно и пропуски недопустимы - думаю, надо делать счетчик оборотов на отдельной микросхеме
     
  7. но как тогда реализовывать приём данных с gps? Ведь законнектить две ардуинки по uart из-за него не получится
     
  8. b707

    b707 Гуру

    в этой Вашей фразе все неправда :)
    Во-первых, необзяательно ардуина.
    Во-вторых, необязательно UARt
    И в третьих, если уж на то пошло - есть ведь софтовый Сериал
     
    arkadyf и Константин_Ли нравится это.
  9. да, что-то сразу не догнал, спасибо за помощь)
     
  10. parovoZZ

    parovoZZ Гуру

    Через прерывания. Энкодер тупым опросом.

    а про другие интерфейсы мы не знаем? Асинхронный вот прям так обязателен?
     
  11. b707

    b707 Гуру

    у него энкодер на моторе - стало быть, десятки и сотни "щелчков" в секунду. Опрос одновременно с сериал - тут не покатит.
     
  12. parovoZZ

    parovoZZ Гуру

    И что такое сотни щелчков в секунду для МК, у которого тактовая 16 МГц? Да он большую часть времени вообще спать может.

    ПАЧАМУ
     
  13. b707

    b707 Гуру

    да, наверно.
    Но тогда и все остальное, мной написанное - ерунда, никакого отдельного МК не нужно.
     
  14. DetSimen

    DetSimen Guest

    давайте заслушаем теперь начальника транспортного цеха дядяВитю.
     
  15. b707

    b707 Гуру

    О. я смотрю ТС код выложил.
    Константин_Ли - как я и предполагал. вы совершенно не заботитесь о том, чтобы опрос GPS был максимально быстрым.

    Во-первых, вы запрашиваете при каждом шаге кучу данных, которые скорее всего так часто не нужны. Например SunsetCoordinates или SunRiseCoordinates, явно не меняются каждую секунду.

    Во-вторых, на каждом шаге вы выводите в сериал невероятное кодичество текста - если правильно подсчитал, порядка 250-300 символов. На скорости 9600 это занимает порядка 300 миллисекунд, в течении которых все остальные функции в вашем коде не работают Думаю, реально ваш код проводит практически все время в процедуре printInf()

    В третьих, для оптимизации работы с GPS стоит заглянуть в библиотеку - нет ли там лишнего. Но это уже после того, как разберетесь с "во-первых" и "во-вторых" :)

    Вообще, если бы вы написали, что это такое будет - можно было бы посоветовать более конкретно.
     
    Последнее редактирование: 24 июн 2019
  16. Ну во-первых, что значит "запрашиваю", это просто идут расчеты которые я просто вывел в отдельную библиотеку, к gps они отношения не имеют (они не обновляют данные с него, а только берут переменные с нужной информацией у объекта). И например SunsetCoordinates или SunRiseCoordinates запрашиваю только один раз при первом запуске контроллера .

    Во-вторых, я проводил тесты которые показали, что и без вывода в сериал порт обработка энкодера идёт аномально медленно (вывод текста это первое на что я подумал когда столкнулся с проблемой)

    А, ну и проект подразумевает мониторинг солнца, основываясь не на фоторезисторах, а на чистых расчетах и gps'e, для повышения точности
     
    Последнее редактирование: 24 июн 2019
  17. Сейчас вывел обновление gps'а в функцию которая отвечает за остановку моторов, т.е. энкодер и gps одновременно больше не могут работать физически, но тем не менее, задержка почему то остаётся

    Код (C++):

    #include <Button.h>

    #include <TinyGPS++.h> //gps libraries
    #include <SoftwareSerial.h>

    #include <Cotsp.h>

    #include "GyverEncoder.h"

    Button BL(8);  //L
    Button BS(9);  //S
    Button BR(10); //R

    #define DIR 5
    #define PWM 6

    #define CLK 3
    #define DT 2

    //gps objs
    static const int RXPin = 12, TXPin = 11;
    static const uint32_t GPSBaud = 9600;
    TinyGPSPlus gps;
    SoftwareSerial ss(RXPin, TXPin);

    Cotsp cotsp;

    bool dr = true;
    int rp = 0; int heading;

    Encoder enc1(CLK, DT, 100);

    bool FS = true;
    bool mode = true;

    bool onSunrise = false;

    void isr() {
      enc1.tick();  // отработка в прерывании
    }

    static void updateGps() {
      while (ss.available())
      gps.encode(ss.read());
    }

    static void updateEnc() {
      enc1.tick();
      if (dr) rp++;
      else rp--;
      heading = rp / 173.81;
      if (heading >= 360) {
      rp = 0;
      heading = 0;
      }
      else if (heading < 0) {
      heading = 360 + heading;
      }
    }

    static void smartDelay(unsigned long ms) {
      unsigned long start = millis();
      do {
      updateGps();
      } while (millis() - start < ms);
    }

    static void printInf() {
      /*
      if (mode)
      Serial.println("Mode: following");
      else
      Serial.println("Mode: returning");
      Serial.println("Year: " + String(int(gps.date.year())) + "; month: " + String(int(gps.date.month())) + "; day: " + String(int(gps.date.day())) + "; hour: " + String(gps.time.hour()) + "; minute: " + String(gps.time.minute()) + "; hour.minute: " + String(gps.time.hour() + gps.time.minute() / 60.));
      Serial.println("Your coordinates: " + String( gps.location.lat()) + " " + String( gps.location.lng()));
      Serial.println("Azimuth (degrees): " + String(cotsp.azimuth));
      Serial.println("Altitude (degrees): " + String(cotsp.altitude));
      Serial.println("Sunset Time: " + String(cotsp.SunsetTime));
      Serial.println("Sunrise Time: " + String(cotsp.SunriseTime));
      Serial.println("Sunset azimuth: " + String(cotsp.SunsetAzimuth));
      Serial.println("Sunrise azimuth: " + String(cotsp.SunriseAzimuth));
      if (dr)
      Serial.println("Direction: right");
      else
      Serial.println("Direction: left");*/

      Serial.println("Heading: " + String(heading) + "; RP: " + String(rp));

    }

    static void RR() {
      dr = true;
      digitalWrite(DIR, HIGH);
      digitalWrite(PWM, LOW);
    }
    static void RL() {
      dr = false;
      digitalWrite(DIR, LOW);
      digitalWrite(PWM, HIGH);
    }
    static void SR() {
      digitalWrite(DIR, HIGH);
      digitalWrite(PWM, HIGH);
      while (!checkGPS()) {
      Serial.println("satellite search..");
      smartDelay(1000);
      }

      while (ss.available())
      gps.encode(ss.read());

      cotsp.UpdateSunCoordinates(gps.date.year(), gps.date.month(), gps.date.day(), gps.location.lat(), gps.location.lng(), gps.time.hour() + (gps.time.minute() / 60.));

    }

    static bool checkGPS() {
      if (gps.charsProcessed() < 10)
      return false;
      return true;
    }

    static bool sw(double phi, double destphi) {
      double delta = destphi - phi;
      if (0 <= delta and delta <= 180 or - 360 <= delta and delta <= -180) {
      return true; //R
      }
      else {
      return false; //L
      }
    }

    void following() {
      updateEnc();
     
      if (FS) {
      cotsp.UpdateSunsetCoordinates(gps.date.year(), gps.date.month(), gps.date.day(), gps.location.lat(), gps.location.lng(), gps.time.hour() + (gps.time.minute() / 60.));
      cotsp.UpdateSunriseCoordinates(gps.date.year(), gps.date.month(), gps.date.day(), gps.location.lat(), gps.location.lng(), gps.time.hour() + (gps.time.minute() / 60.));
      FS = false;
      }
      cotsp.azimuth = 90;
      dr = sw(heading, cotsp.azimuth);

      if (heading == int(cotsp.azimuth)) {
      SR();
      //mode = false;//!!!!!!
      }
      else if (dr) {
      RR();
      }
      else {
      RL();
      }

      if (cotsp.SunsetTime <= hour + (minute / 60.)) {
      SR();
      mode = false;
      }

      printInf();
    }

    void returning() {
      if (onSunrise) {
      if (cotsp.SunriseTime <= (gps.time.hour() + (gps.time.minute() / 60.)))
      mode = true;
      smartDelay(1000);
      }
      else {
      updateEnc();

      dr = sw(heading, cotsp.SunriseAzimuth);

      if (heading == int(cotsp.SunriseAzimuth)) {
      SR();
      onSunrise = true;
      }
      else if (dr) {
      RR();
      }
      else {
      RL();
      }
      }

      printInf();
    }

    void setup() {
      Serial.begin(9600);
      Serial.println("start");

      ss.begin(GPSBaud);

      BL.begin(); BS.begin(); BR.begin();

      pinMode(DIR, OUTPUT);
      pinMode(PWM, OUTPUT);

      attachInterrupt(0, isr, CHANGE);
    }

    void loop() {
      if (BL.pressed()) {
      Serial.println("Rotate left");
      while (!BL.pressed()) {
      updateEnc();
      RL();
      Serial.println(String(heading) + "; " + String(rp));
      }
      Serial.println("Stop rotate left");
      SR();
      }

      if (BR.pressed()) {
      Serial.println("Rotate right");
      while (!BR.pressed()) {
      updateEnc();
      RR();
      Serial.println(String(heading) + "; " + String(rp));
      }
      Serial.println("Stop rotate right");
      SR();
      }

      if (BS.pressed()) {
      while (!checkGPS()) {
      Serial.println("satellite search..");
      smartDelay(1000);
      }
      Serial.println("BS");
      while (!BS.pressed()) {
      if (mode) {
      following();
      }
      else {
      returning();
      }
      }
      SR();
      delay(100); //without this delay serial port for some reason does not work
      Serial.println("Stop rotate following");
      }
    }
     
     
  18. DetSimen

    DetSimen Guest

    дальше
    #include "GyverEncoder.h"
    не читал и не буду.
     
    parovoZZ нравится это.
  19. parovoZZ

    parovoZZ Гуру

    Вообще, если отказаться от вашей этой ардуины, то задача прекрасно решается конечным автоматом на прерываниях. Возможно, потребуется кольцевой буфер, дабы в прерываниях долго не висеть, а обработку всех данных вести между прерываниями.
    А с таким подходом к делу надо брать что-то из СТМ32. В ней, кстати, таймеры имеют энкодеры аппаратно.
     
  20. b707

    b707 Гуру

    Ооооо я и не заметил.
    Константин - библиотеки этого автора имеют в инете дурную славу, разбираться с ними никто не станет. Если хотите ими пользоваться - обращайтесь к автору, но мой вам совет - выкиньте их и забудьте, как страшный сон.
     
    Daniil и DetSimen нравится это.