2012年2月28日 星期二

StencylWorks--"Scratch-like"App開發工具

StencylWorks--"Scratch-like"App開發工具
http://jimmyscratchlab.blogspot.com/2012/02/stencyl-scratch-like-tool.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+blogspot%2FSHxmZ+%28Jimmy%E6%A9%9F%E5%99%A8%E4%BA%BA%E7%A9%8D%E6%9C%A8%E8%BB%9F%E9%AB%94%E5%AF%A6%E9%A9%97%E5%AE%A4%29
http://www.stencyl.com/
http://www.stencyl.com/help/istencyl/

Netduino 與 Android 藍芽通訊


Android 自從發表 ADK 後,與 Arduino已經變成好兄弟了,但是 Netduino 該如何與 Android 通訊呢?
參考網路上有個 Amarino計畫,是使用藍芽模組完成 Android 與 Arduino之間通訊的一組程式庫,將這個程式庫改寫一下應該也可讓 Netduino 與 Android 變成麻吉吧。
image
我所使用的藍芽模組是 sparkfun 的 Bluetooth mate Gold (WRL09358),有六個接腳,由左而右依序是DTS-0、RX-1、TX-0、VCC、CTS-1、GND。產品特色如下,特色第一點就表明這是為 Arduino 所設計的...,Netduino應該也可用吧?
Designed to work directly with Arduino Pro's and LilyPad main boards
FCC Approved Class 1 BluetoothR Radio Modem
Very robust link both in integrity and transmission distance (100m) - no more buffer overruns!
Low power consumption : 25mA avg
Hardy frequency hopping scheme - operates in harsh RF environments like WiFi, 802.11g, and Zigbee
Encrypted connection
Frequency: 2.4~2.524 GHz
Operating Voltage: 3.3V-6V
Serial communications: 2400-115200bps
Operating Temperature: -40 ~ +70C
Built-in antenna
image image
手機端是使用 Amarino 範例改寫的一個簡單程式(如下圖左側),手機畫面左上角的 Button 按鈕可以將按鈕下面的數值(圖片中的數字1)不斷增加兩倍,並且透過無線藍芽送出到藍芽模組,再轉送給 Netduino,進而控制接在 pin9 的LED的亮度。(1~最暗、128~最亮)
image
Netduino 控制板的 analog Input 0 連接一個可變電阻,選轉可變電阻可以改變類比輸入電壓,進而轉換成數位值(介於0~1023),手機端左上角中間的數字(圖片中的537),就是接收 Netduino 經由藍芽模組發送過來的數值資料,手機下方的白底紅線圖是這個數值資料在時間軸上所畫出來的折線圖。
下圖是實驗線路,
image     

接下來就是影片時間了,影片中先試著連續按下Button,可看到數值不斷變大,同時 Netduino 連接的LED也不斷變亮,再來就是旋轉可變電阻,可以觀察到手機程式的數值也不斷變化,同時也畫出了圖形。過程都是透過藍芽無線傳輸。

2012年2月21日 星期二

HTC desire HD 透過ADK與 Arduino 通訊

經過一番努力,我的HTC desire HD終於順利執行ADK內的demokit程式,與Teemino控制板(Arduino 2560 ADK相容板)雙向通訊,辛苦總算有代價

剛開始連接Teemino控制板,HTC總是會跳出如下圖的選擇連線類型,不論選哪一個都會出問題,

image

後來才知道要先將 "詢問USB連線類型" 關掉,方法是: 點選設定->連線至PC->USB連線類型->詢問 (取消打勾)

imageimageimage

接下來才能看到 demokit 的起始畫面,但是剛開始試著將Teemino控制板連上時,demokit 總是無法感應到已經有arduino相容的控制板連上線,讓我一直以為可能是線路有問題,或是硬體有問題,

image

後來才知道要修改 Arduino 端的測試程式, 原因應該是 Teemino控制板上面並沒有內建小搖桿,所以原本測試程式執行到有關搖桿的程式,就會有問題。
修正程式後,終於看到令人感動的畫面。

image

測試程式內容包含
1.可以接收 Arduino 端3個digital input 按鈕,當按下按鈕時,Android 螢幕上對應的 B1 B2 B3 也會隨之點亮。
2.可以接收 Arduino 端2個analog input。

image

3.可以控制 digital output,按下 Relay1、Relay2,可以看到麵包板上的LED燈被點亮
4.可以控制 Arduino 的PWM輸出,例如捲動Servo0捲軸,可以看到伺服馬達隨之轉動
   同樣的拉動led1的捲軸,麵包板上對應的LED的亮度,也會隨之改變。

以上測試大致成功,但是在手機上送出控制訊號到Arduino,直到看到反應,時間拖的有點長,反應很遲緩,我是否該換手機了??

2012年2月16日 星期四

如何讓 Arduion 1.0 能夠編譯 ADK 範例韌體 demokit.ino

 

ADK (Android Open Accessory Development Kit)裡面附了一個 Arduino 的範例程式,可以用來與 Android 平台測試連結,但是只能在 Arduino-0023下順利編譯,如果放到Arduino 1.0就會出現錯誤訊息,因此必須修改原始程式才行。修改步驟如下:

1.下載、安裝 Arduino 1.0。

2.下載ADK(http://developer.android.com/guide/topics/usb/adk.html),解壓縮得到兩個子目錄(firmware/arduino_libs/AndroidAccessory 以及 firmware/arduino_libs/USB_Host_Shield)複製到 <arduino_installation_root>/libraries/ 之下。

3.下載位置CapSense (http://www.arduino.cc/playground/Main/CapSense)
解壓縮CapSense得到子資料夾,複製資料夾CapSense 到<arduino_installation_root>/libraries/ 之下

4.修改以下檔案的內容

<arduino_installation_root>\libraries\USB_Host_Shield\Max3421e.h Line37
        #include "WProgram.h" 改成=> #include " Arduino.h "

<arduino_installation_root>\libraries\AndroidAccessory \AndroidAccessory.h Line20
       #include "WProgram.h" 改成=> #include " Arduino.h "

<arduino_installation_root>\libraries\USB_Host_Shield\Max_LCD.cpp Line38
       #include "WProgram.h" 改成=> #include " Arduino.h "

       inline void Max_LCD::write(uint8_t value) { 改成=> inline size_t Max_LCD::write(uint8_t value) {

<arduino_installation_root>\libraries\USB_Host_Shield\Max_LCD.h Line101
      virtual void write(uint8_t); 改成=> virtual size_t write(uint8_t);

PS.如果在測試程式內出現Wire.receive改成=> Wire.read
PS.如果在測試程式內出現Wire.send 改成=> Wire.write

5.啟動Arduino1.0,選擇正確的Serial port 以及 Board代號(Arduino Mega 2560 or Mega ADK)
clip_image002

6. 開啟 demokit.ino ,編譯應該可以成功,若仍然有問題就將程式內有關 joystick 相關的程式碼通通disable,(修改完畢的程式  http://xduino.blogspot.com/2012/02/apk-demokitino-arduion-10.html)

7.接下來下載程式到 Arduino Mega ADK控制板上(我是用 Teemino),就可以成功與Android平台連結了。

image

2012年2月15日 星期三

ADK範例韌體 demokit.ino --- 修正後可在 Arduion 1.0 編譯通過


#include <Wire.h>
#include <Servo.h>
#include <Max3421e.h>
#include <Usb.h>
#include <AndroidAccessory.h>
#include <CapSense.h>
#define  LED3_RED       2
#define  LED3_GREEN     4
#define  LED3_BLUE      3
#define  LED2_RED       5
#define  LED2_GREEN     7
#define  LED2_BLUE      6
#define  LED1_RED       8
#define  LED1_GREEN     10
#define  LED1_BLUE      9
#define  SERVO1         11
#define  SERVO2         12
#define  SERVO3         13
#define  TOUCH_RECV     14
#define  TOUCH_SEND     15
#define  RELAY1         A0
#define  RELAY2         A1
#define  LIGHT_SENSOR   A2
#define  TEMP_SENSOR    A3
#define  BUTTON1        A6
#define  BUTTON2        A7
#define  BUTTON3        A8
/*
#define  JOY_SWITCH     A9      // pulls line down when pressed
#define  JOY_nINT       A10     // active low interrupt input
#define  JOY_nRESET     A11     // active low reset output
*/
AndroidAccessory acc("Google, Inc.",
             "DemoKit",
             "DemoKit Arduino Board",
             "1.0",
             "http://www.android.com",
             "0000000012345678");
Servo servos[3];
// 10M ohm resistor on demo shield
CapSense   touch_robot = CapSense(TOUCH_SEND, TOUCH_RECV);
void setup();
void loop();
void init_buttons()
{
    pinMode(BUTTON1, INPUT);
    pinMode(BUTTON2, INPUT);
    pinMode(BUTTON3, INPUT);
/*
    pinMode(JOY_SWITCH, INPUT);
*/
    // enable the internal pullups
    digitalWrite(BUTTON1, HIGH);
    digitalWrite(BUTTON2, HIGH);
    digitalWrite(BUTTON3, HIGH);
/*
    digitalWrite(JOY_SWITCH, HIGH);
*/
}

void init_relays()
{
    pinMode(RELAY1, OUTPUT);
    pinMode(RELAY2, OUTPUT);
}

void init_leds()
{
    digitalWrite(LED1_RED, 1);
    digitalWrite(LED1_GREEN, 1);
    digitalWrite(LED1_BLUE, 1);
    pinMode(LED1_RED, OUTPUT);
    pinMode(LED1_GREEN, OUTPUT);
    pinMode(LED1_BLUE, OUTPUT);
    digitalWrite(LED2_RED, 1);
    digitalWrite(LED2_GREEN, 1);
    digitalWrite(LED2_BLUE, 1);
    pinMode(LED2_RED, OUTPUT);
    pinMode(LED2_GREEN, OUTPUT);
    pinMode(LED2_BLUE, OUTPUT);
    digitalWrite(LED3_RED, 1);
    digitalWrite(LED3_GREEN, 1);
    digitalWrite(LED3_BLUE, 1);
    pinMode(LED3_RED, OUTPUT);
    pinMode(LED3_GREEN, OUTPUT);
    pinMode(LED3_BLUE, OUTPUT);
}
/*
void init_joystick(int threshold);
*/
byte b1, b2, b3, b4, c;
void setup()
{
    Serial.begin(115200);
    Serial.print("\r\nStart");
    init_leds();
    init_relays();
    init_buttons();
/*
    init_joystick( 5 );
*/
    // autocalibrate OFF
    touch_robot.set_CS_AutocaL_Millis(0xFFFFFFFF);
    servos[0].attach(SERVO1);
    servos[0].write(90);
    servos[1].attach(SERVO2);
    servos[1].write(90);
    servos[2].attach(SERVO3);
    servos[2].write(90);

    b1 = digitalRead(BUTTON1);
    b2 = digitalRead(BUTTON2);
    b3 = digitalRead(BUTTON3);
/*
    b4 = digitalRead(JOY_SWITCH);
*/
    c = 0;
    acc.powerOn();
}
void loop()
{
    byte err;
    byte idle;
    static byte count = 0;
    byte msg[3];
    long touchcount;
    if (acc.isConnected()) {
        int len = acc.read(msg, sizeof(msg), 1);
        int i;
        byte b;
        uint16_t val;
        int x, y;
        char c0;
        if (len > 0) {
            // assumes only one command per packet
            if (msg[0] == 0x2) {
                if (msg[1] == 0x0)
                    analogWrite(LED1_RED, 255 - msg[2]);
                else if (msg[1] == 0x1)
                    analogWrite(LED1_GREEN, 255 - msg[2]);
                else if (msg[1] == 0x2)
                    analogWrite(LED1_BLUE, 255 - msg[2]);
                else if (msg[1] == 0x3)
                    analogWrite(LED2_RED, 255 - msg[2]);
                else if (msg[1] == 0x4)
                    analogWrite(LED2_GREEN, 255 - msg[2]);
                else if (msg[1] == 0x5)
                    analogWrite(LED2_BLUE, 255 - msg[2]);
                else if (msg[1] == 0x6)
                    analogWrite(LED3_RED, 255 - msg[2]);
                else if (msg[1] == 0x7)
                    analogWrite(LED3_GREEN, 255 - msg[2]);
                else if (msg[1] == 0x8)
                    analogWrite(LED3_BLUE, 255 - msg[2]);
                else if (msg[1] == 0x10)
                    servos[0].write(map(msg[2], 0, 255, 0, 180));
                else if (msg[1] == 0x11)
                    servos[1].write(map(msg[2], 0, 255, 0, 180));
                else if (msg[1] == 0x12)
                    servos[2].write(map(msg[2], 0, 255, 0, 180));
            } else if (msg[0] == 0x3) {
                if (msg[1] == 0x0)
                    digitalWrite(RELAY1, msg[2] ? HIGH : LOW);
                else if (msg[1] == 0x1)
                    digitalWrite(RELAY2, msg[2] ? HIGH : LOW);
            }
        }
        msg[0] = 0x1;
        b = digitalRead(BUTTON1);
        if (b != b1) {
            msg[1] = 0;
            msg[2] = b ? 0 : 1;
            acc.write(msg, 3);
            b1 = b;
        }
        b = digitalRead(BUTTON2);
        if (b != b2) {
            msg[1] = 1;
            msg[2] = b ? 0 : 1;
            acc.write(msg, 3);
            b2 = b;
        }
        b = digitalRead(BUTTON3);
        if (b != b3) {
            msg[1] = 2;
            msg[2] = b ? 0 : 1;
            acc.write(msg, 3);
            b3 = b;
        }
/*
        b = digitalRead(JOY_SWITCH);
        if (b != b4) {
            msg[1] = 4;
            msg[2] = b ? 0 : 1;
            acc.write(msg, 3);
            b4 = b;
        }
*/
        switch (count++ % 0x10) {
        case 0:
            val = analogRead(TEMP_SENSOR);
            msg[0] = 0x4;
            msg[1] = val >> 8;
            msg[2] = val & 0xff;
            acc.write(msg, 3);
            break;
        case 0x4:
            val = analogRead(LIGHT_SENSOR);
            msg[0] = 0x5;
            msg[1] = val >> 8;
            msg[2] = val & 0xff;
            acc.write(msg, 3);
            break;
        case 0x8:
/*
            read_joystick(&x, &y);
            msg[0] = 0x6;
            msg[1] = constrain(x, -128, 127);
            msg[2] = constrain(y, -128, 127);
            acc.write(msg, 3);
*/
            break;
        case 0xc:
            touchcount = touch_robot.capSense(5);
            c0 = touchcount > 750;
            if (c0 != c) {
                msg[0] = 0x1;
                msg[1] = 3;
                msg[2] = c0;
                acc.write(msg, 3);
                c = c0;
            }
            break;
        }
    } else {
        // reset outputs to default values on disconnect
        analogWrite(LED1_RED, 255);
        analogWrite(LED1_GREEN, 255);
        analogWrite(LED1_BLUE, 255);
        analogWrite(LED2_RED, 255);
        analogWrite(LED2_GREEN, 255);
        analogWrite(LED2_BLUE, 255);
        analogWrite(LED3_RED, 255);
        analogWrite(LED3_GREEN, 255);
        analogWrite(LED3_BLUE, 255);
        servos[0].write(90);
        servos[0].write(90);
        servos[0].write(90);
        digitalWrite(RELAY1, LOW);
        digitalWrite(RELAY2, LOW);
    }
    delay(10);
}
// ==============================================================================
// Austria Microsystems i2c Joystick
/*
void init_joystick(int threshold)
{
    byte status = 0;
    pinMode(JOY_SWITCH, INPUT);
    digitalWrite(JOY_SWITCH, HIGH);
    pinMode(JOY_nINT, INPUT);
    digitalWrite(JOY_nINT, HIGH);
    pinMode(JOY_nRESET, OUTPUT);
    digitalWrite(JOY_nRESET, 1);
    delay(1);
    digitalWrite(JOY_nRESET, 0);
    delay(1);
    digitalWrite(JOY_nRESET, 1);
    Wire.begin();
    do {
        status = read_joy_reg(0x0f);
    } while ((status & 0xf0) != 0xf0);
    // invert magnet polarity setting, per datasheet
    write_joy_reg(0x2e, 0x86);
    calibrate_joystick(threshold);
}

int offset_X, offset_Y;
void calibrate_joystick(int dz)
{
    char iii;
    int x_cal = 0;
    int y_cal = 0;
    // Low Power Mode, 20ms auto wakeup
    // INTn output enabled
    // INTn active after each measurement
    // Normal (non-Reset) mode
    write_joy_reg(0x0f, 0x00);
    delay(1);
    // dummy read of Y_reg to reset interrupt
    read_joy_reg(0x11);
    for(iii = 0; iii != 16; iii++) {
        while(!joystick_interrupt()) {}
        x_cal += read_joy_reg(0x10);
        y_cal += read_joy_reg(0x11);
    }
    // divide by 16 to get average
    offset_X = -(x_cal>>4);
    offset_Y = -(y_cal>>4);
    write_joy_reg(0x12, dz - offset_X);  // Xp, LEFT threshold for INTn
    write_joy_reg(0x13, -dz - offset_X);  // Xn, RIGHT threshold for INTn
    write_joy_reg(0x14, dz - offset_Y);  // Yp, UP threshold for INTn
    write_joy_reg(0x15, -dz - offset_Y);  // Yn, DOWN threshold for INTn
    // dead zone threshold detect requested?
    if (dz)
        write_joy_reg(0x0f, 0x04);
}

void read_joystick(int *x, int *y)
{
    *x = read_joy_reg(0x10) + offset_X;
    *y = read_joy_reg(0x11) + offset_Y;  // reading Y clears the interrupt
}
char joystick_interrupt()
{
    return digitalRead(JOY_nINT) == 0;
}

#define  JOY_I2C_ADDR    0x40
char read_joy_reg(char reg_addr)
{
    char c;
    Wire.beginTransmission(JOY_I2C_ADDR);
    Wire.write(reg_addr);
    Wire.endTransmission();
    Wire.requestFrom(JOY_I2C_ADDR, 1);
    while(Wire.available())
        c = Wire.read();
    return c;
}
void write_joy_reg(char reg_addr, char val)
{
    Wire.beginTransmission(JOY_I2C_ADDR);
    Wire.write(reg_addr);
    Wire.write(val);
    Wire.endTransmission();
}
*/