ARDUINO для детей: "как Лего"

Насколько полезна тема и стоит ли расписывать детально далее?

  • 1. Полезно и очень, внимательно слежу за дополнениями. Аффтар! пиши исчо!

  • 2. Может кому-то и полезно, лично мне нет, я уже вырос, обучать? Есть кружки, школы..

  • 3. Может кому и полезно, но сам повторять не собираюсь, полно готовых изделий.

  • 4. Фигня и мазохизм. Проще купить готовое, тема бесполезна.

  • 5. Тема вредна, учит делать своими руками - кто покупать будет то, что я продаю?

  • 5. Мне все равно. И вообще читать не умею, а картинок мало.


Результаты будут видны только после голосования.

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Блок кода обработки линейки датчиков линии (пост №9) из 5-и штук:

C:
/**
 * Модуль работы с датчиками линии
 *
 * @author Arhat109-20171009
 */

// количество усредняемых замеров
#define MAX_AVERAGE    3

// длительность в мсек. периода автонастройки уровней датчиков
#define MAX_AUTOLEVEL   10000

// всего датчиков линии. Оно же и ошибка направления - слева, + справа
// ВСЕГДА нечетное число .. важно!
#ifndef MAX_SENSORS
  #define MAX_SENSORS    5
#endif

/** данные по датчикам 12 байт на датчик */
typedef struct _sensor_ {
  uint8_t pin;
  int8_t  dir;   // "расстояние" датчика от середины: <0 - влево, >0 - вправо
  int     black; // автонастройка: минимальное черное
  int     white; // автонастройка: максимальное белое
  int     lvl;   // автонастройка: уровень между белым и черным;
  int     val;   // замер
  int     adc;   // результат преобразования в: 0 - белое, 1 - черное
} Sensors;
#define ptrSensor(p, n) (((Sensors *)(p))+n)

#ifndef sensor
  Sensors sensor[MAX_SENSORS] = {
    { A7, -4, 1024, -1, 0, 0, 0}, // самый левый
    { A6, -2, 1024, -1, 0, 0, 0},
    { A5,  0, 1024, -1, 0, 0, 0},
    { A4,  2, 1024, -1, 0, 0, 0},
    { A3,  4, 1024, -1, 0, 0, 0}, // самый правый
  };
#endif

#define snPin(p)        (sensor[(p)].pin)
#define snBlack(p)      (sensor[(p)].black)
#define snWhite(p)      (sensor[(p)].white)
#define snVal(p)        (sensor[(p)].val)
#define snLvl(p)        (sensor[(p)].lvl)
#define snAdc(p)        (sensor[(p)].adc)
#define snDir(p)        (sensor[(p)].dir)

/**
 * Вывод в монитор содержимого всех датчиков для проверок
 */
void printSensors()
{
  for( uint8_t i=0; i<MAX_SENSORS; i++){
    Serial.println();
    Serial.print("s="); Serial.print(i, DEC);
    Serial.print(", P="); Serial.print(snPin(i), DEC);
    Serial.print(", D="); Serial.print(snDir(i), DEC);
    Serial.print(", B="); Serial.print(snBlack(i), DEC);
    Serial.print(", W="); Serial.print(snWhite(i), DEC);
    Serial.print(", L="); Serial.print(snLvl(i), DEC);
    Serial.print(", V="); Serial.print(snVal(i), DEC);
    Serial.print(", A="); Serial.print(snAdc(i), DEC);
  }
}

/**
 * Начальная установка датчиков и зачистка данных по ним
 */
void setupSensors()
{
  for( uint8_t i=0; i<MAX_SENSORS; i++ ){
    pinMode( snPin(i), INPUT);
    snBlack(i) = 1024;
    snWhite(i) = -1;
    snVal(i) = snLvl(i) = snAdc(i) = 0;
  }
}

/** усреднение "бегущим средним" */
void getSensorsRun()
{
  for( uint8_t n=MAX_AVERAGE; n; n--){
    for( uint8_t i=0; i<MAX_SENSORS; i++){
      snVal(i) = (analogRead( snPin(i) )*5 + snVal(i)*3) / 8; // к-ты подбирать по устойчивости, если надо!
      snAdc(i) = (snVal(i) > snLvl(i)? 0 : 1);
    }
  }
}

/** усреднение арифметическое */
void getSensorsAvg()
{
  static int adcs[MAX_SENSORS][MAX_AVERAGE];
  int        summ;

  for( uint8_t n=MAX_AVERAGE; n; n--){
    for( uint8_t i=0; i<MAX_SENSORS; i++){
      adcs[i][n] = analogRead( snPin(i) );
    }
  }
  for( uint8_t i=0; i<MAX_SENSORS; i++){
    summ = 0;
    for( uint8_t n=MAX_AVERAGE; n; n--){
      summ += adcs[i][n];
    }
    snVal(i) = summ / MAX_AVERAGE;
    snAdc(i) = (snVal(i) > snLvl(i)? 0 : 1);
  }
}

/**
 * Чтение всех датчиков "оптом"
 * Усреднение удобно делать только на 4 замерах - деление заменяется свдигом!
 */
void getSensors()
{
  getSensorsRun();
}

/** Расчет уровней белого, черного и среднего на каждый вызов */
void calcLevel()
{
  getSensors();
  for(uint8_t i=0; i<MAX_SENSORS; i++)
  {
    if( snVal(i) < snBlack(i) ){ snBlack(i) = snVal(i); }
    if( snVal(i) > snWhite(i) ){ snWhite(i) = snVal(i); }
    snLvl(i) = (snWhite(i) - snBlack(i))/2 + snBlack(i);
  }
}

/**
 * Процедура автонастройки уровня датчиков
 * моргает всеми лампочками 2 раза быстро, настройка MAX_AUTOLEVEL сек, моргает 2 разf медленно
 * Пока настраивается горит средний светодиод
 */
void autoLevel()
{
  uint32_t time;

  blinkYellow(2, 150, 350);
  time = millis();
  while( millis() - time < MAX_AUTOLEVEL){
    blinkBlue(1,20,0);
    calcLevel();
  }
  blinkYellow(2, 500, 500);
}

/**
 * Проверяет как стоит машинка:
 * Считаем среднее кроме среднего датчика и если:
 * а) средний датчик показывает значительно меньше остальных, то он "на линии". Читаем уровни из EEPROM
 * б) иначе считаем что "все датчики на белом" - запускаем автонастройку
 * !!! Предполагается что все датчики показывают примерно одинаково на белом/черном !!!
 */
void getLevels()
{
  int avg = 0;
  int sensor0 = 0;

  getSensors();
  for( uint8_t i=0; i<MAX_SENSORS; i++){
    if( i != (MAX_SENSORS)/2 ){
      avg += snVal(i);
    }
  }
  avg /= (MAX_SENSORS - 1);
  sensor0 = snVal( (MAX_SENSORS)/2 );
//Serial.print(", sen0="); Serial.print((MAX_SENSORS)/2, DEC);
//Serial.print(", avg="); Serial.print(avg, DEC);
//Serial.print(", val0="); Serial.print(sensor0, DEC);
//Serial.println("");

  if( abs(avg - sensor0 ) > avg * 3/8 ){
    // стоим на линии, читаем EEPROM, моргаем средним и поехали:
    blinkBlue(4, 350, 150);
    readEEPROM(snEEPROM, (uint8_t *)sensor, sizeof(sensor));
  }else{
    // нет линии, моргаем крайними, настраиваем и сохраняем в EEPROM:
    blinkRed(3, 350, 150);
    autoLevel();
    writeEEPROM(snEEPROM, sensor, sizeof(sensor));
  }
}

/**
 * Считает величину ошибки линии от середины машинки
 * влево < 0, вправо > 0, ==0 -- линия посередине
 */
void calcDir()
{
  int      summ = 0;
  int8_t   count = 0;

//  Serial.println("");
  for( uint8_t i=0; i<MAX_SENSORS; i++ ){
    summ += snAdc(i) * snDir(i);
    count += snAdc(i);
    if( snAdc(i) == 1 ){
      digitalWrite(snLeds[i], HIGH); // датчик видит линию, включаем его светодиод
    }else{
      digitalWrite(snLeds[i], LOW); // не видит, выключаем.
    }
  }
//  Serial.print("summ="); Serial.print(summ, DEC);
//  Serial.print(", count="); Serial.print(count, DEC);

  // смотрим что получилось: если есть датчики на линии, то ошибка = сумма расстояний поделить на число датчиков на линии
  // иначе: линия потеряна и надо смотреть "где была" в прошлый замер
  prevDir = dir;
  if( count>0 ){
    dir = summ/count;
  }else{
    if     ( lastDir>0 ){ dir =  MAX_SENSORS; } // линия была справа - потерялась там же..
    else if( lastDir<0 ){ dir = -MAX_SENSORS; } // линия была слева ..
    else{
      // упс.. ехали прямо и потеряли линию .. продолжаем прямо
      dir = 0;
    }
  }

  // направление изменилось? нет: считаем сколько так уже едем, да: сохраняем текущее как "последнее" (last..), начинаем заново
  if( prevDir == dir ){
    dirCount++;
  }else{
    lastCount = dirCount;
    lastDir   = prevDir;
    dirCount = 1;
  }
//  Serial.print(", prevDir="); Serial.print(prevDir, DEC);
//  Serial.print(", dirCount="); Serial.print(dirCount, DEC);
//  Serial.print(", lastDir="); Serial.print(lastDir, DEC);
//  Serial.print(", lastCount="); Serial.print(lastCount, DEC);
//  Serial.print(", dir="); Serial.print(dir, DEC);
}
Все неопределенные тут переменные - глобалы из основного скетча движения по линии. Их значения должны сохраняться между вызовами loop().

Ошибка отклонения от линии считается как "среднее расстояние" всех датчиков на линии (что видят черное). Отсюда: важно иметь "средний или нулевой" датчик по центру линии. Его вес нулевой, но он участвует в количестве датчиков на линии, что позволяет отслеживать промежуточные значения от "веса" боковых датчиков +-1, +-3 и т.д. :)
Чтобы время нахождения датчиков четной ошибки и не четной было примерно одинаково, физическое расстояние между датчиками должно примерно соответствовать 2/3 от ширины линии. Это удобно для "узких" линий 15,20мм и не очень удобно для "русской" линии в 50мм. :)

Сохранение "предыдущих" значений в глобалах позволяет оперативно вычислять "радиус кривой" по которой сейчас едет тележка, что зная её вес, габариты, высоту центра тяжести и трение на колесах и передней опоре позволяет ТОЧНО вычислять максимально возможную скорость движения "конкретно сейчас" .. и быть "первым" по ТТХ моторов, веса и качества колес тележки.
:)

P.S. Собственно это всё, что надо знать, чтобы быть первым. :) Отсюда: ПИД-регулятро не есть "айс" .. :)
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Up.

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

Кстати, ссылки на моторы у Гайвера - битые частично. Обновить бы. :)

В общем, нашел что надо по отдельности, заказал. Пока буду делать звенья телескопа.

Итоговые размеры ожидаю такие:
сложенное состояние - 152х40х40мм (сама стрела без мотора, N20 - "снизу").
Развернутое состояние - 632х40х40мм :) 5 звеньев, с учетом корпуса.
Грузоподьемность около 1-2 кг.
Скорость выдвижения/втягивания около 1мм/сек.

Количество проводов удлинения - 16шт. С обоих сторон тупо разьемы.
Собственное оборудование - мотор (2 провода) + 2 концевых датчика (ещё 2 провода). Земля и Питание для концевиков из общей кучи удлининения.

Интересно, по результату - выкладывать?
 
Изменено:
  • Лойс +1
Реакции: Wan-Derer

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
По вопросу "телескопическая рука робота" создал отдельную тему в разделе "проекты в разработке". Приглашаю всех заинтригованных, заинтересованных, просто знатоков - "все в сад", пардон, в эту тему: https://community.alexgyver.ru/threads/ocherednaja-roboruka-nado-li.2373/ :)
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Я придумал название: "Проект АРГО" :)
Поразмыслив, принял Вашу версию.

Пусть будет "АР-ГО" ("Ar-Go!"). Озадачил жену (дизайнер все же!) наклепать логотип, что-то типа такого вижу:

АРдуино -
_____ как леГО!

или
ARduino -
_____ as leGO!

подчерки - сдвиг. В две строки. Не умеет этот движок втыкать табуляции..

Допилю "робо-руку" (из раздела проекты в разработке) - можно будет сделать наклейки.

Спасибо.
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Кстати, полистал вчера поисковики .. народу, который пытается срастить Лего и Ардуино - "выше крыши", но почему-то никто дальше "прикрутить к лего болтиками" или "прикрутить арудину резинкой(изолентой, скотчем)" дальше не идет. Ну и в основном, пользуется традиционное лего - кубиками, несмотря на то, что оно сильно непрочно всё в итого.

Нашел 2 стоящие идеи:
1. Обрамление Ардуино блока из дерева на лазерном резаке. Фанерка 4мм (как раз 1/2 Лего техник) с дырками по периметру, на которой крепится сам Ардуино блок. Типовыми крепежами (круглые пины 1 1/2) легко крепится к круглым лего-отверстиям.

2. Оформление серво-мотора SG90 под обычное лего распилом по толщине (1/3 примерно) техник - балки на 3 отвертсия и подклейка по бокам (длинным) сервы. Получается суммарная ширина в 2 лего-дырки (16мм) и серва хорошо садится на штырьки обычных лего-кирпичей. Ось подрезается на крест и на неё штатным болтом крепится шестеренка на 8,16,24 зуба или иная.
Если идею доработать с подклейкой крепления напротив оси вращения (как тут на фото раньше), то кмк, это здорово.

В общем понравилось. Жаль не сохранил ссыль..
 

ska_ska

✩✩✩✩✩✩✩
4 Дек 2019
3
0
По вопросу "телескопическая рука робота" создал отдельную тему в разделе "проекты в разработке". Приглашаю всех заинтригованных, заинтересованных, просто знатоков - "все в сад", пардон, в эту тему: https://community.alexgyver.ru/threads/ocherednaja-roboruka-nado-li.2373/:)
Вы, определенно, крутой папа
буду ваять ардуино для племянника, он уже подрос.
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Понадобились для приборчика RGB и ИК светодиоды .. наконец-то запилил комплект 5мм светодиодов в наше "Ар-го":
led5mm-1.jpgled5mm-2.jpgLed5mm-3.jpgLed-5mmRGB-2.jpg

Изготовлено по 4шт: 5-мм светодиодов: ИК, белый, красный, желтый, зеленый, синий и RGB. Так сказать "стадии процесса":
1. Как несущая поверхность выбраны лего детальки в 2 "дырки" - балка с поперечным крестовым отверстием. В её круглое отверстие светодиоды 5мм входят, после небольшой "фрезеровки" круглым надфилем очень удобно - практически не высовываются.
2. Поскольку токи свечения были выбраны "на пределе" (44мА - синий .. 52.5мА - ИК), потребовался ещё и мосфет для управления светодиодом со стороны Ардуино, а к нему приложился резистор для стекания заряда и запирания мосфета, когда нога Ардуино "на вход" в третьем состоянии. Второе фото - изготовлена "плата" по технологии сборки гибридных микросхем. :)
3. Основной блок светодиодов + RGB с платой "синий".
4. На плату "синий" сверху наклеена плата "зеленый" .. ещё выше будет "красный" (сделано конечно же) ..
Вот .. примерно так.

До кучки, в таком же лего собрал ещё 4 фототранзистора, но с баластным сопротивлением в 47кОм, вместо штатных 10кОм. Показалось что так диапазон работы несколько ширее получится.

P.S. мосфеты - "какие попали под руку" .. в основном попали si2300 - si2302 корпус SOT-23. Резисторы 68-130ом SMD1206. Мельче мне паять уже проблематично, как показала практика.
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
@ununnamed, так развился ужо. Куда дальше-то?

Не, тут есть ещё несколько начатых (к сожалению и брошенных) тем, куда стоит доразвить проект, но .. пока нет времени. Совсем нет ..честно, честно. ;)
 

Maincreator

✩✩✩✩✩✩✩
10 Окт 2023
1
0
Здравствуйте!

А где почитать тему №9, 12 и т.д.?
Это вы про нумерацию своих постов в этой ленте? Или где?
 

Arhat109

★★★★✩✩✩
9 Июн 2019
473
203
Да, это дополнение постов здесь же просто позже. Уведомление что сверху нечто поменялось..