Arduinoでロボットを作ってみました!【12】動作試験Part2:走行試験
直進走行試験
前進と後進を行って、真直ぐに走行できるかを確認してみます。動作に使用したスケッチは、以下の通りで、首関節をホームポジションに移動→前進4秒→停止5秒→後進5秒→停止5秒を繰り返します。DCモータの駆動はdigitalWriteで行います。
//ARD-R01動作確認:digitalWriteによる直線走行
#include <Servo.h> // ライブラリの読み込み<Servo.h>
Servo servo0,servo1,servo2; // Servo型の変数は「servo0」~「servo2」とする
void setup() //初期設定
{
pinMode(11, OUTPUT); //ピン11を出力に設定(LモータIN1)
pinMode(10, OUTPUT); //ピン10を出力に設定(LモータIN2)
pinMode(9, OUTPUT); //ピン9を出力に設定(RモータIN1)
pinMode(8, OUTPUT); //ピン8を出力に設定(RモータIN2)
servo0.attach(4); // Servo型の変数は「servo0(θ)」をピン4に割り当てる
servo1.attach(5); // Servo型の変数は「servo1(α)」をピン5に割り当てる
servo2.attach(6); // Servo型の変数は「servo2(β)」をピン6に割り当てる
}
void loop() //メインの処理
{
// スコープを中立位置に移動
servo0.write(90); // サーボ出力。θ角度は90°
servo1.write(80); // サーボ出力。α角度は80°
servo2.write(100); // サーボ出力。β角度は100°
delay(1000); // タイマ(1秒)
//DCモータ駆動
//前進
//Lモータ前進回転
digitalWrite(11, HIGH); //ピン11にHIGH(1)を出力
digitalWrite(10, LOW); //ピン10にLOW(0)を出力
//Rモータ前進回転
digitalWrite(9, HIGH); //ピン9にHIGH(1)を出力
digitalWrite(8, LOW); //ピン8にLOW(0)を出力
delay(4000);
//停止
digitalWrite(11, LOW);
digitalWrite(10, LOW);
digitalWrite(9, LOW);
digitalWrite(8, LOW);
delay(5000);
//後進
//Lモータ後進回転
digitalWrite(11, LOW);
digitalWrite(10, HIGH);
//Rモータ後進回転
digitalWrite(9, LOW);
digitalWrite(8, HIGH);
delay(4000);
//停止
digitalWrite(11, LOW);
digitalWrite(10, LOW);
digitalWrite(9, LOW);
digitalWrite(8, LOW);
delay(5000);
}
あまり直進性は良くないようです。
analogWriteによるDCモータ駆動を試す
analogWriteでDCモータを動かしてみて、直進性が改善するかを試してみます。DCモータ駆動のdigitalWriteをanalogWriteに変更してみます。
:
//DCモータ駆動
//前進
//Lモータ前進回転
analogWrite(11, 230); //ピン11にアナログ値 230を出力
analogWrite(10, 0); //ピン10にアナログ値 0を出力
//Rモータ前進回転
analogWrite(9, 255); //ピン9にアナログ値 255を出力
analogWrite(8, 0); //ピン8にアナログ値 0を出力
delay(4000);
:
//後進
//Lモータ後進回転
analogWrite(11, 0);
analogWrite(10, 255);
//Rモータ後進回転
analogWrite(9, 0);
analogWrite(8, 255);
delay(4000);
:
前進の直進性が改善されたために、後進の際に左側に曲がるのが目立ってきました。そこで、後進の際のRモータの回転を少し遅くしようと思い、
analogWrite(8, X);
のXの値を小さくしていったのですが、動きに変化がありません。いろいろとXの値を変化していくと、
X=128~255ではX=255と同じ動き
X≦127ではモータ停止
原因は、Arduino UNOにおいて、アナログ出力(PWM出力)ができるピンは
ピン番号:3, 5, 6, 9, 10, 11
のみ(ピン番号の後ろに~がついているピン)で、PWM出力に対応していない8番ピンにanalogWriteを設定しても、扱いはdigitalWriteと同等になってしまうためのようです。
analogWrite(8, 128~255) → digitalWrite(8, HIGH)
analogWrite(8, 0~127) → digitalWrite(8, LOW)
回路の修正
PWM出力が可能なピン番号を意識しないで回路設計をしてしまいましたので、接続ピン番号を下表のように修正します。
走行速度と瞳LEDの明るさとを可変にしたいと思いますので、モータードライバーとLEDとをPWM出力ピンにつなぎます。また、0, 1番ピンはシリアル通信用のピンなので、空けておくことにします。
analogWriteによるDCモータ駆動を試す Part2
上記の回路修正を行い、再度走行試験を行います。
//ARD-R01動作確認:analogWriteによる直線走行
#include <Servo.h> // ライブラリの読み込み<Servo.h>
Servo servo0,servo1,servo2; // Servo型の変数は「servo0」~「servo2」とする
void setup() //初期設定
{
pinMode(11, OUTPUT); //ピン11を出力に設定(LモータIN1)
pinMode(10, OUTPUT); //ピン10を出力に設定(LモータIN2)
pinMode(6, OUTPUT); //ピン6を出力に設定(RモータIN1)
pinMode(5, OUTPUT); //ピン5を出力に設定(RモータIN2)
servo0.attach(2); // Servo型の変数は「servo0(θ)」をピン2に割り当てる
servo1.attach(4); // Servo型の変数は「servo1(α)」をピン4に割り当てる
servo2.attach(7); // Servo型の変数は「servo2(β)」をピン7に割り当てる
}
void loop() //メインの処理
{
// スコープを中立位置に移動
servo0.write(90); // サーボ出力。θ角度は90°
servo1.write(80); // サーボ出力。α角度は80°
servo2.write(100); // サーボ出力。β角度は100°
delay(1000); // タイマ(1秒)
//DCモータ駆動
//前進
//Lモータ前進回転
analogWrite(11, 233); //ピン11にアナログ値 233を出力
analogWrite(10, 0); //ピン10にアナログ値 0を出力
//Rモータ前進回転
analogWrite(6, 255); //ピン6にアナログ値 255を出力
analogWrite(5, 0); //ピン5にアナログ値 0を出力
delay(4000);
//停止
digitalWrite(11, LOW);
digitalWrite(10, LOW);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
delay(5000);
//後進
//Lモータ後進回転
analogWrite(11, 0);
analogWrite(10, 255);
//Rモータ後進回転
analogWrite(6, 0);
analogWrite(5, 252);
delay(4000);
//停止
digitalWrite(11, LOW);
digitalWrite(10, LOW);
digitalWrite(6, LOW);
digitalWrite(5, LOW);
delay(5000);
}
後進に対してもanalogWriteが有効となり、前進、後進共に直進性が向上しました。
瞳LEDの明るさコントロール試験
瞳LEDの配線も PWM出力ピンに配線変更を行いましたので、明るさのコントロールができるか確認してみます。首を傾けて、瞳LEDの明るさを徐々に明るくし(0→255)、徐々に暗くする(255→0)動作を行ってみます。
//ARD-R01動作確認:LED明るさ調整
#include <Servo.h> // ライブラリの読み込み<Servo.h>
Servo servo0,servo1,servo2; // Servo型の変数は「servo0」~「servo2」とする
void setup() //初期設定
{
pinMode(3, OUTPUT); //ピン3(LED R)に出力設定
pinMode(9, OUTPUT); //ピン9(LED L)に出力設定
servo0.attach(2); // Servo型の変数は「servo0(θ)」をピン2に割り当てる
servo1.attach(4); // Servo型の変数は「servo1(α)」をピン4に割り当てる
servo2.attach(7); // Servo型の変数は「servo2(β)」をピン7に割り当てる
}
void loop() //ループ
{
// スコープを中立位置に移動
servo0.write(90);
servo1.write(80);
servo2.write(100);
delay(2000);
// 上を向いて首を右に傾け、右目をゆるやかに明るくした後暗くする
servo1.write(20);
servo2.write(30);
delay(1000);
int i; //iはint型変数
for(i=0; i<=255; i=i+1)
{
analogWrite(3, i); //ピン3にアナログ値(0~255)を出力
delay(10); //タイマ(10msec)
}
for(i=255; i>=0; i=i-1)
{
analogWrite(3, i); //ピン3にアナログ値(255~0)を出力
delay(10); //タイマ(10msec)
}
// 上を向いて首を左に傾け、左目をゆるやかに明るくした後暗くする
servo1.write(20);
servo2.write(170);
delay(1000);
for(i=0; i<=255; i=i+1)
{
analogWrite(9, i); //ピン9にアナログ値(0~255)を出力
delay(10); //タイマ(10msec)
}
for(i=255; i>=0; i=i-1)
{
analogWrite(9, i); //ピン9にアナログ値(255~0)を出力
delay(10); //タイマ(10msec)
}
}
上を向いて首を右に傾け、右目をゆるやかに明るくした後暗くする動作は期待通りに実行されているのですが、上を向いて首を左に傾けた後の、左目の明るさコントロールができていません。原因を調べたところ、
”いずれかのピンがattach()されると9番,10番ピンからのPWM出力ができなくなる”
のが仕様であることが分かりました。つまり、9番ピンに接続したLED LへはPWM出力ができないためにこのような動きになってしまいました。
再度回路の修正
RCサーボも動かそうとすると、PWM出力が可能なピンは、3, 5, 6, 11の4ピンのみとなります。瞳LEDの明るさコントロールは外せませんから、走行速度制御は後進時はあきらめて前進時のみとして、接続ピン番号を下表のように修正します。
修正した回路図は下図のようになります。
スケッチも修正して、
//ARD-R01動作確認:LED明るさ調整
#include <Servo.h> // ライブラリの読み込み<Servo.h>
Servo servo0,servo1,servo2; // Servo型の変数は「servo0」~「servo2」とする
void setup() //初期設定
{
pinMode(3, OUTPUT); //ピン3(LED R)に出力設定
pinMode(5, OUTPUT); //ピン5(LED L)に出力設定
servo0.attach(2); // Servo型の変数は「servo0(θ)」をピン2に割り当てる
servo1.attach(4); // Servo型の変数は「servo1(α)」をピン4に割り当てる
servo2.attach(7); // Servo型の変数は「servo2(β)」をピン7に割り当てる
}
void loop() //ループ
{
// スコープを中立位置に移動
servo0.write(90);
servo1.write(80);
servo2.write(100);
delay(2000);
// 上を向いて首を右に傾け、右目をゆるやかに明るくした後暗くする
servo1.write(20);
servo2.write(30);
delay(1000);
int i; //iはint型変数
for(i=0; i<=255; i=i+1)
{
analogWrite(3, i); //ピン3にアナログ値(0~255)を出力
delay(10); //タイマ(10msec)
}
for(i=255; i>=0; i=i-1)
{
analogWrite(3, i); //ピン3にアナログ値(255~0)を出力
delay(10); //タイマ(10msec)
}
// 上を向いて首を左に傾け、左目をゆるやかに明るくした後暗くする
servo1.write(20);
servo2.write(170);
delay(1000);
for(i=0; i<=255; i=i+1)
{
analogWrite(5, i); //ピン5にアナログ値(0~255)を出力
delay(10); //タイマ(10msec)
}
for(i=255; i>=0; i=i-1)
{
analogWrite(5, i); //ピン5にアナログ値(255~0)を出力
delay(10); //タイマ(10msec)
}
}
これでようやく期待通りの動きができるようになりました。
8の字走行試験
DCモータの速度制御とLEDの明るさ制御をトータルで確認するために、8の字走行試験を行います。今回のスケッチでは、関数の定義やRCサーボを駆動する際に、動かしたらservo.detach()することで、停止時に「ジジ」とか「カリ」と鳴いたり、時々震えるような現象を抑えることも試みます。
時計回りに一定の半径を保って走り、中間位置で停止、首を振って瞳LEDの明るさを変化させ、反時計回りに一定の半径を保って走るという動作を行います。
//ARD-R01動作確認:8の字走行試験
#include <Servo.h> // ライブラリの読み込み<Servo.h>
Servo servo0,servo1,servo2; // Servo型の変数は「servo0」~「servo2」とする
void setup() //初期設定
{
pinMode(3, OUTPUT); //ピン3に出力設定(LED R)
pinMode(5, OUTPUT); //ピン5に出力設定(LED L)
pinMode(11, OUTPUT); //ピン11に出力設定(LモータIN1)
pinMode(10, OUTPUT); //ピン10に出力設定(LモータIN2)
pinMode(6, OUTPUT); //ピン6に出力設定(RモータIN1)
pinMode(9, OUTPUT); //ピン9に出力設定(RモータIN2)
servo0.attach(2); // Servo型の変数は「servo0(θ)」をピン2に割り当てる
servo1.attach(4); // Servo型の変数は「servo1(α)」をピン4に割り当てる
servo2.attach(7); // Servo型の変数は「servo2(β)」をピン7に割り当てる
}
void loop() //ループ
{
//停止
move_stop(5000);
// スコープを中立位置に移動
scope_np(2000);
// 時計回り走行
move_straight(500);
move_curve(255, 50, 8000);
move_straight(500);
move_stop(2000);
// 上を向いて首を右に傾け、右目をゆるやかに明るくした後暗くする
scope_drive(80, 20, 30, 1000);
int i; //iはint型変数
for(i=0; i<=255; i=i+1)
{
analogWrite(3, i); //ピン3にアナログ値(0~255)を出力
delay(10); //タイマ(10msec)
}
for(i=255; i>=0; i=i-1)
{
analogWrite(3, i); //ピン3にアナログ値(255~0)を出力
delay(10); //タイマ(10msec)
}
// 上を向いて首を左に傾け、左目をゆるやかに明るくした後暗くする
scope_drive(110, 20, 170, 1000);
for(i=0; i<=255; i=i+1)
{
analogWrite(5, i); //ピン5にアナログ値(0~255)を出力
delay(10); //タイマ(10msec)
}
for(i=255; i>=0; i=i-1)
{
analogWrite(5, i); //ピン5にアナログ値(255~0)を出力
delay(10); //タイマ(10msec)
}
//反時計回り走行
move_straight(500);
move_curve(65, 255, 9000);
move_straight(500);
move_stop(2000);
}
//関数の定義
//前進(直進)
void move_straight(int ms)
{
analogWrite(11, 233);
digitalWrite(10, LOW);
analogWrite(6, 255);
digitalWrite(9, LOW);
delay(ms);
}
//前進(曲線走行)
void move_curve(int MLS, int MRS, int ms)
{
analogWrite(11, MLS);
digitalWrite(10, LOW);
analogWrite(6, MRS);
digitalWrite(9, LOW);
delay(ms);
}
//後進
void move_back(int ms)
{
digitalWrite(11, LOW);
digitalWrite(10, HIGH);
digitalWrite(6, LOW);
digitalWrite(9, HIGH);
delay(ms);
}
//停止
void move_stop(int ms)
{
digitalWrite(11, LOW);
digitalWrite(10, LOW);
digitalWrite(6, LOW);
digitalWrite(9, LOW);
delay(ms);
}
//スコープ中立位置移動
void scope_np(int ms)
{
servo0.attach(2);
servo1.attach(4);
servo2.attach(7);
servo0.write(90);
servo1.write(80);
servo2.write(100);
delay(ms);
servo0.detach();
servo1.detach();
servo2.detach();
}
//スコープ駆動
void scope_drive(int deg0, int deg1, int deg2, int ms)
//deg0(θ)設定範囲:45~135°
//deg1(α)設定範囲:20~140°
//deg1(β)設定範囲:30~170°
{
servo0.attach(2);
servo1.attach(4);
servo2.attach(7);
servo0.write(deg0);
servo1.write(deg1);
servo2.write(deg2);
delay(ms);
servo0.detach();
servo1.detach();
servo2.detach();
}
反時計回りの動きの安定性が少々悪いですが、DCモータの速度制御とLEDの明るさ制御ができていることを確認できました。