нова електронна забавка: набір arduino oplà iot

| щоденник, arduino, програмування, проєкт, поновлюється

[поновлюється] побачив і не зміг втриматися — тепер маю нову цікаву електронну забавку: arduino oplà iot kit. набір включає контролер arduino mkr wifi 1010 і монтажну плату arduino mkr iot carrier з кольоровим екраном, сенсорними кнопками та датчиками температури, вологості й тиску тощо; і все це програмується. попередній власник награвся та виставив на барахольці kijiji, — тож… я поки що відклав конструктор freenove, щоби погратися цим.

набір arduino mkr iot

зміст

tl;dr

я лише зовсім трішечки погрався з arduino oplà iot, — але вже в захваті! надзвичайно класний набір: якісно зроблений, цікавий, чудово інтегрований (багато різних елементів і датчиків), і з великою кількістю якісної документації. на мою думку, це чудовий спосіб погратися і навчитися програмувати! ціна трохи кусається на перший погляд, особливо на amazon’і… але набір вартий чесної ціни на arduino.cc!

підготовка

що в наборі

мені продали коробку б/у, але з усіма компонентами:

  • плата контролера arduino mkr wifi 1010;
    • контролер atmel samd21 g18;
    • wifi, bluetooth, usb (micro);
  • монтажна плата arduino mkr iot carrier, на ній:
    • кольоровий екран 240x240 пікс.;
    • звуковий зумер;
    • п’ять сенсорних клавіш з багатоколірними світлодіодами;
    • датчик освітлення (і бібліотека для розпізнавання жестів);
    • датчики температури, вологості, атмосферного тиску;
    • акселерометр і гіроскоп;
    • три роз’єми grove (один i2c, два аналогових, для зовнішніх датчиків);
    • два реле (для керування живленням зовнішніх пристроїв);
    • роз’єм картки пам’яті micro sd;
    • тримач для акумулятора 18650 (може заряджатися від usb);
  • два зовнішніх датчики:
    • інфра-червоний;
    • щуп вологості грунту;
  • напівпрозорий корпус.

оскільки я взяв б/у, все було вже розпаковане, плати з’єднано й у корпусі. на додачу, я отримав два акумулятори формату 18650 на 3000 мАг і простенький зарядний пристрій (треба розібрати й полагодити підпружинений тримач). за ті гроші, що я віддав — це королівський набір.

(повернутися до змісту)

налаштування arduino ide

новий набір oplà iot дає рік безкоштовного доступу до arduino cloud, проте попередній власник цей час вже вибрав. як на мене, то й на краще: не люблю, коли виробники намагаються мене «залочити» на свої хмарні сервіси безкоштовним пончиком. тож питання вибору середовища навіть не постало — arduino ide на лептопі. я вже трохи з ним знайомий, ще з часів збирання «марсохода». версія 1.8.19 (legacy) була в aur, тож швиденько встановилася (команди для arch linux та похідних; для інших дистрибутивів буде інше, для windows чи mac — див. веб-сайт arduino.cc):

> pamac install arduino

далі — завантаження необхідних компонентів ide (core, бібліотеки) для arduino mkr wifi 1010 та arduino mkr iot carrier:

  • завантажити core для samd21 і вибрати «дошку» (arduino mkr wifi 1010);
  • підключити контролер кабелем usb й вибрати порт (див. заувагу нижче про групу uucp);
  • завантажити бібліотеки: Arduino_MKRIoTCarrier (підказка);
  • відкотити версію бібліотеки BSEC Software Library до 1.6.1480 (бо найновіша 1.7.1492 не захотіла працювати).

важливо! на linux, перш ніж можна буде залити тестову програму через usb на контролер, треба додати себе до групи uucp (і перезайти в профіль, або зробити su $USER і запускати arduino з консолі):

> sudo usermod -a -G uucp $USER

тепер можна пробувати «залити» найпростіший код для перевірки світлодіода, як пише підказка на офіційному сайті, але це не дуже цікаво… а ще мені конче треба було якнайшвидше перевірити, чи працює екран. тож…

(повернутися до змісту)

перевірка: hello, world

отже, перша, найпростіша програма — класичний «hello, world» (але на український манер):

#include <Arduino_MKRIoTCarrier.h>
MKRIoTCarrier carrier;                          // Об'єкт класу MKRIoTCarrier

void setup() {
  carrier.noCase();                             // Без корпуса (
  carrier.begin();                              // Ініціалізація монтажної плати

  // Перевірка екрана
  carrier.display.setRotation(0);               // Нормальна орієнтація
  carrier.display.fillScreen(ST77XX_RED);       // Червоне тло
  carrier.display.setTextColor(ST77XX_WHITE);   // Білий текст
  carrier.display.setTextSize(4);               // Великий шрифт
  carrier.display.setCursor(40, 110);           // Позиція для виводу (пікс.)
  carrier.display.print("PTN XLO");             // Український Hello, world =)

  // Перевірка зумера
  carrier.Buzzer.sound(500);                    // Частота зумера 500 Гц
  delay(100);                                   // Тривалість 100 мс
  carrier.Buzzer.noSound();                     // Відкл. зумер
}

void loop() {
  // 
  delay(1000);
}

hello, world! по-українському

(повернутися до змісту)

знайомство з arduino mkr iot carrier

екран

екран працює, що далі? найперше, я спробував навчитися вимикати екран, і це окрема цікава історія, що привела до вимірювання енергоспоживання набору arduino mkr iot за допомогою несправного мультиметра та кількох цікавих висновків. функція для вимикання/вмикання підсвітки екрана arduino mkr iot carrier може виглядати приблизно так:

# include <Arduino_MRKoTCarrier.h>
…
// керування підсвіткою екрана (true/false)
void backlight(boolean state) {
  pinMode(TFT_BACKLIGHT, OUTPUT);
  if (state) {
    digitalWrite(TFT_BACKLIGHT, HIGH);
  } else {
    digitalWrite(TFT_BACKLIGHT, LOW);
  }
}

цікаво, що коротка підказка з використання бібліотеки згадує TFT_BLACKLIGHT — ніхто не виправляє, хоча їхній код не працює і люди, ймовірно, перечіпляються через це?

далі — кольори; простенька самописна функція colorTest() виводить кольорову «шахівницю» довільного розміру, заповнюючи клітинки випадковими кольорами:

// випробування кольорів: кольорова гратка divX x divY з автоматичним обрахуванням кольорів
void colorTest(int divX, int divY) {
    int boxX = int(carrier.display.width() / divX);   // Розміри кольорових прямокутничків
    int boxY = int(carrier.display.height() / divY);  // розраховуються з кількості по x, y
    for (int y = 0; y < divY; y++) {
        for (int x = 0; x < divX; x++) {
          // Колір в бібліотеці Adafruit_ST7735 має тип uint16_t: rgb (5, 6, 5 біт) запаковані в 16 біт
          uint16_t color = random(0xFFFF);            // Випадковий колір
          carrier.display.fillRect(x*boxX, y*boxY, boxX, boxY, color);
        }
    }
}

кольори для екрану adafruit st77xx кодуються трохи незвично (ну, якщо не знати, що таке high color): по 5 біт на червоний та синій, 6 біт на зелений, запаковані в 16 біт. генерування випадкового кольору (тобто числа в діапазоні 0x0..0xFFFF) — це просто, але навряд чи дуже корисно. якщо потрібен якийсь конкретний колір, можна підглянути до невеликого переліку визначених кольорів (ST77XX_), або знайти значно довший перелік. але що як треба вивести конкретну тріаду rgb? в глибинах бібліотеки знайшлася функція color565() якраз для цього; з нею можна замість готової функції для малювання гратки написати іншу, котра малюватиме один блок «шахівниці» визначеним кольором:

// Конвертування кольорів RGB до 565: в кольоровій гратці замалювати прямокутник i,j кольором r,g,b)
void colorBlock(int divX, int divY, int i, int j, uint8_t r, uint8_t g, uint8_t b) {
   int boxX = int(carrier.display.width() / divX);      // Розмір блока по горизонталі
   int boxY = int(carrier.display.height() / divY);     // …по вертикалі
   uint16_t color = carrier.display.color565(r, g, b);  // Конвертування кольору rgb -> high color 565 
   carrier.display.fillRect(i*boxX, j*boxY, boxX, boxY, color);
}

тепер головний цикл для малювання «шахівниці» й випадкового перефарбовування «клітинок» може бути такий:

// Головний цикл (обов'язкове)
void loop() {
    int sizeX = 5, sizeY = 5;
    for (int y = 0; y < sizeY; y++) {               // Малюємо шахівницю 5x5
        for (int x = 0; x < sizeX; x++) {           // …випадковими кольорами
            colorBlock(sizeX, sizeY, x, y, random(255), random(255), random(255));
        }
    }
    while (true) {                                  // Перемальовуємо випадкову клітинку
        colorBlock(sizeX, sizeY, random(sizeX), random(sizeY), random(255), random(255), random(255));
        delay(1000);
    } 
}

далі буде…