image

Разработка проекта Arduino Mega Server идёт полным ходом и в процессе работы возникают неожиданные препятствия, которые приходится героически преодолевать. О некоторых из них вам сегодня расскажу и, возможно, это сэкономит вам немного вашего времени и нервов.

Прикол первый: и на старуху бывает проруха или зри в корень!


Готовлю к выходу 0.14 версию системы для Arduino Due и адаптирую эту версию для работы с Power Monitor. Для тех, кто не знает, Power Monitor это программно-аппаратный комплекс контроля сетевого электропитания, который позволяет контролировать уровень сетевого напряжения и потребляемой мощности по 14 каналам и имеет встроенный контроль частоты сетевого тока и даже сетевой осциллограф, которой прямо на веб-страничке показывает форму тока и напряжения в реальном времени.

image

Схему собрал, всё проверил, запускаю — не работает. Ну что же — бывает, дело привычное. Начинаю проверять код — всё в порядке, проверяю железо — всё окей, проверяю соединения — тоже всё в порядке. В глубокой задумчивости сажусь в кресло и начинаю соображать, где может быть ошибка. После долгих размышлений прихожу к выводу, что всё сделано правильно. Почему же не работает? Чудес не бывает, поэтому проверяю всё во второй раз.
image

Код, железо, соединения. Всё, вроде, правильно. Опять много думаю. Перелопачиваю код ещё раз, с пристрастием — результат — ноль. Поскольку все поликлинические методы исчерпаны, перевожу пациента в хирургическое отделение и достаю тестер и паяльник. Пациент опасливо косится на меня, но дара речи он лишён и не может мне ничего подсказать. После недолгих манипуляций выясняется, что питание на Power Monitor не подаётся вообще! Как же так? Ясно видны проводники подачи питания, а питания нет!

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

Тут ещё присутствует психологический момент — если вы считаете шину целой, то не обращаете внимания на пропуск в маркировке (мало ли что там вздумалось нарисовать изготовителю). Вот такие приколы иногда случаются в разработке — зри, как говорится, в корень!

Прикол второй: привет от нашей любимой команды arduino.cc


Как я уже сказал, разработка идёт полным ходом и AMS стал уже довольно объёмным проектом и, естественно, в проекте невозможно обойтись без очень полезных директив условной компиляции. Это мощный инструмент управления работой кода, тем более, что Arduino Mega Server имеет модульную структуру и директивами условной компиляции включаются и отключаются различные модули системы.

#define
#ifdef
#endif

Это сделано для того, чтобы можно было отключить ненужные вам модули и сэкономить драгоценную память микроконтроллера. И я ещё не встречался в своей практике (на разных языках программирования), чтобы директивы условной компиляции не работали или «глючили». Это нонсенс! До последнего времени я считал, что это невозможно, но (весёлые) разработчики среды программирования Arduino не дают нам скучать, но обо всём по порядку.

Итак, пытаемся отключить ненужный нам модуль, в данном случае, модуль работы с MajorDoMo (и до сих пор это работало как и положено).

//#define MAJORDOMO_FEATURE

По идее, всё, что находится между директивами

#ifdef MAJORDOMO_FEATURE

...

#endif

должно быть выключено из компиляции. Но не тут то было!


#ifdef MAJORDOMO_FEATURE

char majorMegaObject[] = "ncMega01";
char majorCommObject[] = "comm_mega01";

// MajorDoMo net settings
byte MAJOR_IP[] = {192, 168, 2, 8};
int MAJOR_PORT = 80;

// <-------------------------------------- ВОТ ЗДЕСЬ ЕЩЁ ОТКЛЮЧАЕТСЯ КОМПИЛЯЦИЯ

// EthernetClient object
EthernetClient mclient;

// <-------------------------------------- А ВОТ ЗДЕСЬ УЖЕ НЕТ! ВСЁ, ЧТО НИЖЕ КОМПИЛИРУЕТСЯ, НЕСМОТРЯ НА ЗАПРЕТ!

void majordomoInit() {
  initStart("MajorDoMo");
  timeStamp();
  Serial.print("Connect to MajorDoMo... ");
  if (mclient.connect(MAJOR_IP, MAJOR_PORT)) {
    Serial.println("OK");
    //mclient.println("GET /search?q=arduino HTTP/1.0");
    mclient.println();
  } else {
      Serial.println("failed");
    }
  delay(200);
  mclient.stop();
  modulMajor = MODUL_ENABLE;
  initDone();
}

…

Как вы можете заметить, условная компиляция не просто не работает (это плохо, но еще куда не шло), а работает «как Бог на душу положит», то есть где хочет — компилирует, где не хочет — не компилирует! И это совсем плохо, потому, что такие непредсказуемые «глюки» очень трудно отловить и они могут приводить к совершенно непредсказуемым последствиям.

Кстати, в данной статье идёт речь о Arduino IDE версии 1.6.5. Но, судя по всему, версия среды разработки не имеет особого значения, все они достаточно глючны. О чём я узнал только в последнее время, до тех пор, пока я компилировал маленькие скетчи и небольшие проекты, всё было в порядке.

Прикол третий: опять наша любимая arduino.cc и совершенно фантастический баг


Не буду тут долго описывать, на мой взгляд, совершенно из ряда вон выходящий баг в компиляторе среды Arduino, а сразу приведу код, чтобы вы сами могли оценить это чудо.

Объявляем переменную:

long errorsHttpSend = 0;

В цикле печатаем:

Serial.println(errorsHttpSend);

Результат:

808333615

Переименовываем, добавляя 2:

long errorsHttpSend2 = 0;

В цикле печатаем:

Serial.println(errorsHttpSend2);

Результат:

0 

Встаёт вопрос как вообще можно вести разработку в такой системе? Тут ещё можно упомянуть совершенно неадекватную работу различных версий Arduino IDE. Код, который прекрасно работает в одной версии среды, отказывается компилироваться в другой. Одна среда компилирует проект, другая «не видит» одну из библиотек. После переустановки среды разработки перестаёт компилировать проект та же версия 1.6.5 (которая до переустановки компилировала).

Так что имейте в виду, с чем вам придётся столкнуться, работая с Arduino. Здесь есть только один положительный момент: с такой системой вы волей-неволей станете гуру программирования и мастером системного администрирования.

Позволю себе высказать новогоднее пожелание для команды разработчиков Arduino: дорогие вы наши! Поздравляем вас с Новым Годом и желаем в новом году выпустить нормально работающую среду разработки!

С Новым Годом!


Друзья! Поздравляю вас с наступающим 2016 годом и надеюсь, что информация из этой статьи поможет вам сэкономить немного времени и нервов в новом году! И удачных разработок!

P.S.

Несмотря на все происки врагов, в ближайшее время всё-таки выйдет новая версия Arduino Mega Server под номером 0.14 для Arduino Mega и Arduino Due со множеством новых возможностей.

Комментарии (8)


  1. Ogoun
    30.12.2015 17:07

    Недавно пересел с Arduino Studio на AVR Studio, которая использует Visual Studio 2012, и соответственно позволяем создавать нормальные проекты, использовать автодополнения, форматирование, переходы по коду. И которая умеет работать с более обширным списком железа.


    1. smart_alex
      30.12.2015 17:27

      Я вообще в шоке от Arduino IDE. То, что я описал в статье вообще не укладывается в голове. Невозможно перейти с 1.6.5 на 1.6.7, среда видит 4 библиотеки, а пятую — не видит, хоть убей. При возврате на 1.6.5 — проект перестаёт компилироваться.

      С переменными вообще непонятно, что делать — их значения выдаются «с потолка», а про выборочную (!) условную компиляцию я вообще молчу.

      И самое плохое то, что это не «прокол», а система и улучшений ждать не приходится. Волей-неволей задумаешься о переходе на AVR Studio.


  1. olartamonov
    30.12.2015 17:58

    Это нонсенс! До последнего времени я считал, что это невозможно, но (весёлые) разработчики среды программирования Arduino не дают нам скучать, но обо всём по порядку.


    Оооо, как раз тут радовался в Makefile'ах OpenWRT.

    Конструкция
    define Download/package1
      URL:=blah-blah-blah
      blah-blah-blah
    endef
    
    define Build/package2
      ifeq (условие)
        $(call Download,package1))
        blah-blah-blah
      endif
      blah-blah-blah
    endef
    


    Скачивает package1 всегда. Независимо от выполнения вызова, обёрнутого в ifeq. Просто на всякий случай. Дошло до этого макроса — скачало. Ничего с ним больше не делает, но скачивает. Более того, если вообще всю секцию Download/package1 обернуть в ifeq, то оно ещё и ругается, что хочет скачать, но URL'а нету.

    Игнорирование #define в сишном коде — круче однозначно, но всё же, всё же. Четверть часа не мог понять, почему сборка прошивки останавливается на попытке скачать исходники с лежащего сайта, если использование этих исходников в явном виде выключено везде, где его только можно выключить.


    1. smart_alex
      30.12.2015 18:21

      Да… будем знать, что компилятор нужно ещё проверять. Я как-то уже привык, что всё делается правильно, тут такое…

      А с переменными, вообще слов нет:

      а = 0;
      print a

      808333615

      %()


      1. arruin
        30.12.2015 23:05
        +2

        Imho внутрисхемная отладка при сколько-нибудь масштабном проекте просто необходима. Иначе время потребное на поиск сбоя начинает расти в совсем неприличных размерах. Ну, в случае с ArduinoIDE остаётся только найти в %TEMP% каталог с собранным проектом и натравить на ELF-файл objdump из потрохов ArduinoIDE ( avr-objdump -S projectname.elf > projectname.lss) получив при этом ассемблерный листинг прошивки с cpp-вставками помогающими понять что данный блок кода делает.


        1. smart_alex
          30.12.2015 23:30

          Это да, но тут речь идёт о том, IDE ведёт себя совершенно неприемлемо. У меня требования совсем минимальные — чтобы можно было просто заниматься проектом, а не думать о бесконечных багах.

          Переменная errorsHttpSend так и висит в проекте и показывает совершенно безумные значения. И я не знаю, что с ней делать. Она просто объявлена и ей присвоено значение 0. А дальше с ней не производится никаких действий, она просто выводится на печать. И показывает разные 6-и — 8-и значные значения. И что дальше делать?

          Такое поведение похоже на нехватку памяти, но это Due и память используется всего процентов на 15.


  1. AVI
    31.12.2015 12:02

    О, мой Бог! О, мой Бог!
    У макетка второго типа, с разорванным питанием. Вчера убил более 3 часов на поиск проблемы.
    В проекте используется компас HMC5883L, общается по I2C. До этого датчик был протестирован и отложен в сторону. Сейчас пришло время его применить. Макетка обросла подключениями и датчик попал на вторую половину макетки.
    В итоге ардуино намертво виснет при попытке пообщаться с HMC5883L. Только сейчас обнаружил, что на нем не было питания все это время. Разрыв реально в упор не видел все это время. Уже даже поверил, что датчик умудрился скончаться пока дожидался применения )


    1. smart_alex
      31.12.2015 13:36

      Иначе, как приколом это назвать трудно, но на практике всё очень жестоко — поди догадайся, что половина схемы без питания, хотя перемычки прекрасно видны. А ещё возможны «интересные» варианты с подачей одной земли или одного питания без земли. Если есть связь через другие элементы схемы, то глюки будут ещё интереснее.