В этом посте опишу свой опыт работы с платформой 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, там хранится и обновляется в реальном времени разнообразная статистика по интерфейсам в текстовом виде. Линукс — сила!
А вот и результат. По ходу ролика включается-выключается закачка, ну и видно, как реагирует устройство.
Надо будет еще что-нибудь собрать.