Как подключить к Arduino эхолот Humminbird?

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем Bif+, 12 фев 2019.

  1. Лодка немного порыскает в своем диапазоне, потом заплывет на глубину и начнет нарезать круги без остановки.
    С компасом что-то терпимое может и можно сделать, и то придется корректировать периодически.
     
  2. Bif+

    Bif+ Гик

    Да в этом то и вся соль! Я не говорю о полномасштабном автопилотировании. Фанатам автопилота проще купить буржуйский девайс, выложив за него $2тыс. да + еще картплоттер за $1,5тыс. Я в лодке жить не собираюсь. Я езжу на рыбалку, а не за рыбой!
    "Лодка немного порыскает в своем диапазоне..." и этого достаточно для того, чтобы разобраться со спиннингом.
    Что касается компаса, то я его сделал по тому видео, благо там есть схема и код. Направление держит, но на практике еще не применял, В том виде, что я изготовил, надо ставить на мотор-докатку, а у меня основной движетель водомет. Докатка тоже есть,но выносить серводвигатель за корму на транец - там волна, т.е заморочки с герметизацией. Эх, скинуть бы лет 20! Так что, господа, спешите жить!
     
  3. parovoZZ

    parovoZZ Гуру

    в точку!
     
  4. tpolimer

    tpolimer Нерд

    Итак, конечный код, рассчитанный на использование 1-ой ардуины.

    GetAngleFromCompass - получение угла с компаса.
    MotorControl - это Ваш код, тут нужно будет вставить управление.

    Код (C++):
    #include <SoftwareSerial.h>
    SoftwareSerial mySerial(2, 3); // RX, TX

    // Включаем отладку.
    #define DEBUG

    #define POTENTIOMETER_R1_PIN      A0
    #define POTENTIOMETER_R2_PIN      A1

    #define BUFFER_SIZE 15
    char serialBuffer[BUFFER_SIZE + 1];

    // Текущая глубина.
    int lastDeep = 0;
    // Предыдущая глубина.
    int previousDeep = 0;

    // Частота получения значений от компаса и управления мотором.
    const int intervalMainBlock = 1000;

    void setup()
    {
      // put your setup code here, to run once:
      Serial.begin(4800);
      mySerial.begin(4800);
      while (!Serial)
      {
        ; // wait for serial port to connect. Needed for native USB port only
      }
    }

    void loop()
    {
      static byte finishComand = 0;

      // Получение глубины.
      GetDeep(&finishComand);

      // Предыдущее значение системного таймера.
      static unsigned long previousSystickMainBlock = 0;
      // Текущее значение системного таймера.
      unsigned long currentSystickMainBlock = millis();

      // Запускаем с интервалом intervalMainBlock и проверяем значение глубины.
      if ((currentSystickMainBlock - previousSystickMainBlock) >= intervalMainBlock
          && lastDeep != 0)
      {
        previousSystickMainBlock  = millis();

    #ifdef DEBUG
        Serial.println("BeginMainBloack");
    #endif

        // Получение текущее значения угла от компаса.
        int angle = GetAngleFromCompass();

        // Управление мотором.
        MotorControl(angle);

    #ifdef DEBUG
        Serial.println("EndMainBloack");
    #endif

      }
    }

    // Функция получения глубины.
    void GetDeep(byte* finishComand)
    {
      if (mySerial.available() > 0)
      {
        static byte saveInBuffer = 0;
        static byte commandCorrect = 0;

        char lastChar = mySerial.read();
        static byte indexBuffer = 0;
        switch (lastChar)
        {
          case '$':
            memset(serialBuffer, 0, sizeof(serialBuffer));
            indexBuffer = commandCorrect = finishComand = 0;

            // Сохраняем предыдущую глубину.
            previousDeep = lastDeep;

            serialBuffer[indexBuffer] =  lastChar;

            saveInBuffer = 1;
            break;
          default:
            if (commandCorrect == 1 && lastChar == ',')
            {
              finishComand = 1;
              saveInBuffer = 0;

              // Умножаем глубину на 10, для удобной работы в дальнейшем.
              lastDeep = (int)(atof(&serialBuffer[7]) * 10);

              // Если есть переменная DEBUG.
    #ifdef DEBUG
              Serial.print("lastDeep - ");
              Serial.println(lastDeep);

              Serial.print("previousDeep - ");
              Serial.println(previousDeep);
    #endif
            }

            if (indexBuffer < BUFFER_SIZE && saveInBuffer == 1)
            {
              indexBuffer = indexBuffer + 1;
              serialBuffer[indexBuffer] =  lastChar;
            }
            break;
        }

        if (indexBuffer == 6)
        {
          if (strstr(serialBuffer, "$INDPT,") > 0)
          {
            commandCorrect = 1;
          }
          else
          {
            saveInBuffer = 0;
          }
        }
      }
    }

    // Получение текущее значения угла от компаса.
    int GetAngleFromCompass()
    {
      int angle = 0;

      // Вставляем нужный код.

      return angle;
    }

    // Управление мотором.
    void MotorControl(int angle)
    {
      // Общая идея, valR1 и valR2 настраивают глубину, от 0 до 10 метров с шагом 0,1 метра.
      // Диапазон valR1 и valR2 от 0 до 100, что соответствует глубине от 0 до 10 метров с шагом 0,1 метра.
      // Где 1 равно 0,1метра, а 35 соответствует грубине 3,5 метра.
      int valR1 = analogRead(POTENTIOMETER_R1_PIN);        // запомнить показания с  R1
      valR1 = map(valR1, 0, 1023, 0, 100);                 // перевести в диапазон 0.. 100

    #ifdef DEBUG
      Serial.print("valR1 - ");
      Serial.println(valR1);
    #endif

      int valR2 = analogRead(POTENTIOMETER_R2_PIN);       // запомнить показания с  R2
      valR2 = map(valR2, 0, 1023, 0, 100);                 // перевести в диапазон 0.. 100

    #ifdef DEBUG
      Serial.print("valR2 - ");
      Serial.println(valR2);
    #endif
     
      if (lastDeep < valR1)
      {
        Serial.println("x<a");
      }
      else if (lastDeep == valR1)
      {
        Serial.println("a");
      }
      else if (lastDeep > valR1)
      {
        Serial.println("x>a");
      }
      else if (lastDeep == valR2)
      {
        Serial.println("b");
      }
      else if (lastDeep > valR2)
      {
        Serial.println("x>b");
      }
      else if (lastDeep < valR2)
      {
        Serial.println("b");
      }
    }
    Что касается использование ардуино меги, то она не нужна. Но если библиотек и/или кода будет прилично, придется использовать именно мегу.
     
    Последнее редактирование: 16 мар 2019
    Bif+ нравится это.
  5. Bif+

    Bif+ Гик

    Добрый день!
    Очень хорошо! Как я понял, DAC не нужен. А как обеспечить приоритет сигнала от компаса, если потеряем или выйдем далеко за пределы заданной глубины? Чтобы не получилось:
     
  6. Bif+

    Bif+ Гик

    Не реагирует на потенциометры никак:

    BeginMainBloack
    valR1 - 94
    valR2 - 94
    x<a
    EndMainBloack
    lastDeep - 33
    previousDeep - 34
    lastDeep - 33
    previousDeep - 33
    BeginMainBloack
    valR1 - 93
    valR2 - 92
    x<a
    EndMainBloack
    lastDeep - 34
    previousDeep - 33

    lastDeep работает, x<a тоже не меняется.
    R1, R2 по 10к, может большие?
     
  7. Bif+

    Bif+ Гик

    При отсутствии сигнала с эхолота в монитор порта ничего не выводится.
     
  8. Bif+

    Bif+ Гик

    При включенном эхолоте, если закрыть монитор порта, а затем снова открыть, выдает:
    lastDeep - 51
    previousDeep - 0
    BeginMainBloack
    valR1 - 46
    valR2 - 44
    x>a
    EndMainBloack
    lastDeep - 53
    previousDeep - 51
    BeginMainBloack
    valR1 - 93
    valR2 - 92
    x<a
    EndMainBloack
    lastDeep - 58
    previousDeep - 53

    В первое мгновение показывает данные R1, R2 и x>a правильно, затем - нет.
    Потенциометры не трогал.
     
  9. Bif+

    Bif+ Гик

    Эти значения тоже не меняются:
    valR1 - 46
    valR2 - 44
    очевидно, тоже "с потолка".
     
  10. Bif+

    Bif+ Гик

    Добрый день!
    С потенциометрами разобрался, работают.
    lastDeep - 73
    previousDeep - 72
    BeginMainBloack
    valR1 - 34
    valR2 - 62
    x>a
    EndMainBloack
    lastDeep - 73
    previousDeep - 73
    BeginMainBloack
    valR1 - 34
    valR2 - 62
    x>a
    EndMainBloack
    lastDeep - 73
    Должен выводить: x>b, но кроме x<a и x>a при изменении lastDeep не хочет.
    Что не так?
     
  11. ostrov

    ostrov Гуру

    Можно просто, можно как положено, называется ПИД-регулятор.
     
  12. parovoZZ

    parovoZZ Гуру

    В данном случае хватит и обычного интегратора.
     
  13. Bif+

    Bif+ Гик

    Так, с этим разобрался...
    lastDeep - 53
    valR1 - 44
    valR2 - 64
    x
    lastDeep - 64
    valR1 - 44
    valR2 - 64
    x>b
    lastDeep - 57
    valR1 - 44
    valR2 - 64
    x
     
  14. tpolimer

    tpolimer Нерд

    Хотел отправить ответ раньше, но постоянная ошибка 502 и форум не доступен.

    Да, все делается на одной ардуине.

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

    Да, так и задумано, если данных нет, то это ошибка.
    Код (C++):
    // Запускаем с интервалом intervalMainBlock и проверяем значение глубины.
      if ((currentSystickMainBlock - previousSystickMainBlock) >= intervalMainBlock
          && lastDeep != 0)
    Это очень просто проверить, соединяем A0 и 5V, а A1 c 3,3V, затем меняем местами, так же соединяем с землей (GND) и смотрим, что получилось. 5V будет соответствовать 100, 3,3V = 63, GND = 0. Видимо проблемы с подключением.

    По поводу больше, меньше, равно, скопировал Ваш кусок кода и оформил его с if else.
     
  15. Bif+

    Bif+ Гик

    Я сделал так:
    Код (C++):
    #ifdef DEBUG
      Serial.print("valR2 - ");
      Serial.println(valR2);
    #endif
      if (lastDeep <= valR1)
      {
        Serial.println("x<a");
      }
      else if (lastDeep > valR1, lastDeep < valR2 )
      {
        Serial.println("x");
      }
      if (lastDeep >= valR2)
      {
        Serial.println("x>b");
      }
     
    }
    Работает. Пока оставлю так, надо разобраться с компасом.
     
  16. tpolimer

    tpolimer Нерд

    Старое правило - работает не трогай:).

    Хотя мне эта строка мне не понятна.
    Даже любопытно стало, как это работает. Говорю о запятой в условии.

    Рад, что дела идут.
     
  17. Bif+

    Bif+ Гик

    Спасибо.
    Запятую убрал, не компилируется.
     
  18. Bif+

    Bif+ Гик

    Добрый вечер, уважаемое сообщество!
    Думал, что с подключением сервы не будет проблем, ан, нет - не все так просто, как казалось!
    vimple.co/06d090281d594007b05ba618ed8d6be5

    Код (C++):
    #include <SoftwareSerial.h>
    SoftwareSerial mySerial(2, 3); // RX, TX
    #include <Servo.h>
    #define servoPin 5
    #define servoMinImp 600
    #define servoMaxImp 2200
    Servo myservo;

    // Включаем отладку.
    #define DEBUG

    #define POTENTIOMETER_R1_PIN      A0
    #define POTENTIOMETER_R2_PIN      A1

    #define BUFFER_SIZE 15
    char serialBuffer[BUFFER_SIZE + 1];

    // Текущая глубина.
    int lastDeep = 0;
    // Предыдущая глубина.
    int previousDeep = 0;

    // Частота получения значений от компаса и управления мотором.
    const int intervalMainBlock = 1000;

    void setup()
    {
      // put your setup code here, to run once:
      Serial.begin(4800);
      mySerial.begin(4800);
      while (!Serial)

      {
        ; // wait for serial port to connect. Needed for native USB port only
      }
      myservo.attach(servoPin, servoMinImp, servoMaxImp);
    }

    void loop()
    {
      static byte finishComand = 0;

      // Получение глубины.
      GetDeep(&finishComand);

      // Предыдущее значение системного таймера.
      static unsigned long previousSystickMainBlock = 0;
      // Текущее значение системного таймера.
      unsigned long currentSystickMainBlock = millis();

      // Запускаем с интервалом intervalMainBlock и проверяем значение глубины.
      if ((currentSystickMainBlock - previousSystickMainBlock) >= intervalMainBlock
          && lastDeep != 0)
      {
        previousSystickMainBlock  = millis();

    #ifdef DEBUG
        //Serial.println("BeginMainBloack");
    #endif

        // Получение текущее значения угла от компаса.
        int angle = GetAngleFromCompass();

        // Управление мотором.
        MotorControl(angle);

    #ifdef DEBUG
        //Serial.println("EndMainBloack");
    #endif

      }
    }

    // Функция получения глубины.
    void GetDeep(byte* finishComand)
    {
      if (mySerial.available() > 0)
      {
        static byte saveInBuffer = 0;
        static byte commandCorrect = 0;

        char lastChar = mySerial.read();
        static byte indexBuffer = 0;
        switch (lastChar)
        {
          case '$':
            memset(serialBuffer, 0, sizeof(serialBuffer));
            indexBuffer = commandCorrect = finishComand = 0;

            // Сохраняем предыдущую глубину.
            previousDeep = lastDeep;

            serialBuffer[indexBuffer] =  lastChar;

            saveInBuffer = 1;
            break;
          default:
            if (commandCorrect == 1 && lastChar == ',')
            {
              finishComand = 1;
              saveInBuffer = 0;

              // Умножаем глубину на 10, для удобной работы в дальнейшем.
              lastDeep = (int)(atof(&serialBuffer[7]) * 10);

              // Если есть переменная DEBUG.
    #ifdef DEBUG
              Serial.print("lastDeep - ");
              Serial.println(lastDeep);

              // Serial.print("previousDeep - ");
              //Serial.println(previousDeep);
    #endif
            }

            if (indexBuffer < BUFFER_SIZE && saveInBuffer == 1)
            {
              indexBuffer = indexBuffer + 1;
              serialBuffer[indexBuffer] =  lastChar;
            }
            break;
        }

        if (indexBuffer == 6)
        {
          if (strstr(serialBuffer, "$INDPT,") > 0)
          {
            commandCorrect = 1;
          }
          else
          {
            saveInBuffer = 0;
          }
        }
      }
    }

    // Получение текущее значения угла от компаса.
    int GetAngleFromCompass()
    {
      int angle = 0;

      // Вставляем нужный код.

      return angle;
    }

    // Управление мотором.
    void MotorControl(int angle)
    {
      // Общая идея, valR1 и valR2 настраивают глубину, от 0 до 10 метров с шагом 0,1 метра.
      // Диапазон valR1 и valR2 от 0 до 100, что соответствует глубине от 0 до 10 метров с шагом 0,1 метра.
      // Где 1 равно 0,1метра, а 35 соответствует грубине 3,5 метра.
      int valR1 = analogRead(POTENTIOMETER_R1_PIN);        // запомнить показания с  R1
      valR1 = map(valR1, 0, 1023, 0, 100);                 // перевести в диапазон 0.. 100

    #ifdef DEBUG
      Serial.print("valR1 - ");
      Serial.println(valR1);
    #endif

      int valR2 = analogRead(POTENTIOMETER_R2_PIN);       // запомнить показания с  R2
      valR2 = map(valR2, 0, 1023, 0, 100);                 // перевести в диапазон 0.. 100

    #ifdef DEBUG
      Serial.print("valR2 - ");
      Serial.println(valR2);
    #endif

      if (lastDeep <= valR1)
      {
        myservo.writeMicroseconds(1970);

        Serial.println("x<a");
     
        //delay(950);
     
      }

      else if  (lastDeep > valR1,  lastDeep < valR2 )
      {
        Serial.println("x");

        myservo.writeMicroseconds(1570);

        // delay(950);

      }

      if (lastDeep >= valR2)
      {
        myservo.writeMicroseconds(1200);

        Serial.println("x>b");

        //delay(950);

      }

    }
    lastDeep - 46

    valR1 - 47

    valR2 - 64

    x<a

    lastDeep - 52

    valR1 - 47

    valR2 - 64

    x

    lastDeep - 72

    valR1 - 47

    valR2 - 63

    x>b




    Когда глубина от эхолота меньше заданной от R1 (lastDeep <= valR1), т.е. ("x<a") еще не так дёргается. Но когда
    (lastDeep > valR1, lastDeep < valR2 ), т.е. ("x") - начинает танцевать. Частота танца в такт чтения сигнала глубины от эхолота. Читает одновременно ("x<a") и ("x"). Пробовал путь с наименьшим сопротивлением - использовать delay(950), не получается. Если задержку установить 1000 (надо бы 3000-5000), то пропадает lastDeep - глубина от эхолота. Пытался разобраться https://playground.arduino.cc/Code/SimpleTimer/ ,
    но пока плаваю. Как избавиться от танцев?
     
    Последнее редактирование: 23 мар 2019
  19. Bif+

    Bif+ Гик

    Может конфликтуют библиотеки
    <Servo.h> и <SoftwareSerial.h>?
     
  20. Bif+

    Bif+ Гик

    Очевидно, конфликт!
    Как только включаю myservo.attach, сразу на осциллограмме паразитный сигнал и серводвигатель начинает танцевать. На этот сигнал накладывается нужный и скачки усиливаются чуть-ли не до 45 градусов
    Знаний в этом вопросе мало, поэтому пошел по пути использования библиотек <AltSoftSerial.h>.
    Опять же, по той же причине, что маловато знаний, компилятор выдает ошибку либо 'altSerial' was not declared in this scope, либо ошибку загрузки в Arduino Nano. Подскажите, что не так? Или, как использовать родной аппаратный Serial, о чем говорил Airbus?
    Код (C++):
    #include <AltSoftSerial.h>
    #include <Servo.h>
    AltSoftSerial myExo (8, 9);   // RX, TX
    #define servoPin 10
    Servo myservo;
    #define servoMinImp 30        //600
    #define servoMaxImp 160       //2200



    // Включаем отладку.
    #define DEBUG

    #define POTENTIOMETER_R1_PIN      A0
    #define POTENTIOMETER_R2_PIN      A1

    #define BUFFER_SIZE 15
    char serialBuffer[BUFFER_SIZE + 1];

    // Текущая глубина.
    int lastDeep = 0;
    // Предыдущая глубина.
    int previousDeep = 0;

    // Частота получения значений от компаса и управления мотором.
    const int intervalMainBlock = 1000;

    void setup()
    {
      // put your setup code here, to run once:
      altSerial.begin(4800);
      myExo.begin(4800);
      while (!altSerial)
      {
        ; // wait for serial port to connect. Needed for native USB port only
      }

       myservo.attach(servoPin, servoMinImp, servoMaxImp);
    }

    void loop()
    {
      static byte finishComand = 0;

      // Получение глубины.
      GetDeep(&finishComand);

      // Предыдущее значение системного таймера.
      static unsigned long previousSystickMainBlock = 0;
      // Текущее значение системного таймера.
      unsigned long currentSystickMainBlock = millis();

      // Запускаем с интервалом intervalMainBlock и проверяем значение глубины.
      if ((currentSystickMainBlock - previousSystickMainBlock) >= intervalMainBlock
          && lastDeep != 0)
      {
        previousSystickMainBlock  = millis();

    #ifdef DEBUG
       // Serial.println("BeginMainBloack");
    #endif

        // Получение текущее значения угла от компаса.
        int angle = GetAngleFromCompass();

        // Управление мотором.
        MotorControl(angle);

    #ifdef DEBUG
        //Serial.println("EndMainBloack");
    #endif

      }
    }

    // Функция получения глубины.
    void GetDeep(byte* finishComand)
    {
      if (myExo.available() > 0)
      {
        static byte saveInBuffer = 0;
        static byte commandCorrect = 0;

        char lastChar = myExo.read();
        static byte indexBuffer = 0;
        switch (lastChar)
        {
          case '$':
            memset(serialBuffer, 0, sizeof(serialBuffer));
            indexBuffer = commandCorrect = finishComand = 0;

            // Сохраняем предыдущую глубину.
            previousDeep = lastDeep;

            serialBuffer[indexBuffer] =  lastChar;

            saveInBuffer = 1;
            break;
          default:
            if (commandCorrect == 1 && lastChar == ',')
            {
              finishComand = 1;
              saveInBuffer = 0;

              // Умножаем глубину на 10, для удобной работы в дальнейшем.
              lastDeep = (int)(atof(&serialBuffer[7]) * 10);

              // Если есть переменная DEBUG.
    #ifdef DEBUG
             altSerial.print("lastDeep - ");
             altSerial.println(lastDeep);

              //Serial.print("previousDeep - ");
             // Serial.println(previousDeep);
    #endif
            }

            if (indexBuffer < BUFFER_SIZE && saveInBuffer == 1)
            {
              indexBuffer = indexBuffer + 1;
              serialBuffer[indexBuffer] =  lastChar;
            }
            break;
        }

        if (indexBuffer == 6)
        {
          if (strstr(serialBuffer, "$INDPT,") > 0)
          {
            commandCorrect = 1;
          }
          else
          {
            saveInBuffer = 0;
          }
        }
      }
    }

    // Получение текущее значения угла от компаса.
    int GetAngleFromCompass()
    {
      int angle = 0;

      // Вставляем нужный код.

      return angle;
    }

    // Управление мотором.
    void MotorControl(int angle)
    {
      // Общая идея, valR1 и valR2 настраивают глубину, от 0 до 10 метров с шагом 0,1 метра.
      // Диапазон valR1 и valR2 от 0 до 100, что соответствует глубине от 0 до 10 метров с шагом 0,1 метра.
      // Где 1 равно 0,1метра, а 35 соответствует грубине 3,5 метра.
      int valR1 = analogRead(POTENTIOMETER_R1_PIN);        // запомнить показания с  R1
      valR1 = map(valR1, 0, 1023, 0, 100);                 // перевести в диапазон 0.. 100

    #ifdef DEBUG
      altSerial.print("valR1 - ");
      altSerial.println(valR1);
    #endif

      int valR2 = analogRead(POTENTIOMETER_R2_PIN);       // запомнить показания с  R2
      valR2 = map(valR2, 0, 1023, 0, 100);                 // перевести в диапазон 0.. 100

    #ifdef DEBUG
      altSerial.print("valR2 - ");
      altSerial.println(valR2);
    #endif
      if (lastDeep <= valR1)
      {
        myservo.write(150);
        altSerial.println("x<a");
      }
       else if  (lastDeep > valR1 && lastDeep < valR2 )
      {
        myservo.write(90);
        altSerial.println("x");
      }
       if (lastDeep >= valR1)
      {
        myservo.write(30);
        altSerial.println("x>b");
      }
    }
     
    Последнее редактирование: 30 мар 2019