Дело было вечером, делать было нечего

В этом посте опишу свой опыт работы с платформой 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

Пора сделать что-нибудь полезное. Например, индикатор загрузки сетевого интерфейса.
Алгоритм будет простой:

  1. На машине вычисляем текущую скорость на интерфейсе.
  2. Вычисляем процент загрузки.
  3. Вычисляем количество светодиодов, которые необходимо зажечь.
  4. Вычисляем контрольное число, которое характеризует набор светодиодов.
  5. Пересылаем его на МК.
  6. Зажигаем светодиоды средствами МК.
  7. ???
  8. 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, там хранится и обновляется в реальном времени разнообразная статистика по интерфейсам в текстовом виде. Линукс — сила!

А вот и результат. По ходу ролика включается-выключается закачка, ну и видно, как реагирует устройство.

Надо будет еще что-нибудь собрать.

Добавить комментарий

Ваш e-mail не будет опубликован.

Поставьте галочки правильно (как бы защита от спама):

Я бот

Я не бот