Акселерометры пока не прониклись... зато, получил новый модуль для детектирования цвета. Встречайте модуль VEML6040 производства Vishay. У меня нет большого опыта, но из трёх сенсоров цвета, котрые я подержал в руках - этот самый простой, пожалуй. Общается по i2c имеет всего один конфигурационный регистр и 4 регистра для считывания результата. Всё. Нет даже статуса, сообщающего, что измерения выполнены и результаты доступны. В конфигурационном регистре можно выставить время интегрирования от 40мс до 1280мс, ручной или автоматический режим запуска, бит для ручного запуска и бит выключающий сенсор. Поэтому, чтобы им пользоваться достаточно записать 0 в конфиг и сенсор начнёт работать в автоматическом режиме с временем интеграции 40мс. Хм, для проверки валидности данных (что они взяты из одного цикла интегрирования), пожалуй, надо сделать повторное считывание и сравнение. Ну и принимать данные как валидные, если оба раза считались одинаковые данные.
Ну а теперь, надо бы заняться реальным определением цвета. Изначальный, мною реализованный алгоритм был крайне туп: превышение некоего порога указывает на наличие соответсвующего цвета. Но это меня не очень устраивало - хотелось подвести какую-нибудь математическую базу. Поэтому попытался для начала попытаться разместить показания сенсоров в трёхмерном пространстве RGB и вычислять расстояния до координат точек, соответствующим ожидаемым цветам. Например красный: 255,0,0; зелёный 0,255,0 итд.

Ну и то расстояние, которое в этом пространстве окажется меньше (и меньше определенного порога) - и является требуемым результатом. Да вот с порогом у меня как-то не сошлось. Если интенсивность освещения мала - цвет не определяется, если большая - начинает видеть цвета и на "белом" фоне. Поэтому ничего глупее не придумал, как провести нормализацию уровней:
Rнорм = R/(R+G+B)
Gнорм = G/(R+G+B) итд. Вот это был fail. Функция стала возвращать почти всегда один результат - черный цвет. Проведя моделирование в Excel понял, что в этом случае все контрольные точки имеют среди кратчйших расстояний и расстояния до "черной координаты" (0,0,0). А так как проверка начинается именно с неё, то на этом варианте всё и заканчивается. Короче, я понял что это не решает мою задачу.
Ну для определения цвета существует еще куча возможностей.. Есть CIELAB, CIELUV, HSI. Ну, первые два очень крутые способы описания цветового пространства, поэтому решил воспользоваться обычным ширпотребным HSI - Hue, Saturation, Intensity. Вот этот Hue и есть искомая вещь. Жаль только, что она выражается в виде угла круга. Ну и для выяснения, нужно ли выделять цвет, можно воспользоваться параметром насыщенности: если насыщенность недостаточна - цвет белый (оттенки не волнуют).
I = (R+G+B)/3 - интенсивность
S = 1 - min(R,G,B)/I - насыщенность.
Так как сама по себе интенсивность мне не нужна, формулу для насыщенности сделал такой:
inv_saturation = 3 * min(R,G,B) / (R+G+B);
вычитание из единицы тоже выкинул - мне без разницы какое сравнение делать.
Это была самая лёгкая часть. А вот формула для вычисления Hue (ой, мне лень вырисовывать корни и дроби, потому вставлю всю картинку):
Вот этот арктангенс и есть небольшой камень преткновения. Если тупо считать дробь, то ничего не получится. Потому как простой арктангенс может вернуть результат только от -90 до +90 градусов. Т.е. первый и четвёртый квадрант. После вычисления дроби информация о втором и третьем квадранте теряются. Поэтому, проще оказалось эту дробь рассматривать как координату в плоскости XY:
X = 2*R - G - B, Y= sqrt(3)*(G - B). И вот знаки X и Y указывают на квадрант в котором находится точка.

Если нарисовать этот круг, получается, что красный находится на 0 градусе, желтый на 60, зелёный - 120, светлоголубой 180, синий -120, фиолетовый - -60. Кстати, если взять синус и косинус от каждой координаты, то выяснится, что координата X принимает значения плюс-минус 1 и 0.5, а координата Y - 0 и плюс-минус корень из 3 пополам. Поэтому, вычислять углы нет особого смысла. И можно из формулы для координаты Y выбросить этот "корень из 3". Тогда если Y близок к нулю цвет или красный, или голубой (в зависимости от знака X), а если Y примерно равен X, то остальные 4 цвета (и тоже определются знаками X и Y). Причем, это "близко к нулю" можно поставить на границе в 30 градусов. А синус 30 есть 0.5 - поэтому "порог" можно ставить как раз на этом уровне - если Y находится в диапазоне от -0.5 до +0.5 - это близко к 0, иначе - всё остальное.
Попробовал написать код исходя из этих предпосылок - всё вроде работает, кроме одного - ни разу не удалось отдетектировать синий цвет. Почему-то G - B всегда даёт положительный результат. Всё что мне кажется "синим" подставляю под сенсор - синего не вижу - всегда присутствует зелёная составляющая с большей, чем синяя амплитудой. Надо будет попробовать в сенсор посветить синим светодиодом. Даже, если под сенсор подсунуть белый лист бумаги, красная и зелёная составляющие равны, а вот синяя почти в два раза меньше. Может, "белый" светодиод имеет очень слабую "синюю составляющую? На взляд, он имеет желтоватый оттенок.
====
На позапрошлой неделе задумался о том, что хорошо, что сделал плавный разгон, а вот как быть с плавным торможением? Проблема в том, как вычислить с какого расстояния надо начинать тормозить. И пока я кручу эту мысль в голове, вдруг вывалилась мысль, что у меня еще одно из самых тормозных мест - поворот робота. При этом, я всегда знаю, на сколько я хочу повернуться и всегда примерно знаю, на сколько уже повернулся. Поэтому в функцию поворота вставил код разгона. Сначала, сделал так, что робот половину поворота разгоняется, а вторую половину - тормозит. Но, оказалось, что делать разгон с минимума до указанной в конфиге скорости поворота, а после 45 градусов (если поворот на 90) делать торможение до минимума, выходит, что почти половину поворота робот выполняет на минимальной скорости. Поэтому, решил, что задаваемая в конфигурации скорость поворота будет минимальной скоростью, до которой робот будет при торможении сбавлять скорость. При разгоне, решил разрешить разгоняться до максимальной скорости. Погоняв робота по трассе, так же решил сместить точку начала торможения на 60 градусов (тоже для 90 градусного поворота). Но, похоже, просто введу в конфиг еще парочку параметров, чтобы при необходимости я мог быстро изменить эти углы в любую сторону в зависимости от обстоятельств.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."