ProjectSR が 2023年01月29日12時40分19秒 に編集
初版
タイトルの変更
消防ロボット SUIJIN MK-1
タグの変更
Arduino
XBee
ラジコン
消防
電子工作
3Dプリンター
Youtube
ロボット
メイン画像の変更
記事種類の変更
製作品
本文の変更
🔳概要・基本構成 --- ①送信側のArduinoがオペレータのジョイスティックの操作量,ボタンの信号,放水量調整可変抵抗を読み取ります. ②操作量に応じたモータの回転速度を計算し,受信側のArduinoへ数値を送ります. ③メカハードは,車体,タンク,電子バルブ,3Dで制作したポンプと砲座で構成されています. 🔳解説 ユーチューブ ニコニコ動画 にて 動作しているPVを公開しています. (本編は2:15~) @[youtube](https://www.youtube.com/watch?v=1rKI0RFGbKo) ### ニコニコ動画 [https://www.nicovideo.jp/watch/sm41604261) 構成解説編は現在準備中です. 後日作成次第,公開します. ポイント --- ●モータを制御するため,送信側のArduinoが操作量を読み取る事 ●複数のモータの回転速度に関係する複数の数値を送受信する事 ●水漏れが無いようにパッキン,シールを用いること です. 今回は,Arduino+XBeeのを使ったジョイスティックワイヤレスコントローラシステムを応用して 水を放出し,火を消す 消防ロボットを製作しました. 1⃣本体構成 --- ### ①内部構成 簡単な車体内部構成をポンチ絵程度の断面図で示します.(拡大できます)  車体は,コントローラから無線で信号を受信し,砲座,ポンプを回転 水路の開閉を行う電磁弁には ON/OFF指令を出力します.  電磁弁は開いた状態で初めてポンプが回るように,プログラムを組んでいます. 砲座と車体の履帯(クローラ)は電磁弁の状態によらず,動作可能です (後程プログラムチャートを示します)  各種用機器の画像は以下になります  ### ②タンク タンク外観です. ポリタンクやペットボトル等検討しましたが,車体に合わせられる形状にしたかったので, 自作することにしました.  タンクの材質は塩ビ板で,ホームセンターで売られている 塩ビ三角棒と接着剤で補強し,水漏れが発生しないように, シリコンシーラントを使っています.  タンクとL字の塩ビパイプを接続する配管は 金属パテで固定し,ゴムで水漏れを防ぐようにしています.  ### ③メインポンプ メインポンプの外観です. タンクと接続する配管は,接着と水漏れ防止をするため,金属パテを使っています.  ポンプは,モータRS775とビームカップリングで接続されています.  続いてポンプ内側です. ポンプは渦巻ポンプというもので,羽が回転することで, 水を回転方向へ押し出します. ハウジングや,羽は3Dプリンターで製作しています. (調べたところ,消防車も同じ形式のものを使っているそうです.)  ↑の羽は,ネジでアルミ製の軸と締結されています. この軸は,ビームカップリング・モータの順番に接続されているのですが, ビームカップリングと羽の間に,ポンプカバーとベアリングホルダーがあります. カバーとベアリングホルダーには,軸を通す穴が開いています.  製作当初,隙間から水が漏れてしまう事態が発生するので, PDUパッキンという,回転軸から水が漏れないようにする部品があり,利用しています. ただ,材質がゴムのため,軸とパッキンで摩擦が発生し,モータが回らない事態が発生しました. (プロジェクト中止を覚悟しました) ただ,パッキンと軸にシリコングリスを塗り付けて,摩擦を弱めることに成功!  また,ベアリングを,ベアリングホルダーにはめる際, 外周をアロンαで接着しています. 目的は,ベアリングが外れる事の防止と,水漏れ防止です.  ### ④砲座 ノズルは取り外した,砲座外観です.  砲座は,X,Z軸の回転が可能で,回りすぎを防止するため. 各回転軸に対して,可変抵抗を設けています.  モータ,可変抵抗,砲座回転軸にギアが取り付けられており, モータが回転したら,可変抵抗と砲座軸のギアが回り, 可変抵抗の値が所定の位置に達したらモータが停止する プログラムを組んでいます.  Z軸回転の砲座も,ギアは可変抵抗,回転軸,モータに取り付けられ, モータが回ることで,回転軸と可変抵抗が回り, 可変抵抗の値が所定の位置に達した際に,モータは停止します. 上段にギアボックス,下段に可変抵抗と回転軸の軸受けがあります.    2⃣電子回路 --- 続いて電子回路の説明をします. まずは,受信側回路 ロボットの回路 NUE MK-2とTele Fenix MK-1を併用し,電磁弁と制御用のリレーを追加しています.  続いて送信側 コントローラの回路です ソレノイド制御用リレーへ指令を送るトグルスイッチと ポンプモータの回転数を調整する,可変抵抗を追加しています.  3⃣制御フロー プログラム --- ### ①配列の設定 配列を用意して,モータの回転方向回転速度,電磁弁のON/OFFの送受信を行います. ### 制御フローチャート 送信側,受信側の制御フローチャートを記載します. 送信は長いので,2つ図を作成しています. #### 送信側①  #### 送信側②  #### 受信側  ### プログラム #### 送信側 ```html int SendBuf[8]; int i; int HDatain,VDatain,HDataout,VDataout,SUITONin,SUITONout; int button2 =2; int button3 =3; int button4 =4; int button5 =5; int button6 =6; int DirR; int DirL; int SUITON_under_R_read; int SUITON_under_L_read; int SUITON_top_U_read; int SUITON_top_D_read; int SUITONDirup_out; int SUITONDirunder_out; int Duty1,Duty2,Duty3; int SubSolenoid_read; int SubSolenoid_out; int countn=0; int solenoidout=0; int SUINTONin ; void setup() { // put your setup code here, to run once: Serial.begin(9600); pinMode(button2,INPUT); pinMode(button3,INPUT); pinMode(button4,INPUT); pinMode(button5,INPUT); pinMode(button6,INPUT); } void loop() { // put your main code here, to run repeatedly: VDatain = analogRead(A0); VDataout = map(VDatain,0,1023,0,220); HDatain = analogRead(A1); HDataout = map(HDatain,0,1023,0,220); SUITONin = analogRead(A5); SUITONout = map(SUITONin,0,1023,0,255); SUITON_under_R_read = digitalRead(button2); SUITON_under_L_read = digitalRead(button3); SUITON_top_U_read = digitalRead(button4); SUITON_top_D_read = digitalRead(button5); SubSolenoid_read = digitalRead(button6); //前進後退 if(VDataout>120){ if(HDataout>140){ DirL = 0; DirR = 0; Duty1 =VDataout; Duty2 =HDataout; } else if(140>=HDataout && 100<HDataout){ DirL = 0; DirR = 0; Duty1 =(VDataout-110)*2; Duty2 =(VDataout-110)*2; } else{ DirL = 0; DirR = 0; Duty1 =(200-HDataout); Duty2 =VDataout; } } else if(VDataout<=120 && VDataout>=95){ if(HDataout>110){ DirL = 1; DirR = 0; Duty1 =(HDataout-115)*2; Duty2 =(HDataout-115)*2; } else if(HDataout<110){ DirL = 0; DirR = 1; Duty1 =(108-HDataout)*2; Duty2 =(108-HDataout)*2; } else{ DirL = 2; DirR = 2; Duty1 =0; Duty2 =0; } } else{ if(HDataout>150){ DirL = 1; DirR = 1; Duty1 =(HDataout-120)*2; Duty2 =(120-VDataout)*2; } else if(150>=HDataout && HDataout>100){ DirL = 1; DirR = 1; Duty1 =(120-VDataout)*2;//(110-VDataout)*2 Duty2 =(120-VDataout)*2;//(110-VDataout)*2 } else{ DirL = 2; DirR = 2; Duty1 =(120-HDataout)*2; Duty2 =(120-VDataout)*2; } } if(SUITON_under_R_read==LOW || SUITON_under_L_read==LOW){ //砲台下側左右 if(SUITON_under_R_read==LOW){ SUITONDirunder_out=1; } else{ SUITONDirunder_out=0; } } else{ SUITONDirunder_out=2; } if(SUITON_top_U_read==LOW || SUITON_top_D_read==LOW){ //砲台上側上下 if(SUITONDirup_out==LOW){ SUITONDirup_out=1; } else{ SUITONDirup_out=0; } } else{ SUITONDirup_out=2; } //for無限ループからのbreakで脱出 if (SubSolenoid_read==HIGH) { solenoidout=0; } else{ solenoidout=1; } //SendBuf[0] = 0xFF; //SendBuf[1] = 0xFF; SendBuf[0] = DirL; SendBuf[1] = Duty1; SendBuf[2] = DirR; SendBuf[3] = Duty2; SendBuf[4] = SUITONDirunder_out; SendBuf[5] = SUITONDirup_out; SendBuf[6] = solenoidout; SendBuf[7] = SUITONout; //SendBuf[4] = 0; Serial.write(255); Serial.write(255); //Serial.print(255); //Serial.println(255); for(i=0;i<8;i++){ //Serial.println(SendBuf[i]); Serial.write(SendBuf[i]); } Serial.write(0); //Serial.println(0); //Serial.print("VDataout"); //Serial.println(VDataout); //Serial.print("HDataout"); //Serial.println(HDataout); //Serial.println(SubSolenoid_read); delay(200); } ``` #### 受信側 ```html /*int PIN_OUT1=22; int PIN_OUT2=23; int PIN_OUT3=24; int PIN_OUT4=25;//←メインモータの回転方向*/ int PIN_VREF4=4; int PIN_VREF5=5; int PIN_VREF6=6; int PIN_VREF7=7;//←ここまで砲台モータ int PIN_VREF2=2; int PIN_VREF3=3; int PIN_VREFD8=8; int PIN_VREFD9=9;//←ここまでメインモータ int PIN_SUITON=10;//←放水モータ int PIN_solenoid=11;//電磁弁ONOFF int PIN_SUITOND=12;//←放水モータ方向 int RcvData=0; int RcvBuf[8];//配列数は送られてきたデータの数n カウント数はn-1 //int MT_Rin=5; //int MT_Lin=6; int MT_RoutSerial=0; int MT_LoutSerial=0; int MT_RoutSerial2=0; int MT_LoutSerial2=0; int MT_RSuboutSerial=0; int MT_LSuboutSerial=0; int i=0; int RcvState=0; //int RcvCountF=0; //int RcvCountS=0; int RcvC=0; int MT1D=0; int MT2D=0; int MT1S=0; int MT2S=0; int RcvCount=0; int SUITONvalue=0; int analogupper; int analoglower; int VDataout1; int VDataout2; void setup() { Serial.begin(9600); // 9600bpsでシリアルポートを開く /*pinMode(PIN_OUT1,OUTPUT); pinMode(PIN_OUT2,OUTPUT); pinMode(PIN_OUT3,OUTPUT); pinMode(PIN_OUT4,OUTPUT);*/ pinMode(PIN_VREF2,OUTPUT); pinMode(PIN_VREF3,OUTPUT); pinMode(PIN_VREF4,OUTPUT); pinMode(PIN_VREF5,OUTPUT); pinMode(PIN_VREF6,OUTPUT); pinMode(PIN_VREF7,OUTPUT); pinMode(PIN_VREFD8,OUTPUT); pinMode(PIN_VREFD9,OUTPUT); pinMode(PIN_SUITON,OUTPUT); pinMode(PIN_solenoid,OUTPUT); pinMode(PIN_SUITOND,OUTPUT); } void loop() { while(Serial.available() > 0){ RcvData=Serial.read(); //Serial.println(RcvData); //Serial.println(RcvState); switch(RcvState){ case 0: if(RcvData==255){ RcvState = 1; //Serial.print("RcvData1"); //Serial.println(RcvState); } break; case 1: if(RcvData==255){ RcvState = 2; //Serial.print(" RcvData2"); //Serial.println(RcvData); } else{ RcvState = 0; } break; case 2: RcvBuf[RcvCount]=RcvData; RcvCount++; if(RcvCount >=9){ RcvCount=0; RcvState = 3; //Serial.print(" RcvData*"); //Serial.println(RcvData); } break; case 3: MotorCnt(); RcvState=0; break; } //Serial.print(" RcvCount*"); //Serial.println(RcvCount); } //Serial.print(" RcvData*"); //Serial.println(RcvData); } void MotorCnt(){ //モータ1の制御 //digitalWrite(13, HIGH ); //delay(100); //digitalWrite(13, LOW ); //delay(100); //digitalwriteが先でanalogWriteが後!! analogupper = analogRead(A0); VDataout1 = map(analogupper,0,1023,0,255); analoglower = analogRead(A1); VDataout2 = map(analoglower,0,1023,0,255); if(RcvBuf[0]==0 || RcvBuf[0]==1){ if(RcvBuf[0] == 0){ MT_LoutSerial = RcvBuf[1]; //Serial.print("左前"); //Serial.print(MT_LoutSerial); digitalWrite(PIN_VREFD8,HIGH); analogWrite(PIN_VREF2,MT_LoutSerial); } else{ MT_LoutSerial = RcvBuf[1]; //Serial.print("左後"); //Serial.print(MT_LoutSerial); digitalWrite(PIN_VREFD8,LOW); analogWrite(PIN_VREF2,MT_LoutSerial); } if(RcvBuf[2] == 0){ MT_RoutSerial = RcvBuf[3]; //Serial.print("右前"); //Serial.println(MT_RoutSerial); digitalWrite(PIN_VREFD9,HIGH); analogWrite(13,MT_RoutSerial); } else{ MT_RoutSerial = RcvBuf[3]; //Serial.print("右後"); //Serial.println(MT_RoutSerial); digitalWrite(PIN_VREFD9,LOW); analogWrite(13,MT_RoutSerial); } } else{//MT_RoutSerial2とLoutSerial2は回転方向表示用変数 また,回転速度の表示を行うと,ジョイスティックが中立になっても,受信側の値が0にならないので,analogwrite(PWM出力)の値は強制的に0にしている //MT_RoutSerial2 = RcvBuf[0]; //MT_LoutSerial2 = RcvBuf[2]; //Serial.print("停止 "); //Serial.print("左回転方向"); //Serial.print(MT_LoutSerial2); //Serial.print("右回転方向"); //Serial.print(MT_RoutSerial2); //Serial.print("回転速度"); //Serial.print(MT_LoutSerial); //Serial.print(" "); //Serial.println(MT_RoutSerial); digitalWrite(PIN_VREFD8,LOW); digitalWrite(PIN_VREFD9,LOW); analogWrite(PIN_VREF2,0); analogWrite(PIN_VREF3,0); } if(RcvBuf[4]==0 || RcvBuf[4]==1){ if(RcvBuf[4] == 0){//ここから配列 ボタン入力の処理を描いてゆく if(VDataout1<170){ analogWrite(PIN_VREF4,50); analogWrite(PIN_VREF5,0); Serial.print("砲座X"); Serial.println(1); } else{ //角度が大きければ停止 analogWrite(PIN_VREF4,0); analogWrite(PIN_VREF5,0); Serial.print("砲座X"); Serial.println(2); } } else if(RcvBuf[4] == 1){ if(VDataout1>50){ analogWrite(PIN_VREF4,0); analogWrite(PIN_VREF5,50); Serial.print("砲座X"); Serial.println(3); } else{ //角度が大きければ停止 analogWrite(PIN_VREF4,0); analogWrite(PIN_VREF5,0); Serial.print("砲座X"); Serial.println(4); } } } else{ //ボタンが押されていないので停止 analogWrite(PIN_VREF6,0); analogWrite(PIN_VREF7,0); Serial.print("砲座X"); Serial.println(5); } if(RcvBuf[5]==0 || RcvBuf[5]==1){ if(RcvBuf[5] == 0){ if(VDataout2<190){ analogWrite(PIN_VREF6,70); analogWrite(PIN_VREF7,0); Serial.print("砲座Z"); Serial.println(1); } else{ analogWrite(PIN_VREF6,0); analogWrite(PIN_VREF7,0); Serial.print("砲座Z"); Serial.println(2); } } else if(RcvBuf[5] == 1){ if(VDataout2<30){ analogWrite(PIN_VREF6,0); analogWrite(PIN_VREF7,70); Serial.print("砲座Z"); Serial.println(3); } else{ analogWrite(PIN_VREF6,0); analogWrite(PIN_VREF7,0); Serial.print("砲座Z"); Serial.println(4); } } } else{ analogWrite(PIN_VREF6,0); analogWrite(PIN_VREF7,0); Serial.print("砲座Z"); Serial.println(5); } if(RcvBuf[6] == 1){ SUITONvalue = RcvBuf[7]; digitalWrite(PIN_SUITOND,HIGH); analogWrite(PIN_SUITON,SUITONvalue); digitalWrite(PIN_solenoid,HIGH); } else{ SUITONvalue = 0; digitalWrite(PIN_SUITOND,HIGH); analogWrite(PIN_SUITON,0); digitalWrite(PIN_solenoid,LOW); } Serial.print("可変抵抗⇓"); Serial.println(VDataout2); delay(100); } ``` 電子部品 --- 最後に本製作例で使用した電子部品を紹介します. |部品名|購入先| |---|---|---| |Arduino uno|秋月電子通商orマルツパーツor千石電商| |Polplu24V21|朱雀技研| |モータRS775|朱雀技研| |モータRS775ギアヘッド|朱雀技研| |トグルスイッチ小|秋月電子通商orマルツパーツor千石電商| |トグルスイッチ大|アマゾン| |バイクバッテリー|アマゾン| |電線|秋月電子通商orマルツパーツor千石電商or近くのホームセンター| |Arduino変換基盤|秋月電子通商orマルツパーツor千石電商| |XBeeと変換基盤|秋月電子通商orマルツパーツor千石電商| |ジョイスティックレバー|秋月電子通商orマルツパーツor千石電商| |ピンヘッダとピンソケット|秋月電子通商orマルツパーツor千石電商| |電子基板|秋月電子通商orマルツパーツor千石電商 また,記載されている内容で不備や,不足しているところ,追加してほしい内容が ありましたら,ご連絡ください. (レスポンスは悪いかもしれませんが)