Arduino. Программирование роботов

В этой статье мы поговорим об интересном проекте Arduino. Arduino - это open-source проект, содержащий в себе примерный стандарт электронного устройства, среду разработки, bootloader, стандарт программирования и оформления новых библиотек.

Проект длится уже несколько лет, существует уже более 10 оригинальных плат производителя, но так как проект открытый, то пользователи и сторонние производители разработали просто бесчисленное множество устройств-клонов. Даже клонами их назвать сложно, так как зачастую отличаются они лишь внешним видом, моделью контроллера, питанием, интерфейсом связи с компьютером и бортовой периферией. Большинство проектов построены на базе контроллеров AVR: Mega8, 168, 328, 1280, 2560. Благодаря своей популярности проект среду разработки портировали на ARM контроллеры и даже есть вариант, где используется контроллер AVR со встроенным блоком ПЛИС.

По сути, ядро Ардуино может быть портировано на большинство ваших плат на базе AVR MEGA. Для этого достаточно зашить в него фирменный бутлодер и задействовать UART контроллера через USB-UART или COM-UART переходник. В последней модели UNO за связь с компьютером отвечает 2й контроллер, в него же можно зашить прошивку, при которой UNO будет распознана системой как устройство типа джойстика, мышки, клавиатуры и прочего.

Итак, давайте рассмотрим устройство с ног до головы.

1. Bootloader Arduino.

Последние версии платформы Ардуино базируются на бутлодере STK500V2.  На данный момент этот бутлодер поддерживает следующие модели контроллеров AVR Mega: ATmega8, ATmega16, ATmega32, ATmega8515, ATmega8535, AVR_ATmega162, ATmega128,  ATmega1280,  ATmega2560, AVR_ATmega2561.

Чтобы сделать  код мультиплатформенным, здесь применен распространенный метод, когда вместо обращения к регистрам и битам каждой платформы создается абстрактная надстройка в виде фиктивных  битов и регистров, вместо имен которых в код при компиляции подставляются адреса и номера битов выбранного контроллера.

Например для контроллеров ATmega8, ATmega16, ATmega32, ATmega8515, ATmega8535

#define UART_BAUD_RATE_LOW          UBRRL
#define UART_STATUS_REG             UCSRA
#define UART_CONTROL_REG            UCSRB
#define UART_ENABLE_TRANSMITTER     TXEN
#define UART_ENABLE_RECEIVER         RXEN
#define UART_TRANSMIT_COMPLETE    TXC
#define UART_RECEIVE_COMPLETE       RXC
#define UART_DATA_REG                    UDR
#define UART_DOUBLE_SPEED             U2X

Код бутлодера компилировался при помощи avr-gcc 4.1 из пакета WinAVR и занимает не более 1024 байт. Этот бутлодер может также использоваться с программой AVRISP, входящей в состав AVR Studio.

Работа бутлодера базируется на стандартах  Atmel Application Note AVR109 - Self-programming  и Atmel Application Note AVR068 - STK500v2 Protocol

Важными параметрами бутлодера являются частота кварцевого генератора и скорость обмена данными по UART.  По умолчанию они выставлены на 16МГц и 115200  бит/с.

Как уже было сказано, бутлодер осуществляет запись данных по заданному адресу памяти программ, в связи с этим для старших моделей контроллеров, где объем памяти программ более 64Кбайт появилась необходимость использования 32х разрядной адресации и под переменную адреса выделено уже 4 байта, для этого в коде проекта предусмотрено исключение.

#if defined(RAMPZ)
	typedef uint32_t address_t;
#else
	typedef uint16_t address_t;
#endif

Контроллер исполняет код бутлодера в течении 7 секунд с момента включения, при этом на плате Arduino может мигать светодиод с частотой 1 Гц. В случае превышения времени ожидания прошивка может быть осуществлена автоматически при наличии программного сброса на плате, либо путем ручного сброса контроллера.   Порт и номер бита светодиода отличается в зависимости от модели контроллера (платы) и вообще может быть задан.

Принимающий код контроллер рассматривается как конечный автомат и имеет 8 состояний:

#define ST_START               0
#define ST_GET_SEQ_NUM         1
#define ST_MSG_SIZE_1          2
#define ST_MSG_SIZE_2          3
#define ST_GET_TOKEN           4
#define ST_GET_DATA            5
#define ST_GET_CHECK           6
#define ST_PROCESS             7

Контроллер и компьютер обмениваются сообщениями, которые хранятся в буферной переменной unsigned char msgBuffer[285].    Текущее состояние принимающего автомата содержится в  переменной unsigned char msgParseState;

Во время приема данных вычисляется контрольная сумма. В случае несовпадения контрольной суммы принимающий автомат переходит в стартовое состояние,  и прием данных начинается снова.

В целом обмен полностью происходит через буфер msgBuffer. Ответ контроллера после записи данных во флеш-память также происходит путем перезаполнения этого массива и отправления его обратно в компьютер.  Перед этим происходит посылка байта MESSAGE_START, который предупреждает о начале приема ответных данных. После этого светодиод меняет свое состояние, и управления вновь передается в начало цикла, который продолжается до окончания посылаемых данных.

Bootloader Arduino имеет расширенные возможности, которые позволяют просмотреть такие полезные данные как версию компилятора, содержимое памяти программ, EEPROM, доступные порты, векторы прерываний и прочее.  Эти возможности включаются после объявления директивы ENABLE_MONITOR в коде бутлодера. В случае вызова (символ “!” ) запускается функция RunMonitor(), которая выводит по запросу  эти данные на компьютер пользователя.

Вывод: Bootloader Arduino обеспечивает запись данных в память программ и EEPROM. Работа базируется на стандарте команд AVR068 - STK500 Communication Protocol. Контроллер во время работы рассматривается как конечный автомат и имеет 8 состояний. Обмен данным ведется через буферный массив.  Существует возможность просмотра параметров контроллера, содержимого памяти программ, EEPROM, доступных портов, версии компилятора и много другого. Такое построение архитектуры обеспечивает Bootloader Arduino надежную и долговечную работу.

2. Основы работы ядра платформы Arduino

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

Главным в иерархии ядра является заголовочный файл WProgram.h. Использование этого файла подключает автоматически все файлы ядра.

  1. HardwareSerial.h

Содержит объявление класса HardwareSerial. Этот класс обеспечивает коммуникацию платы Ардуино через последовательный порт. Содержит в себе следующие методы:

void begin( long );             // Установление соединения с заданной скоростью
void end( void );               // Закрытие последовательного соединения
virtual int available( void );  // проверка наличия данных в приемном буфере
virtual int peek( void );       // читает данные из приемного буфера, но не удаляет их
virtual int read( void );       // читает данные из приемного буфера с их удалением
virtual void flush( void );     //помещает в приемный буффер наиболее старый по времени приема непрочитанный байт
virtual void write( uint8_t );  // записывает байт в регистр передачи данных по UART. Ждет отправки байта, т.е. доступности линии.

2. wiring.h

Этот файл содержит объявления математических констант и функций, таких как модуль числа, выделение максимального или минимального  из 2х чисел, округление до ближайшего целого, квадрат числа, разрешение прерываний, битовые операции и многое другое.

3. Print.h

Содержит класс Print. Основная задача этого класса вывод данных различного типа.  Основные методы Print и Println являются перегруженными, что позволяет выводить данные различного типа.

4. Wiring.c

Это очень важный исполняемый файл, так как здесь содержится инициализация таймеров и функции подсчета времени с момента включения платы. Кроме того этот файл подключает заголовочный файл wiring_private.h, в котором в зависимости от модели контроллера объявляются внешние прерывания: их названия и количество.  Стоит отметить,  что фукнция millis()  использует таймер 0, поэтому нужно помнить это, если есть намерения использовать 8 битный таймер 0 в своем приложении. Также здесь содержатся инициализации остальных таймеров контроллера, их значение коэффициента деления тактовой частоты по умолчанию для всех равно 64. С этим связаны проблемы пользователей при использовании таймеров такого вида:

TCCR1B |= (1<<CS00) | (1<<CS20) – в этом случае вместо коэффициент деления 1024 таймер перейдет в режим ввода тактовых колебаний на ножке T1. То есть будет получен совершенно неожиданный результат. Правильно будет:

TCCR1B = (1<<CS00) | (1<<CS20)

5.pins_arduino.с

В этом файле в зависимости от модели контроллера объявлены массивы наименований портов и соответствующие им ножки контроллера. Порядок следования при объявлении определяет номер соответствующей ножки. Для редактирования или дополнения портов ввода/вывода редактированию подлежит именно этот файл. Тоже самое  относится к портам таймеров.

6. WCharacter.h

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

7. String.h. Содержит объявление класса String для работы с массивами символов. Включает строковые операторы, а также различные функции работы со строками в виде следующих методово: поиск подстроки, преобразование символов,  замены символов и многое другое.

8. wiring_analog.h

Содержит объявление 2х важный функции analogRead(pin) – чтение напряжения на ножке контроллера с помощью АЦП и analogWrite(pin) – установление ШИМ с заданной скважностью. Необходимо отметить, что используется аппаратный ШИМ, поэтому эта функция доступна лишь для выделенных ножек контроллера.

9. wiring_digital.c

Этот файл ответственен за работу с портами ввода/вывода: установка типа порта (на вход и на выход) и текущего логического значения на ножке., проверка логического уровня при работе на вход. Может работать с ножками, на которые выводится аппаратный ШИМ.

10.  WMath.cpp

Этот исполняемый файл содержит функции возвращения псевдослучайного  числа.

11. WInterrupts.c

Здесь содержатся функции открытия и закрытия внешних прерываний.

12. wiring_pulse.c

Содержит функцию измерения времени между изменениями логического уровня на заданной ножке. С       высокого на низкий. Работает с длительностями от 2 до 180 секунд.

13. Tone.cpp

Содержит функцию вывода колебаний типа меандр с заданной частотой на заданную длительность на выбранную ножку контроллера.

14. main.cpp. Здесь содержится функция стартовой инициализации, а также фукнции setup() и loop(), которые пишутся в Arduino Sketch.

Вывод: Arduino IDE – это надстройка над основным кодом, которая предоставляет удобный инструмент для работы с периферией контроллера, а также основные математические функции. Благодаря такой архитектуре  ядро легко может быть доработано, а также обеспечена работа на новых контроллерах.

3. Создание новых библиотек Ардуино.

Библиотеки Ардуино –  классы, написанные на языке C++. Это позволяет делать компилятор WINAVR, интегрированный в IDE Arduino.  Все стандартные библиотеки расположены в папке Arduino\libraries. Здесь же нужно располагать и новые библиотеки. Для этого достаточно создать там новую папку с именем новой библиотеки и расположить там свой код.

Пример создания новой библиотеки:

#ifndef SHARP_H
#define SHARP_H
#ifndef WProgram_h
#include	"WProgram.h" // Этот файл отрывает нам доступ к функциям ядра
#endif
 
#define Vcc 5u  //напряжение питания цифровой части
 
// коэффициенты аналогового сигнала УЗ дальномера GP2D120
#define K (-1) // калиброванные коэффициенты ИК дальномера GP2D120
#define M 2914u
#define B 5u
#define AN (9.8 / (1000 * 25.4))
 
// коэффициенты аналогового сигнала УЗ дальномера GP2D12
#define M1 6787u
#define B1 (-3)
#define K1 (-4)
 
// коэффициенты аналогового сигнала УЗ дальномера GP2Y0A02YK0F
#define M2 96810u
#define K2 (-29)
#define B2 1
// коэффициенты аналогового сигнала УЗ дальномера GP2Y0A21YK0F
#define M3 6787u
#define B3 (-3)
#define K3 (-4)
enum IRType {GP2D120=0, GP2D12=1, GP2Y0A02YK0F=2, GP2Y0A21YK0F=3} ; // типы испольуемых датчиков
class VSharp
{
 
	unsigned char m_port;
	IRType m_IRSensor;
 
 
	VSharp(const VSharp&);
	VSharp& operator=(const VSharp&);
public:
 
	VSharp(unsigned char port, IRType IRSensor);
	template <uint8_t width>
	int GetADCMedian();
	int SuperGauss();
	float GetDistanceIR();
 
};
template <uint8_t width>
int VSharp::GetADCMedian()
{
	int DataADC[width];
	    int temp;
	    for (uint8_t i = 0; i < width; ++i)
	        DataADC[i] = analogRead(m_port);
	    for (uint8_t i = 0;i < width; ++i)
	        for (uint8_t j = 0; j < width - 1; ++j)
	            if (DataADC[j + 1] < DataADC[j]) {
	                temp = DataADC[j];
	                DataADC[j] = DataADC[j + 1];
	                DataADC[j + 1] = temp;
	            }
	    return DataADC[width >> 1];
 
}
#endif

Содержимое Sharp.c:

#include "Sharp.h"
 
VSharp::VSharp(uint8_t port, IRType IRSensor) :
		m_port(port),         //члены класса
		m_IRSensor(IRSensor)
{
	pinMode( m_port, INPUT);  //этот код выполняется при создании класса
}
 
int VSharp::SuperGauss()
{
    int gauss[5];
    for (uint8_t i = 0;i < 5; ++i)
     gauss[i]=GetADCMedian<5>();
    return (((gauss[0] + gauss[4]) >> 4) + ((gauss[1] + gauss[3]) >> 2) + 3 * ((gauss[2] >> 3)));
}
 
float VSharp::GetDistanceIR()// выдает расстояние до препятствия в ММ
{
    float temp = SuperGauss();
    switch (m_IRSensor) {
    case GP2D120:
        return (10 * ((M / (temp + B)) + K) < 300) ? 10 * ((M / (temp + B)) + K) : 300;
    case GP2D12:
        return (10 * ((M1 / (temp + B1)) + K1) < 500) ? 10 * ((M1 / (temp + B1)) + K1) : 500;
    case GP2Y0A02YK0F:
        return ((M2 / (temp * B2 + K2)) < 1200) ? M2 / (temp * B2 + K2)  : 1200;
    case GP2Y0A21YK0F:
        return ((M3 / (temp * B3 + K3)) < 650) ? M3 / (temp * B3 + K3) : 650;
    }
}

Для использования класса достаточно создать новый эскиз в среде Arduino, создать объект данного класса:

#include <Sharp.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
 
static VSharp Sensor1(14,GP2D120); // Sensor1 – объект класса VSharp, 14 – номер ножки контроллера, куда подается аналоговый сигнал дальномера
 
void setup()
{
}
 
void loop()
{
    int a = Sensor1.GetDistanceIR();
}

Вывод:  Возможности языка С++ делают удобным создание новых библиотек,   код получается наглядным, в нем можно быстро разобраться.  Используя данный подход можно создавать программное обеспечение для работы с различным оборудованием.

Файлы проекта можно скачать из статьи по дальномерам Sharp.

Если открыть Arduino IDE и вставить туда свой код, получим следующее:

Внизу указан размер кода в памяти программ из общего размера флеш данного контроллера.  При прошивке нужно правильно выбрать плату в разделе tools/board.  Библиотеки Ардуино можно добавить, нажав sketch/import library

В Ардуино доступны на данный момент следующие библиотеки для работы с :

- знакосинтезирующим дисплеем (на основе HD44780)

- энергонезависимой памятью EEPROM

- обмена данными по Ethernet

- для работы с LCD дисплеем

- работы со светодиодными матрицами

- работы с SD картами

- UART

- шаговыми двигателями

- организации 1-wire обмена данными

- управления сервомашинками

- обмена данными по SPI

Не буду останавливаться подробно, список команд и описание на русском можно, например, найти тут.

Итак, вы сделали свой небольшой проект на этой платформе, допустим датчик температуры, и теперь хотите чего-то большего, например, организовать свой домашний сервер, иметь к нему доступ, вести логи данных, то вам нужен Processing IDE. Он также, как и Arduino IDE написан на JAVА, для этой среды есть библиотека Arduino и вы можете использовать ресурсы вашей платы при написании кода на обычном PC. По сути, это существенно расширяет ваши возможности. Пример на картинке:

Какие основные библиотеки доступны в Processing?

- Видео

- OpenGL

- Network

- Аудио

- PDF Export

- RS-232

- Ардуино

- DXF экспорт

- OpenCV

Это далеко не все, я когда наткнулся на этот проект, был поражен размахом и идеей. С полным списком возможностей можно ознакомиться здесь. Как вы видите, это приложение очень похоже на Arduino IDE, кстати, в последнем часть примеров идет кодом и для Processing

4. Делаем свою Arduino. Итак, для тех, для кого оригинал платы недоступен, или кажется дорогим, давайте сделаем сами плату. Будем использовать исключительно дырочный монтаж, так как вам придется все делать вручную. На сайте доступен проект платы Arduino Severino.

Принципиальная схема:

 

 

Список компонентов
POSITION VALUE DESCRIPTION DETAIL
С1 22pF (22 pico Farad) ceramic disc capacitor
С2 22pF (22 pico Farad) ceramic disc capacitor
СЗ 100nF (100 nano Farad - or 0.1 micro Farad) ceramic or polyester capacitor
С4 100nF (100 nano Farad - or 0.1 micro Farad) ceramic or polyester capacitor
С5 100(jF (100 micro Farad) electrolytic capacitor 16volts (or more: 25v) radial-lead
С6 100nF (100 nano Farad - or 0.1 micro Farad) ceramic or polyester capacitor
С7 100nF (100 nano Farad - or 0.1 micro Farad) ceramic or polyester capacitor radial-lead
С8 100(jF (100 micro Farad) electrolytic capacitor 16volts (or more: 25v) radial-lead
С9 10(jF (10 micro Farad) non-polarized electrolytic capacitor 16volts (or more: 25v, 50v) radial-lead
D1 1N4004 diode DO41-10
D2 1N4148 diode DO35-10
D3 1N4148 diode DO35-10
DC1 2.1mm. DC power jack
IC1 ATMEGA8 (or ATMEGA168) 28P3 package
IC2 7805C Tension Regulator
ICSP 2x3 male pin header ICSP
Л 1x8 female pin header 0.1" (or 2.54 mm.) PORT D(D0-D7)
J2 1x6 female pin header 0.1" (or 2.54 mm.) PORT C(A0-A5)
J3 1x8 female pin header 0.1" (or 2.54 mm.) PORT B(D8-D13)
JPO 1x3 right angle pin header 0.1" (or 2.54 mm.)
JP4 1x2 right angle pin header 0.1" (or 2.54 mm.) AUTO RESET
L1 100(jH leaded inductor axial leaded (silver)brown, black, brown, golden
LEDO 3 mm. LED choose a color Rx Led
LED1 3 mm. LED choose a color Tx Led
LED13 3 mm. LED choose a color Pin13 Led
LED14 3 mm. LED choose a color Power Led
POWER 1x6 female pin header
Q1 16 MHz crystal
R1 1kohm (1.0 kilo ohm) Resistor 1/4 Watt, ±5% brown, black, red, gold
R2 1kohm (1.0 kilo ohm) Resistor 1/4 Watt, ±5% brown, black, red, gold
R3 1kohm (1.0 kilo ohm) Resistor 1/4 Watt, ±5% brown, black, red, gold
R4 1kohm (1.0 kilo ohm) Resistor 1/4 Watt, ±5% brown, black, red, gold
R5 10kohms (10.0 kilo ohms) Resistor 1/4 Watt, ±5% brown, black, orange, gold
R6 1kohm (1.0 kilo ohm) Resistor 1/4 Watt, ±5% brown, black, red, gold
R7 10kohms (10.0 kilo ohms) Resistor 1/4 Watt, ±5% brown, black, orange, gold
R8 10kohms (10.0 kilo ohms) Resistor 1/4 Watt, ±5% brown, black, orange, gold
R9 4k7ohms (4.7 kilo ohms) Resistor 1/4 Watt, ±5% yellow, violet, red, gold
R10 10kohms (10.0 kilo ohms) Resistor 1/4 Watt, ±5% brown, black, orange, gold
R11 10kohms (10.0 kilo ohms) Resistor 1/4 Watt, ±5% brown, black, orange, gold
S1 6x6 mm., 4 terminals Switch Tactile B3F-10XX
Т1 BC547 Transistor NPN general purpose transistor T092
Т2 BC557 Transistor PNP general purpose transistor T092
Х1 9 PIN FEMALE RIGHT ANGLE PC MOUNT D-SUB CONNECTOR DE-9 CONNECTOR
jumper 0.1" (or 2.54 mm.)
jumper 0.1" (or 2.54 mm.)

Плата односторонняя.

 

 

 

 

 

 

 

 

 

Внизу статьи будет выложена документация, печатку можно брать оттуда и делать оттиск для ЛУТ. Я так и сделал в свое время. Вот только при конвертировании видимо возникли искажения, поэтому некоторые ножки встали "ежиком",  рекомендую проверить размеры рисунка перед оттиском. Кстати, плата в основе имеет Atmega 8, вообще выбор контроллеров немного странный, например нет моделей с ATmega16,32 на борту, хотя они тоже имеют классический through-hole, просты в установке.

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

В результате вы получите примерно такой результат:

Кстати, стоит обратить внимание, как сделан преобразователь уровней UART-RS232. Для этого используются 2 транзистора разной проводимости. При этом работает эта связка вполне приемлемо. Прошивка платы хранится где-то в недрах Arduino дистрибутива.

Вот такая простая платка позволит вам попробовать все возможности Arduino IDE, даже вкупе с Processing. Все бы было хорошо, но как сказал один известный человек:  теоретически практика ничем не отличается от теории, но на практике они различны. Это означает, что при работе с Ардуино часто происходит то, что не получается объяснить, частично это связано с ядром проекта, частично со сложностью отладки, ведь отладчика-то НЕТ. Но все же это изделие является, на мой взгляд, лучшим вариантом, с чего нужно начать начинающему робототехнику.

Полезные ссылки:

Среда разработки Arduino IDE.  Качаем последний релиз.

Среда разработки Processing.

Документация по Arduino Severino для тех, кто хочет сделать сам.

Список команд для Arduino с описание на русском

Описание библиотек Processing

Leave a Reply

You must be logged in to post a comment.