/*このスケッチを丸ごとコピーするだけでは再現できません。機体に合わせた設定値の変更が必要です。
------------------------------------------------------------------------------------*/
#include "Servo.h" //サーボ用ライブラリー
#include "IRremote.h" //赤外線リモコン用ライブラリー
Servo leftservo;//左サーボを定義
Servo rightservo;//右サーボを定義
Servo USservo;//超音波サーボを定義
const int trigger = 7;//トリガーを7番ピンに定義
const int echo = 6;//エコーを6番ピンに定義
const int modeLED = 9;//modeLEDを7番ピンに定義
const int PowerLED = 10;//PowerLEDを6番ピンに定義
const int distancelimit = 12;//超音波センサー前方距離リミット値
const int sidedistancelimit = 10;//超音波センサー横側距離リミット値
const int turntime = 200;//左右旋回時間の設定
int leftscanval, centerscanval, rightscanval;//超音波距離測定の定義
int receiver = 4;//赤外線受信センサーを4番ピンに定義
int modecontrol = 0;//モードコントロールの初期値
int power = 0;//パワー初期値
int distance;
int numcycles = 0;
int thereis;
IRrecv irrecv(receiver);//赤外線受信の定義
decode_results results;
char choice;
char contcommand;
char turndirection;
void setup() {
rightservo.attach(11);//右サーボを11番ピンに設定
rightservo.write(90);//初期サーボ角度を設定
USservo.attach(12);//超音波センサーサーボを12番ピンに設定
USservo.write(90);//初期サーボ角度を設定
leftservo.attach(13);//左サーボを13番ピンに設定
leftservo.write(90);//初期サーボ角度を設定
irrecv.enableIRIn();//赤外線受信センサーを設定
pinMode(trigger, OUTPUT);//トリガーを出力ピンに設定
pinMode(echo, INPUT);//エコーを入力ピンに設定
pinMode(PowerLED, OUTPUT);//PowerLEDを入力ピンに設定
pinMode(modeLED, OUTPUT);//modeLEDを入力ピンに設定
digitalWrite(trigger, LOW);//トリガーをLOWに設定
digitalWrite(modeLED, LOW);//PowerLEDをLOWに設定
digitalWrite(PowerLED, LOW);//PowerLEDをLOWに設定
}
int watch() {//以下、超音波センサーの設定
long howfar;
digitalWrite(trigger, LOW);
delayMicroseconds(5);
digitalWrite(trigger, HIGH);
delayMicroseconds(15);
digitalWrite(trigger, LOW);
howfar = pulseIn(echo, HIGH);
howfar = howfar * 0.01657;
return round(howfar);
}
void forwards() {//前進時のサーボ角度設定
leftservo.write (150);
rightservo.write (25);
}
void backwards() {//後進時のサーボ角度設定
leftservo.write (30);
rightservo.write (150);
}
void turnleft(int t) {//左旋回時のサーボ角度設定
leftservo.write (85);
rightservo.write (85);
delay(t);
}
void turnright(int t) {//右旋回時のサーボ角度設定
leftservo.write (95);
rightservo.write (95);
delay(t);
}
void stopmove() {//ストップ時のサーボ角度設定
leftservo.write (90);
rightservo.write (90);
}
void watchsurrounding() {
USservo.write(90);//ソナーサーボを90度(前方)に向ける
delay(200);//200ms状態を保持
centerscanval = watch();//前方を監視
if (centerscanval < distancelimit) {//前方の距離がリミットより短い場合
stopmove();//停止
}
USservo.write(140);//ソナーサーボを140度(斜め左前方)に向ける
delay(100);//100ms状態を保持
leftscanval = watch();//左側を監視
if (leftscanval < sidedistancelimit) {//左側の距離が横側リミットより短い場合
stopmove();//停止
}
USservo.write(90);//ソナーサーボを90度(前方)に向ける
delay(200);//200ms状態を保持
centerscanval = watch();//前方を監視
if (centerscanval < distancelimit) {//前方の距離がリミットより短い場合
stopmove();//停止
}
USservo.write(40);//ソナーサーボを40度(右斜め前方)に向ける
delay(100);//100ms状態を保持
rightscanval = watch();//右側を監視
if (rightscanval < sidedistancelimit) {//右側の距離が横側リミットより短い場合
stopmove();//停止
}
}
char decide() {
watchsurrounding();//周囲の監視
if (leftscanval > rightscanval && leftscanval > centerscanval) {
choice = 'l';//左より右の距離が近く、且つ左より前方の距離が近い場合は'l'
}
else if (rightscanval > leftscanval && rightscanval > centerscanval) {
choice = 'r';//右より左の距離が近く、且つ右より前方の距離が近い場合は'r'
}
else {
choice = 'f';//それ以外の場合は'f'
}
return choice;
}
void translateIR() {//赤外線リモコンの手動運転モード(シャープ製テレビリ用モコンの場合)
switch (results.value) {
case 0xF148EA81: // ↑ボタン
forwards();// 前進
break;
case 0xF148EB80: // ←ボタン
turnleft(turntime);// 左旋回
stopmove();//turntime設定時間後停止
break;
case 0xF1484A8B: // 決定ボタン
stopmove();//停止
break;
case 0xF1481B8F: // →ボタン
turnright(turntime);// 右旋回
stopmove();//turntime設定時間後停止
break;
case 0xF1480481: // ↓ボタン
backwards();// 後進
break;
case 0xF148C144: // 黄色ボタン(手動モード終了)
modecontrol = 0;//モードを0に戻す
stopmove();//停止
digitalWrite (modeLED, LOW);//modeLEDを消灯
break;
default:
;
}
delay(500);
}
void loop() {
if (irrecv.decode(&results)) { //赤外線リモコンによるモード切り替え
if (results.value == 0xF1480148) { // 青色ボタン(スタート)
power = 1;//自動運転ON
digitalWrite (PowerLED, HIGH);//PowerLEDを点灯
}
if (results.value == 0xF1488140) { // 赤ボタン(ストップ)
stopmove();//停止
power = 0;//自動運転OFF
digitalWrite (PowerLED, LOW);//PowerLEDを消灯
}
if (results.value == 0xF148C144) { // 黄ボタン(手動モード開始)
modecontrol = 1;//手動運転モード
stopmove();//停止
digitalWrite (modeLED, HIGH);//modeLEDを点灯
}
irrecv.resume();//受信待機
}
while (modecontrol == 1) { //手動運転が選択された場合
if (irrecv.decode(&results)) { //赤外線受信デコード
translateIR();//関数実行
irrecv.resume();//受信待機
}
}
if (power == 1) { //赤外線リモコンの青色ボタンが押された場合
forwards();//前進
++numcycles;//numcyclesを加算
if (numcycles > 100) { //numcyclesカウンターが100以上になれば
watchsurrounding();//watchsurrounding()を実行
if (leftscanval < sidedistancelimit) { //左横リミット内に入った場合
turnright(turntime);//右旋回
}
if (rightscanval < sidedistancelimit) { //横リミット内に入った場合
turnleft(turntime);//左旋回
}
numcycles = 0;//カウンターを戻す
}
distance = watch();//リミット内に入った場合の処理
if (distance < distancelimit) {//リミット内に入った場合
++thereis;//thereisカウンターを加算
}
if (distance > distancelimit) {//リミット外に出た場合
thereis = 0;//thereisカウンターを戻す
}
if (thereis > 15) {//thereisカウンター値が15以上になった場合
stopmove();//停止
turndirection = decide();
switch (turndirection) {
case 'l':
turnleft(turntime);//左旋回
break;
case 'r':
turnright(turntime);//右旋回
break;
case 'f':
;
break;
}
thereis = 0;//thereisカウンター値が15以下の場合は0
}
}
}
|