Arduino Tank

「Arduino Tank」の編集履歴(バックアップ)一覧はこちら

Arduino Tank」(2013/08/12 (月) 18:58:24) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

*はじめに ArduinoとXBeeとモーターシールドを使ってラジコンを作ろうと思う。ラジコンのソースコードは今後Arduinoを用いた動くおもちゃを作る際の動作確認に利用する事が出来る。また、XBeeによる無線通信とモーターの制御を組み合わせた最も基本的な工作のひとつであるため、ソースコードやノウハウを他の工作に生かす事ができると考える。 *Arduino Tankの機能 -無線により操作が可能 -一本のスティックで操作が可能 -スティックを倒した方向に進む(角度は無段階) -スティックを倒した角度に比例してスピードが変化(1chにつき255段階) -超信地展開が可能(左右のキャタピラーを逆方向に回す事によりその場で回転) *車体側 **車体側の機能 -無線により値を受け取る事で動作 -左右のキャタピラーがそれぞれ比例制御が可能(8bit-255段階) **ハードウェアの構成 -キャタピラー(タミヤ工作キット) -ギアボックス([[タミヤダブルギアボックス>http://www.tamiya.com/japan/products/70168double_gearbox/index.htm]]) -シャーシ(タミヤユニバーサルプラスチック基盤) -マイコン(Arduino Uno) -モータードライバー([[Ardumoto>http://www.switch-science.com/catalog/427/]]: Arduinoのシールドの一種) -通信モジュール(XBee Series2) #ref(ArduinoTank.jpg) **ハードウェアの説明 タミヤ工作キットのキャタピラー工作キットとダブルギアボックスを組み合わせて駆動系を作った。また、シャーシはタミヤユニバーサルプラスチック基盤で作った。マイコンはArduino Unoを用いており、モータードライバーにはArdumotoを利用している。また、ArduinoとXbeeはArduino → XBeeは分圧抵抗により電圧を落としている。XBee→Arduinoはそのまま入力を行っている。本来はロジックレベル変換レベル変換を行うべきであるが、現状で動作している。(XBeeに5Vを入力してしまうと壊れるので注意) **ソフトウェアの説明 XBeeから3Byteのデータを受け取り、それを2系統の8bit出力と1bitの回転方向に変換し、Ardumotoに出力する事でモーターの制御を行っている。 #ref(スティックコントローラー.jpg) *スティックコントローラー側 **スティックコントローラーの機能 -スティックを倒した方向に応じて、2つのキャタピラー出力に変換し無線送信する -スティックを押す事で超信地旋回するモードとしないモードに切り替わる(超信地旋回するモードの場合には緑LEDが点灯) **使用した部品 -[[Arduino Fio>http://arduino.cc/en/Main/ArduinoBoardFio]] -XBee -LiPoバッテリー -[[アナログジョイスティック>http://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-07RM]] -LED × 2(赤, 緑) -ブレッドボード **ハードウェアの説明 Arduinoのアナログ入力0, 1にジョイスティックのX軸とY軸を接続し、AD変換を行っている。また、D2ピンにボタンを接続し、スイッチが押された場合はGNDレベルに落ち、割り込みが発生するようになっている。D2ピンとスイッチに関しては 10KΩのプルアップ抵抗が取り付けられている。またD3とD5ピンにLEDが取り付けられており、PWMにより明るさの調整が可能になっている。 **ソフトウェアの説明 XY座標により入力されるデータを2つのモーター出力に変換している。変換のために極座標に飛ばし、角度θにより左右のモーター出力の係数を出力する関数を記述し、それをベクトルの大きさRと掛け合わせる事でモーター出力を得ている。またスイッチによりモードの切り替えを行い、モード0(超信地旋回あり)とモード1(超信地旋回しない)で別の関数を呼び出している。データは現在100ms毎に送信を行っている。チャタリング対策に関してもソフトウェア的に行っている。一旦ボタンが押された場合は500ms割り込みを無視するように設定されている。 *実験 Arduino Tank Ver0.1と合わせて動作実験を行い、意図した通りに動作している事を確認した。ただし、通信エラーが発生する事がある。通信エラーはPCの近く等電磁波が発生していると考えられる場所、および走っている途中で発生している。現在はデータの送信周期は100msになっているが、遅くしすぎるとレスポンスが悪く、速くしすぎると通信エラーが頻発する。 *今後の課題 -通信モジュールのテスト(どういった場合にエラーが発生するか) -一定時間データが来ない場合に停止するような実装(車体側で一定時間データが来ない場合タイマー割り込みにより出力を0にする実装) #ref(Arduinoラジコン完成版.jpeg) 最終的にこうなった(苦笑) *ソースコード **車体側 #highlight(linenumber,c){{ /*キャタピラーラジコンの完成版*/ #define ROTATION1_PIN 12 #define SPEED1_PIN 3 #define ROTATION2_PIN 13 #define SPEED2_PIN 11 #define RXPIN 2 #define TXPIN 4 int left_power, right_power; void setup(){ pinMode(ROTATION1_PIN, OUTPUT); pinMode(ROTATION2_PIN, OUTPUT); pinMode(SPEED1_PIN, OUTPUT); pinMode(SPEED2_PIN, OUTPUT); digitalWrite(ROTATION1_PIN, HIGH); digitalWrite(ROTATION2_PIN, HIGH); analogWrite(SPEED1_PIN, 0); analogWrite(SPEED2_PIN, 0); Serial.begin(9600); left_power = 0; right_power = 0; } void loop(){ boolean rotation1, rotation2; int speed1, speed2, i; char c[4]; if(Serial.available()){ c[0] = Serial.read(); if((c[0] & 0b10000000) != 0){ delay(5); c[1] =Serial.read(); c[2] = Serial.read(); c[3] = Serial.read(); left_power = (c[0] & 0b01111111) << 2 | (c[1] & 0b01100000) >> 5; right_power = (c[1] & 0b00011111) << 4 | (c[2] & 0b01111000) >> 3; left_power -= 255; right_power -= 255; //以下で回転数の計算 //左モーターに関して if(left_power >= 0) //正回転の場合 rotation1 = HIGH; else rotation1 = LOW; //右モーターに関して if(right_power >= 0) //正回転の場合 rotation2 = HIGH; else rotation2 = LOW; speed1 = abs(left_power); speed2 = abs(right_power); digitalWrite(ROTATION1_PIN, rotation1); digitalWrite(ROTATION2_PIN, rotation2); analogWrite(SPEED1_PIN, speed1); analogWrite(SPEED2_PIN, speed2); } } } }} **コントローラー側 #highlight(linenumber,cpp){{ //ソースコード: polar_stick_ver2 #include <MsTimer2.h> #include <math.h> #define MAX_X 1012 #define MAX_Y 998 #define MIN_X 0 #define MIN_Y 0 #define NEUTRAL_X 414 #define NEUTRAL_Y 422 #define asobi 20 #define STICK_LED 3 int timer_count; int stick_mode; void count_down(){ if(timer_count > 0) timer_count--; } void button_interrupt(){ if(timer_count == 0){ if(stick_mode == 0){ stick_mode = 1; analogWrite(STICK_LED, 255); } else{ stick_mode = 0; analogWrite(STICK_LED, 0); } timer_count = 30; } } void setup(){ Serial.begin(9600); timer_count = 0; attachInterrupt(0, button_interrupt, FALLING); MsTimer2::set(10, count_down); MsTimer2::start(); attachInterrupt(0, button_interrupt, FALLING); stick_mode = 0; digitalWrite(STICK_LED, LOW); } /* rは中央からの距離, sは角度を表す. rの最大は1である. sはスティックを前に倒すと0, 左に倒すと-90, 右に倒すと90, 後ろに倒すと180 or -180を返す */ void stick_read(double *r, double *s){ double stick_x, stick_y; //スティック位置の補正 stick_x = (double)analogRead(0); stick_y = (double)analogRead(1); if(stick_x < NEUTRAL_X){ stick_x = (stick_x - NEUTRAL_X) / (NEUTRAL_X - MIN_X); } else{ stick_x = (stick_x - NEUTRAL_X) / (MAX_X - NEUTRAL_X); } if(stick_y < NEUTRAL_Y){ stick_y = (stick_y -NEUTRAL_Y) / (NEUTRAL_Y - MIN_Y); } else{ stick_y = (stick_y - NEUTRAL_Y)/ (MAX_Y - NEUTRAL_Y); } /* デバッグ用 Serial.print(stick_x); Serial.print(","); Serial.println(stick_y); */ *r = sqrt(pow(stick_x,2) + pow(stick_y, 2)); if(*r > 1)*r = 1; else if(*r < -1)*r = -1; *s = atan2(stick_x, stick_y) /3.14 * 180; } /* 極座標による入力を二つのモーターの出力に変換する関数. 超信地展開するバージョン. moterの出力は-255 ~ 255である. -は逆回転を表す */ void convert_pwm(double r, double s, int *lp, int *rp){ double _lp, _rp; if(-180 <= s && s < -90){ _lp = -1; _rp = (s + 180) / 45 - 1; } else if(-90 <= s && s < 0){ _lp = (s + 90) / 45 - 1; _rp = 1; } else if(0 <= s && s < 90){ _lp = 1; _rp = 1 - s / 45; } else{//90 <= r <= 180の時 _lp = 1 - (s - 90) / 45; _rp = -1; } *lp = _lp * r * 255; *rp = _rp * r * 255; if(abs(*lp) < 20)*lp = 0; if(abs(*rp) < 20)*rp = 0; /*デバグ用 Serial.print(_lp); Serial.print(","); Serial.println(_rp); */ } /* 極座標による入力を二つのモーターの出力に変換する関数. 超信地展開しないバージョン. moterの出力は-255 ~ 255である. -は逆回転を表す */ void convert_pwm2(double r, double s, int *lp, int *rp){ double _lp, _rp; if(-180 <= s && s < -90){ _lp = (s + 180) / 90 - 1; _rp = (s + 180) / 45 - 1; } else if(-90 <= s && s < 0){ _lp = (s + 90) / 90; _rp = 1; } else if(0 <= s && s < 90){ _lp = 1; _rp = 1 - s / 90; } else{//90 <= r <= 180の時 _lp = 1 - (s - 90) / 45; _rp = -1 * (s - 90) / 90; } *lp = _lp * r * 255; *rp = _rp * r * 255; if(abs(*lp) < 20)*lp = 0; if(abs(*rp) < 20)*rp = 0; /*デバグ用 Serial.print(_lp); Serial.print(","); Serial.println(_rp); */ } void make_command(int left_power, int right_power){ char c0, c1, c2, c3; left_power += 255; right_power += 255; c0 = (left_power & 0b111111100) >> 2; c1 = (left_power & 0b000000011) << 5; c1 = c1 | ((right_power & 0b111110000) >> 4); c2 = (right_power & 0b000001111) << 3; c3 = 0; c0 = c0 | 0b10000000;//先頭バイトの先頭ビットを1とする c0 = c0 & 0b111111111; Serial.print(c0); Serial.print(c1); Serial.print(c2); Serial.print(c3); } void loop(){ double r, s; int left_power, right_power;//-255 ~ 255でモーター出力を表現 stick_read(&r, &s);//極座標で値を返す関数 if(stick_mode == 0) convert_pwm2(r,s,&left_power, &right_power); else if(stick_mode == 1) convert_pwm(r,s,&left_power, &right_power); make_command(left_power, right_power); /*でバグ用 Serial.print(left_power); Serial.print(","); Serial.println(right_power); */ delay(100); } }}
*はじめに ArduinoとXBeeとモーターシールドを使ってラジコンを作ろうと思う。ラジコンのソースコードは今後Arduinoを用いた動くおもちゃを作る際の動作確認に利用する事が出来る。また、XBeeによる無線通信とモーターの制御を組み合わせた最も基本的な工作のひとつであるため、ソースコードやノウハウを他の工作に生かす事ができると考える。 *Arduino Tankの機能 -無線により操作が可能 -一本のスティックで操作が可能 -スティックを倒した方向に進む(角度は無段階) -スティックを倒した角度に比例してスピードが変化(1chにつき255段階) -超信地展開が可能(左右のキャタピラーを逆方向に回す事によりその場で回転) *車体側 **車体側の機能 -無線により値を受け取る事で動作 -左右のキャタピラーがそれぞれ比例制御が可能(8bit-255段階) **ハードウェアの構成 -キャタピラー(タミヤ工作キット) -ギアボックス([[タミヤダブルギアボックス>http://www.tamiya.com/japan/products/70168double_gearbox/index.htm]]) -シャーシ(タミヤユニバーサルプラスチック基盤) -マイコン(Arduino Uno) -モータードライバー([[Ardumoto>http://www.switch-science.com/catalog/427/]]: Arduinoのシールドの一種) -通信モジュール(XBee Series2) #ref(ArduinoTank.jpg) **ハードウェアの説明 タミヤ工作キットのキャタピラー工作キットとダブルギアボックスを組み合わせて駆動系を作った。また、シャーシはタミヤユニバーサルプラスチック基盤で作った。マイコンはArduino Unoを用いており、モータードライバーにはArdumotoを利用している。また、ArduinoとXbeeはArduino → XBeeは分圧抵抗により電圧を落としている。XBee→Arduinoはそのまま入力を行っている。本来はロジックレベル変換レベル変換を行うべきであるが、現状で動作している。(XBeeに5Vを入力してしまうと壊れるので注意) **ソフトウェアの説明 XBeeから3Byteのデータを受け取り、それを2系統の8bit出力と1bitの回転方向に変換し、Ardumotoに出力する事でモーターの制御を行っている。 #ref(スティックコントローラー.jpg) *スティックコントローラー側 **スティックコントローラーの機能 -スティックを倒した方向に応じて、2つのキャタピラー出力に変換し無線送信する -スティックを押す事で超信地旋回するモードとしないモードに切り替わる(超信地旋回するモードの場合には緑LEDが点灯) **使用した部品 -[[Arduino Fio>http://arduino.cc/en/Main/ArduinoBoardFio]] -XBee -LiPoバッテリー -[[アナログジョイスティック>http://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-07RM]] -LED × 2(赤, 緑) -ブレッドボード **ハードウェアの説明 Arduinoのアナログ入力0, 1にジョイスティックのX軸とY軸を接続し、AD変換を行っている。また、D2ピンにボタンを接続し、スイッチが押された場合はGNDレベルに落ち、割り込みが発生するようになっている。D2ピンとスイッチに関しては 10KΩのプルアップ抵抗が取り付けられている。またD3とD5ピンにLEDが取り付けられており、PWMにより明るさの調整が可能になっている。 **ソフトウェアの説明 XY座標により入力されるデータを2つのモーター出力に変換している。変換のために極座標に飛ばし、角度θにより左右のモーター出力の係数を出力する関数を記述し、それをベクトルの大きさRと掛け合わせる事でモーター出力を得ている。またスイッチによりモードの切り替えを行い、モード0(超信地旋回あり)とモード1(超信地旋回しない)で別の関数を呼び出している。データは現在100ms毎に送信を行っている。チャタリング対策に関してもソフトウェア的に行っている。一旦ボタンが押された場合は500ms割り込みを無視するように設定されている。 *実験 Arduino Tank Ver0.1と合わせて動作実験を行い、意図した通りに動作している事を確認した。ただし、通信エラーが発生する事がある。通信エラーはPCの近く等電磁波が発生していると考えられる場所、および走っている途中で発生している。現在はデータの送信周期は100msになっているが、遅くしすぎるとレスポンスが悪く、速くしすぎると通信エラーが頻発する。 *今後の課題 -通信モジュールのテスト(どういった場合にエラーが発生するか) -一定時間データが来ない場合に停止するような実装(車体側で一定時間データが来ない場合タイマー割り込みにより出力を0にする実装) #ref(Arduinoラジコン完成版.jpeg) 最終的にこうなった(苦笑)

表示オプション

横に並べて表示:
変化行の前後のみ表示: