В этом посте опишу свой опыт работы с платформой Arduino (а точнее, с ее аналогом Freeduino). Под катом рассказ, как можно заполучить себе схемку, как писать для нее под Линуксом, а также небольшой пример использования — визуализатор загрузки сети.
Arduino — небольшая платформа для любителей микроэлектроники. Существует в различных исполнениях, формфакторах, с разными микроконтроллерами на борту. Выбранный мной от балды вариант — Arduino Duemilanove. А точнее, ее полный аналог Freeduino 2009. Создатели оригинала ничего не имеют против свободного распространения платформы, поэтому и возник проект Freeduino.
Схему заказывал год назад у вышеозначенных товарищей из Кемерова (не реклама). Посылка пришла в срок, все было красиво упаковано, внутри кроме собственно схемы инструкция-техпаспорт, мини-CD с каким-то ПО, кругленький разъем для питания. Сама схема сделана добротно, видимо, в заводских условиях.

Сердцем схемы является AVR-микропроцессор ATmega328. Для прошивки доступно 30 килобайт из 32, еще 2 килобайта занимает загрузчик, который позволяет легко заливать новые прошивки. Стало быть, можно особо не экономить на размерах. Прошивки получаются компиляцией кусочков кода, которые называются скетчами. Скетчи пишутся на C-подобном языке Processing.
Для Debian есть пакет arduino в репозитории. Для установки потребует JRE + потянет за собой avr-* библиотеки. В моем случае в testing-репозитории пакета не нашлось, можно было сделать apt-pinning и поставить из stable или unstable, но в итоге я просто скачал пакет+зависимости руками и поставил через dpkg.
При подключении схемы к USB-порту компьютера должно появиться новое устройство /dev/ttyUSB0 (если не — смотрите в ядре поддержку FTDI чтоль). Работает как эмулятор последовательного порта — можно писать и читать символы. Владелец устройства — root:dialout, поэтому если хочется работать с ним не от рута, нужно добавиться в группу dialout:
root@dmws:~# usermod -a -G dialout mic root@dmws:~# groups mic mic : mic dialout cdrom floppy sudo audio dip video plugdev
Пора сделать что-нибудь полезное. Например, индикатор загрузки сетевого интерфейса.
Алгоритм будет простой:
- На машине вычисляем текущую скорость на интерфейсе.
- Вычисляем процент загрузки.
- Вычисляем количество светодиодов, которые необходимо зажечь.
- Вычисляем контрольное число, которое характеризует набор светодиодов.
- Пересылаем его на МК.
- Зажигаем светодиоды средствами МК.
- ???
- PROFIT!
Скетч:
void setup() {
// Включаем последовательный порт:
Serial.begin(9600);
// Инициализируем выходы:
for (int i = 1; i <= 8; i += 1) {
pinMode(i, OUTPUT);
digitalWrite(i, LOW);
}
}
void loop() {
if (Serial.available()) {
// Читаем очередной символ:
int signal = Serial.read();
// Пробегаемся по битам полученного символа и выставляем на соответствующих
// выводах соответствующие уровни:
for (int i = 1; i <= 8; i += 1) {
int level = ((signal >> (i - 1)) & 1) ? HIGH : LOW;
digitalWrite(i, level);
}
delay(200);
}
}
Python-скрипт:
# coding=utf8
'''
Управляющая часть.
@author: Mic, 2011
'''
from time import sleep
# Задержка между опросом:
DELAY = 0.2
# Максимальная скорость интерфейса (байт/сек):
MAX_SPEED = 1024 * 1024
# Количество доступных индикаторов:
LED_COUNT = 6
def get_current_received():
'''
Возвращает количество байт, полученных в данный момент на интерфейсе.
@return: int
'''
return int(open('/proc/net/dev').read().split('x0A')[3].split(' ')[3])
def get_active_led_count(workload):
'''
Возвращает количество светодиодов, которые надо зажечь.
@param workload: float
@return: int
'''
return int(max(workload // (100.0 / LED_COUNT), 1))
def get_signal_value(led_count):
'''
Возвращает число, характеризующее набор светодиодов.
@param led_count: int
@return: int
'''
return min(sum(2 ** i for i in range(led_count)), 255)
def send_signal(signal):
'''
Отправляет сигнал в порт.
@param signal: int
'''
output = open('/dev/ttyUSB0', 'w')
output.write(chr(signal))
output.close()
prev = 0
current = 0
while True:
current = get_current_received()
if prev:
speed = (current - prev) * (1 / DELAY)
workload = speed * 100 / MAX_SPEED
led_count = get_active_led_count(workload)
signal = get_signal_value(led_count)
send_signal(signal)
data = (speed / 1024, workload, led_count, signal)
print 'now speed is %4dkb/s, workload is %6.2f%%, led count is %d, signal is %3d'%data
prev = current
sleep(DELAY)
Скорость вычисляем на основе данных из /proc/net/dev, там хранится и обновляется в реальном времени разнообразная статистика по интерфейсам в текстовом виде. Линукс — сила!
А вот и результат. По ходу ролика включается-выключается закачка, ну и видно, как реагирует устройство.
Надо будет еще что-нибудь собрать.