2014年10月24日金曜日

Arduino て遊ぼう(4) SPIでXBeeとつなぐ

すシリアルでつなげたものを、SPIに移植します。

結線は
xbee             ----     Pro Micro
(slave)                       (master)
18 SPI CLK  <--- 15 SPI CLK
17 SPI SLAVE 
    #SELECT <--- 5 digital out
19 SPI SLAVE 
    #ATTEN    ---> 4 digital in
     * use interrupt 
11 SPI MOSI <--- 16 SPI MOSI
4 SPI MISO   ---> 14 SPI MISO

xbeeはDout(2)をlowに落として、強制的にSPIモードにしておきます。

Arduino は
まずは、受信処理のみ。
ATTENがlowになったらCSを落として一通り受信します。
受信完了でパケット処理します。
(SPIは高速なので先に受信してしまうことにします)

そしてエコーバック。本当は、送信中もATTENを見てやらないといけませんが、、それはまた次回。

エコーバックはうまくいったので、
定型のHTMLを返すようして
簡易webサーバーの出来上がり(^^)

Arduino で遊ぼう(3) XBeeとシリアル接続してAPIモード

Arduino とXBee wifiをシリアルで接続して、APIモードで動かしました。

XBee wifiにはtelnetで接続すると、
受信パケットをエコーバックします。

シリアルのボーレートは57600bpsまでしかうごきませんでした。

とりあえずのコード
(汚い…、。)

/*
 XBee WiFi Connected Serial.
 XBee works in API Mode.

 Receie Serial and Parse API packet,
 then echo back by API packet.
 */

/**
 * 送信パケットの生成
 */
int makeXBeeApiSendIp(byte* pPacket, unsigned short u16Size,
byte* pbIpAddrDst, byte* pbPortDst, byte* pbPayload, word length)
{
if(u16Size < length + 16)
{
Serial.println("buffer too short");
return -1;
}

// パケット生成
pPacket[0] = 0x7E;
// length
        u16Size = length + 12;
pPacket[1] = u16Size >> 8;
pPacket[2] = u16Size & 0x00FF;
// API Cmd
pPacket[3] = 0x20;
// FrameID
pPacket[4] = 0x00;
// IpAddrDst
pPacket[5] = pbIpAddrDst[0];
pPacket[6] = pbIpAddrDst[1];
pPacket[7] = pbIpAddrDst[2];
pPacket[8] = pbIpAddrDst[3];
// PortDst
pPacket[9] = pbPortDst[0];
pPacket[10] = pbPortDst[1];
// PortSrc
pPacket[11] = 0x26;
pPacket[12] = 0x16;
// Packet Type
pPacket[13] = 0x01; //< TCP, Connection Keep
//
pPacket[14] = 0x00;
// Payload
for(int i=0; i<length; i++)
{
pPacket[15 + i] = pbPayload[i];
}
// チェックサム計算
byte sum = 0;
for(int i=0; i<length + 12; i++)
{
sum += pPacket[3 + i];
}
pPacket[length + 15] = 0xFF - sum;

return length + 16;
}

/**
 * 受信パケットのダンプ
 */
void printPayload(byte* pPayload, word length)
{
  if(0 < length)
  {
    Serial.println("dump");
for(word i = 0; i<length; i++)
{
Serial.print(pPayload[i], HEX);
Serial.print(",");
}
        Serial.println();
  }
}

/**
 * 受信パケットのパース
 */
byte g_pbIpAddrSrc[4];
byte g_pbPortSrc[2];
byte* g_pbPayload;
int parseXBeeApiReceiveIp(byte* pPacket, unsigned short u16Size,
byte* pbIpAddrSrc, byte* pbPortSrc, byte** ppbPayload) {
// APIコード確認
if (0xB0 != pPacket[3]) {
// Serial.print("wrong api code:");
// Serial.println(pPacket[3]);
return -1;
}
// 送信元IPアドレス取得
pbIpAddrSrc[0] = pPacket[4];
pbIpAddrSrc[1] = pPacket[5];
pbIpAddrSrc[2] = pPacket[6];
pbIpAddrSrc[3] = pPacket[7];
//        Serial.write(pbIpAddrSrc, 4);
//        Serial.println();
// 送信元ポート取得
pbPortSrc[0] = pPacket[10];
pbPortSrc[1] = pPacket[11];
//        Serial.write(pbPortSrc, 2);
//        Serial.println();
// ペイロード取得
*ppbPayload = &pPacket[14];

//        Serial.println(pPacket[1]);
//        Serial.println(pPacket[2]);

return ((int) pPacket[1] << 8) + (int) pPacket[2] - 11;
}

/**
 * 受信処理
 */
#define RECEIVE_IP 1
unsigned char u8ReceiveMode = 0;
#define RECEIVE_MODE_IDLE 0
#define RECEIVE_MODE_LEN1 1
#define RECEIVE_MODE_LEN2 2
#define RECEIVE_MODE_DATA 3
#define RECEIVE_MODE_CS 4
#define APIPACKET_SIZE_MAX 1024
byte g_pu8ApiPacket[APIPACKET_SIZE_MAX];
unsigned short g_u16ApiPacketSize;
unsigned short g_u16ApiPacketLength;
int parseChar(byte data) {
// Serial.println(data, HEX);

switch (u8ReceiveMode) {
case RECEIVE_MODE_IDLE:
// wait for "0x7E"
if (0x7E == data) {
g_u16ApiPacketSize = 0;
g_u16ApiPacketLength = 0;
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_LEN1;
// Serial.println("api start");
}
break;
case RECEIVE_MODE_LEN1:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_LEN2;
break;
case RECEIVE_MODE_LEN2:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_DATA;
g_u16ApiPacketLength = ((unsigned short) g_pu8ApiPacket[1] << 8)
+ (unsigned short) g_pu8ApiPacket[2];
// Serial.print("get len :");
// Serial.println(g_u16ApiPacketLength);
if (g_u16ApiPacketLength > (APIPACKET_SIZE_MAX - 4)) {
Serial.println("invalid data len");
u8ReceiveMode = RECEIVE_MODE_IDLE;
}
break;
case RECEIVE_MODE_DATA:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
if ((g_u16ApiPacketSize - 3) >= g_u16ApiPacketLength) {
u8ReceiveMode = RECEIVE_MODE_CS;
// Serial.println("get data");
}
break;
case RECEIVE_MODE_CS:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_IDLE;
// Serial.println("get cs");
return RECEIVE_IP;
break;
default:
break;
}
return 0;
}

byte RXLED = 13;
byte toggle = 0;

void setup() {
pinMode(RXLED, OUTPUT);  // Set RX LED as an output
// TX LED is set as an output behind the scenes

Serial.begin(115200); //This pipes to the serial monitor
Serial1.begin(4800); //This is the UART, pipes to sensors attached to board
}

void loop() {
if (0 < Serial.available()) {
                byte data = Serial.read();
Serial1.write(g_pu8ApiPacket, makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX, g_pbIpAddrSrc, g_pbPortSrc, &data, 1));
if (0 == toggle) {
digitalWrite(RXLED, LOW);   // set the LED on
TXLED0; //TX LED is not tied to a normally controlled pin
toggle = 1;
} else {
digitalWrite(RXLED, HIGH);    // set the LED off
TXLED1;
toggle = 0;
}
}
if (0 < Serial1.available()) {
// Serial.write(parseChar(Serial1.read()));
if (RECEIVE_IP == parseChar(Serial1.read())) {
int len = parseXBeeApiReceiveIp(g_pu8ApiPacket, g_u16ApiPacketSize,
g_pbIpAddrSrc, g_pbPortSrc, &g_pbPayload);
Serial.print("receive ip packet:");
Serial.println(len);

printPayload(g_pbPayload, len);

// echo
                        byte data = *g_pbPayload;
Serial1.write(g_pu8ApiPacket, makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX, g_pbIpAddrSrc, g_pbPortSrc, &data, 1));
}
}
}

2014年10月21日火曜日

Arduino で遊ぼう(2) xbee とspiで接続[情報編]

xbee ---- Pro Micro
(slave)     (master)
18 SPI CLK  <--- 15 SPI CLK
17 SPI SLAVE 
    #SELECT <--- 5 digital out
19 SPI SLAVE 
    #ATTEN    ---> 4 digital in
     * use interrupt 
11 SPI MOSI <--- 16 SPI MOSI
4 SPI MISO   ---> 14 SPI MISO

xbee wifiのspiは
spi mode 0, MSB first

pin2(dout)をlowで起動すると強制的にspiモードになる。

arduinoは
SPI.setBitOrder(MSBFIRST)
SPI.setDataMode(SPI_MODE0)
SPI.setClockDivider(SPI_CLOCK_DIV4)
   -> 8MHzの4分周で2MHz

XBeeのAPIモードでの送信コマンドは

最後のチエックサムが。。。

digiにドキュメントがありました。
<http://www.digi.com/support/kbase/kbaseresultdetl?id=2206>
普通にlength bytes の後ろからの和をFFから引けばいいですね。

2014.10.23 追記
まずは、シリアルでxbeeをapiモードで動かした。
xbee 192.168.111.200:9750
pc 192.168.111.210で接続
xbeeからtcp送信時のシリアルデータ例
(pcのポートはcb 9b)
7E 00 0d 20 01 c0 a8 6f d2 cb 9b 26 16 01 00 31 61
"1"を送信
 



Arudinoで遊ぼう(1) 構想

今更だけど、arduinoを触ってみようと思う。

xbeeと前に買ったシリアル出力JPEGカメラをつなげてカメラ付きたまロボwebサーバー版を作りたい。
(以前はxbeeのapiモードをudpで使ったりシリアル透過でカメラ制御していたので専用のiosアプリだった。ディベロッパーライセンスは切れたので、もうiosアプリ作れない。。。し)

arduino はpro micro 3.3Vでxbeeにもカメラにも直結。電源は前のたまロボ同様にDCDCで昇圧。モータードライバはスイッチサイエンスの
POLOLU-2135 デュアルモータードライバDRV8835
で、前のより小さい。

シリアルは、arduino のハードシリアルとソフトシリアルでいいかと思ってもいたが、ソフトシリアルは9600bpsがいいとこらしい。

これは厳しいです。

で、xbeeはspiで行けないかと考えています。
こんな文書がありました。
<a href=http://www.digi.com/support/kbase/kbaseresultdetl?id=3362>An Introduction to SPI on XBee</a>
いけるかな?

xbeeは3.5MHzまで対応しているみたいなのでpro microは1/4分周で、
うまく行けば、2MHz⁈

2014年7月3日木曜日

BeagleBoneBlackでモーター制御3

ちゃんとまっすぐ進むように左右の速度をトリムしたいので、左右それぞれPWMで制御するように修正する。

eHRPWM1Bも使う(AとBは同じモジュールなので周期が同じになるが、ちゃんとdutyが違えばいいので)

duty, polarityは個別設定できるが、
periodは共通。

runはなんだか取り扱い注意。AとBを合わせてオンオフしないと変な状態になる。



以下は古い。

eHRPWM2Aも使う。




BeagleBone Blackでロボット

似たようなタイトルの本もあり、参考にさせてもらったし、この本に著者関連のショップからBeagleBone Blackを購入できた。

ただ、構成はいろいろ違う。
Wifiで繋がりブラウザで操作できる。
Mjpegのストリートで画像が見れる。
モータードライバーも違う。

モバイルバッテリーで駆動しているが、モーター1A、本体+USB機器で2Aなので、
http://www.amazon.co.jp/gp/aw/d/B00ASSGJ3Q/ref=redir_mdp_mobile?ref_=pe_492632_48821362_TE_M3T1_dp_1
を使った。


今後は、距離センサーを使った自動運転、バンパースイッチによる緊急停止を追加予定。

2014年6月25日水曜日

超信地旋回

BeaglaBone Blackをタミヤのキャタピラのキットとギヤボックスに乗せて走らせた。

前後は問題無いが、
旋回するとキャタピラが外れた。

なんかいい回避策はないかとググったら、
 超信地旋回:左右を逆転
 信地旋回:片方を停止
と呼ぶらしく、
いずれも負荷が高く実機ではやらないことも多いらしい。

接地抵抗が小さければ信地旋回できそうだけど、ウチのはソコソコ重いし、キャタピラはゴムなのでむりなのかな。

左右は独立して速度調整できるので信地じゃない旋回にしよう。