Разработка → Android + Arduino = ♥

blo 4 июля 2011 в 14:48 94,1k
Не так давно Google открыл API для работы Android устройств с USB. Сегодня пришло время пощупать что же это такое и узнать какие возможности нам открываются.




Итак, у нас имеется Arduino Mega 2560, USB Host Shield и HTC Desire с прошивкой cyanogen 7.1.0 RC1 (Android 2.3.4). На всякий случай напомню, что все что будет описываться дальше — работает только начиная с Android 2.3.4 для телефонов и Android 3.1 для планшетов.
Тут стоит отметить что данный USB Host Shield не совсем удачный, особенно в сочетании с Arduino Mega 2560. Первая проблема заключалась в том что данная плата расширения сделана для Arduino UNO, а она отличается от Mega положениями контактов SPI, поэтому пришлось кидать перемычки (см. фото). Второй проблемой, хотя и вполне ожидаемой, стала потребность во внешнем источнике питания для работы этой платы расширения. Более удачной считается USB Host Shield 2.0 от Circuits@Home, но она и дороже.


Плата с перекинутыми SPI контактами

Настройка Arduino ПО


1. Если еще не установлено, то скачать и установить ПО для Arduino.
2. Скачать и распаковать пакет ADK (содержит DemoKit приложение). Должны появится папки app, firmware, и hardware.
3. Скачать библиотеку CapSense
4. Скопировать firmware/arduino_libs/AndroidAccessory и firmware/arduino_libs/USB_Host_Shield в <arduino_installation_root>/libraries/.
5. Создать директорию CapSense в <arduino_installation_root>/libraries/ и скопировать в нее CapSense.cpp и CapSense.h из архива CapSense.

Загрузка прошивки


Google любезно предоставляет свой DemoKit скетч для Arduino. Все что нужно — это открыть его из firmware/demokit/demokit.pde, скомпилировать и залить на плату.

Тестовое Android приложение


В DemoKit пакете также находятся исходники Android приложения для демонстрации возможностей. Google предлагает нам самостоятельно создать Android проект и собрать это приложение. Для начала нам надо будет установить API Level 10. Дальше все просто — создаем Android проект и указываем путь к папке app, в Build Target указываем Google APIs (Platform 2.3.3, API Level 10). Собираем приложение и устанавливаем на телефон. Кто не хочет возится со сборкой — может скачать готовый APK.

Запуск


Просто подключаем наш телефон к USB Host Shield. Если мы все сделали правильно, то на экране появится запрос запуска DemoKit приложения.



Само приложение содержит две вкладки — In (кнопки, джойстик и сенсоры) и Out (светодиоды, реле и сервоприводы).



Я решил что для демонстрации вполне достаточно пары светодиодов и кнопки. Как это все чудо работает можно пронаблюдать на видео.



Немного кода


В рассматриваемом примере сообщения, передающиеся по USB, состоят из трех байтов:
1-й байт определяет команду или группу устройств, например светодиоды — 0x2
2-й байт указывает на конкретное устройство, например зеленый светодиод — 0x1
3-й байт содержит значение, передаваемое устройству, например максимальная яркость — 0xff

Arduino


...
/* инициализация */
AndroidAccessory acc("Google, Inc.",
                     "DemoKit",
                     "DemoKit Arduino Board",
                     "1.0",
                     "http://www.android.com",
                     "0000000012345678");
void setup()
{
    ....
    acc.powerOn();
}

void loop()
{
    byte msg[3];
    /* проверка подключения */
    if (acc.isConnected()) {
        /* получение сообщения от Android устройства */
        int len = acc.read(msg, sizeof(msg), 1);
        if (len > 0) {
            /* сообщение для светодиодов */
            if (msg[0] == 0x2) {
                if (msg[1] == 0x0)
                    analogWrite(LED3_RED, msg[2]);
                else if (msg[1] == 0x1)
                    analogWrite(LED3_GREEN, msg[2]);
                else if (msg[1] == 0x2)
                    analogWrite(LED3_BLUE, msg[2]);
            }
        }

        msg[0] = 0x1;

        b = digitalRead(BUTTON1);
        if (b != b1) {
            msg[1] = 0;
            msg[2] = b ? 1 : 0;
            /* отправка состояния кнопки */
            acc.write(msg, 3);
            b1 = b;
        }
        
    }
}


Android


import com.android.future.usb.UsbAccessory;
import com.android.future.usb.UsbManager;
...
public class DemoKitActivity extends Activity implements Runnable {
    private UsbManager mUsbManager;
    UsbAccessory mAccessory;
    FileInputStream mInputStream;
    FileOutputStream mOutputStream;

    ...

    private void openAccessory(UsbAccessory accessory) {
        mFileDescriptor = mUsbManager.openAccessory(accessory); 
        if (mFileDescriptor != null) {
            mAccessory = accessory;
            FileDescriptor fd = mFileDescriptor.getFileDescriptor();
            mInputStream = new FileInputStream(fd);
            mOutputStream = new FileOutputStream(fd); 
            Thread thread = new Thread(null, this, "AccessoryThread");
            thread.start();
        }
    }

    public void run() {
        int ret = 0; 
        byte[] buffer = new byte[16384]; 
        int i;

        while (ret >= 0) { 
            // получение входящих сообщений
            ret = mInputStream.read(buffer); 

            i = 0;
            while (i < ret) {
                int len = ret - i; 
                switch (buffer[i]) {
                    case 0x1: // сообщение от кнопки
                        if (len >= 3) {
                            Message m = Message.obtain(mHandler, MESSAGE_SWITCH); 
                            m.obj = new SwitchMsg(buffer[i + 1], buffer[i + 2]);
                            mHandler.sendMessage(m);
                        }
                        i += 3;
                        break; 
                }
            }
        }
    }

    // пример использования - включить красный светодиод на полную яркость:
    // mActivity.sendCommand((byte)2, (byte)0, (byte)255)
    public void sendCommand(byte command, byte target, int value) {
        byte[] buffer = new byte[3];
        if (value > 255)
            value = 255;

        buffer[0] = command;
        buffer[1] = target;
        buffer[2] = (byte) value;
        if (mOutputStream != null && buffer[1] != -1) {
            try {
                mOutputStream.write(buffer);
            } catch (IOException e) {
                ...
            }
        }
    } 
}


Выводы


Открывая такие возможности Google в первую очередь конечно же рассчитывает на появление большого числа активных Android аксессуаров, но далеко не последнее место занимает тот факт, что по сути мы получаем удобное устройство для взаимодействия с различными датчиками, сенсорами и приводами. Такое устройство запросто может стать мозгом чего-то роботизированного.

Также нельзя забывать о том, что Android устройство для Arduino может выполнять роль платы расширения, в которой есть GPS, Bluetooth, WiFi, акселерометр и многое другое.

Ссылки


1. Android USB Accessory
2. Android Open Accessory Development Kit
Проголосовать:
+97
Сохранить: