はじめに
ここでは、Arduino UNOで ラジコンサーボ を動かす実験をします。
目次へ戻るには ここ をクリック
※本ページは実験のテキストです。
ラジコンサーボとは
一般に「サーボモーター」と言うと、産業用の機械に使われるモーター・ギアボックス・回転角度センサが一体となったシステムの事を指します。
一方、トイ・ホビー用途であるラジコン(ラジオ・コントロールを略してRCとも言う)の世界では,RCカーやRC飛行機、RCヘリコプターに使用するプロポーショナル・サーボシステムの事を「サーボモーター」「サーボ」「ラジコンサーボ」「RCサーボ」などと呼んでいます.
簡単に言えば「通称『サーボモーター』には,ガチとオモチャの2種類がある」ということです.
ガチのサーボモーターを使うには,「モータ駆動回路」「角度検出回路」などの回路を別途用意する必要があります.
ホビーの方はそれら周辺回路基板も含めてモーターケースの中に内蔵されているので、単独で使うことができるのが特徴です.
ラジコンサーボの用途
前述したように,ラジコンサーボは元々,
- RCカーではステアリングの動作
- RC飛行機では動作
- ヘリコプターではプロペラピッチの動作
しかし,ラジコンサーボはモーターの回転角度を比較的簡単な信号で変えることができるので,
ロボットアームや二足歩行ロボット,四脚ロボットなどの様々なロボットが作られるようになりました.
近年「Maker(メイカー)」と呼ばれている,電子工作やものづくりの世界では,ラジコンサーボは多用されています.
ラジコンサーボの信号
ラジコンサーボを動かすためには,「ラジコンサーボ信号」と呼ばれる特殊な信号を送ってやる必要があります.
長いので,以降は「サーボ信号」と略させてもらいます.
上の図を見ながら読んで下さい.
サーボ信号は,20ミリ秒おきに1回送信します.
1回送信するだけではダメで,常に送り続ける必要があります.
信号の状態は通常はLOW(0[V])ですが,HIGH(5[V])にするパルス幅の長さでラジコンサーボの角度が変わります.
1500マイクロ秒(1.5ミリ秒)が基準になる中央の値です(厳密に言うとフタバは1520マイクロ秒ですが).
1500±700マイクロ秒にHIGHの時間を変えることで,サーボの角度が変わります.
ラジコンサーボ信号はPPM信号と言います.
「Pulse Position Modulation」の略で,日本語だと「パルス位置変調」になります.
PWM (Pulse Width Modulation=パルス幅変調)に非常によく似ていますが,PWMのパルス幅は0~100%の全域で使うのに対して,PPMは20ミリ秒のうち4~11%の部分しか使いません.
サーボ信号をPWM信号と解説している方もいますが,厳密には「 広い意味でのPWMで,PWMの特定デューティ比しか使わない 」となります.
図では800マイクロ秒が-90度とか2200マイクロ秒が+90度と書いていますが,これ正確に90度じゃないです.
製品によって動作範囲が違うので,実物で試して使うしかありません.
Amazon等で売っている「HJサーボテスター」を使うと,800~2200マイクロ秒の値を確認しながらサーボ信号が出せます.
・Amazon 「HJサーボテスター」
HJサーボテスターの3つの動作モードの説明。
— hsgucci404 (@hsgucci404) April 20, 2023
・ツマミで800〜2200usに可変
・1500usのニュートラルで固定
・800〜2200を往復(ツマミはスイープ速度) pic.twitter.com/eoDvb9yw6A
Qiitaにも,HJサーボテスターの記事を書かれている方がいました.
・HJサーボテスターを使ってみた
ラジコンサーボを使ったロボットをつくる人は,動作確認用に「サーボテスター」を1つ持っておくといいでしょう.
HJサーボテスター以外にも,もっと簡易的な製品もありますし,Arduinoで作ることもできます.
ラジコンサーボのケーブル色
ラジコンサーボは,製造会社によってケーブルの色が異なります.
真ん中の 5V(電源)が赤色 という点は共通ですが,サーボ信号とGNDの色が異なっています.
- JRPROPO系だと サーボ信号が橙色, GNDが茶色 です.
- フタバ・近藤科学系だと サーボ信号が白色 , GNDが黒色 です.
分からなくなったら, 色が暗い&濃い方がGND と覚えておくと良いでしょう.
Arduinoとラジコンサーボの配線
まずは物理的な配線をします.
下の図のように,Arduinoとラジコンサーボを配線してください.
ラジコンサーボのコネクタと,Arduinoとをジャンパ線で接続します.
サーボ信号は9番ピンに接続 してください.
参考として,実際の写真を掲載しておきます.
サンプルスケッチを読み込む
Arduinoには,ラジコンサーボを動かすサンプルプログラムが標準で準備されています.
メニューバーから,[ ファイル ]-[ スケッチ例 ]-[ Servo ]-[ Sweep ]を開きます.
コンパイル,プログラムの書き込み,実行
それでは,これまでと同様に、コンパイルし,マイコンへの書き込みを行ってください。
書き込みが完了すると,プログラムが実行されて,いきなりサーボが動き始めます.
サーボが右へ左へと永遠に動き続けます.
プログラム的には0~180度を動くように命令していますが,実際はどのくらい動いているのか確認してみましょう.
うるさいと思ったら,電源の5Vの線を外して止めましょう.
スケッチの解説
実際のプログラムは英語でコメントが書かれていますが,日本語にしたSweep.inoを掲載しておきます.
#include <Servo.h> // Servo.hをインクルード
Servo myservo; // Servoクラスの実体(インスタンス)をmyservoとして作成
// ほとんどのボードで12個のクラスが作れる=12個のサーボが動かせる
int pos = 0; // サーボ角度の変数
// 初期化関数
void setup() {
myservo.attach(9); // myservoクラスに9番ピンを接続する
}
// ループ関数
void loop() {
for (pos = 0; pos <= 180; pos += 1) { // 0 -> 180度へ,1度ずつ増加
myservo.write(pos); // write関数で出力
delay(15); // 15ミリ秒のウェイトを入れる.ウェイトがないと一瞬で終わってしまう
}
for (pos = 180; pos >= 0; pos -= 1) { // 180 -> 0度へ,1度ずつ減少
myservo.write(pos);
delay(15);
}
}
それぞれ解説していきます.
#include <Servo.h> // Servo.hをインクルード
Servo myservo; // Servoクラスの実体(インスタンス)をmyservoとして作成
// ほとんどのボードで12個のクラスが作れる=12個のサーボが動かせる
int pos = 0; // サーボ角度の変数
Servo.h は,Arduino開発環境であらかじめ準備されているので,いきなり #include
して使えます.
Servo myservo;
でServoクラスのインスタンスmyservoを宣言しています.
ところで,int a;
は「int型の変数aを宣言する」と言いますが,「Servo型の変数myservoを宣言」とは言いません.
クラスは内部に変数と関数を持っていて,intやfloatのような単純な型とは別の存在なので,インスタンスとかオブジェクトという言い方をするのです.
int pos = 0;
でサーボの角度の数値が入る変数posを宣言しています.0~180の値が入ります.
次は初期化関数です.
// 初期化関数
void setup() {
myservo.attach(9); // myservoクラスに9番ピンを接続する
}
myservoが持っているattach
関数を使って,使うピンを指定しています.
attachは「取り付ける」という意味ですから,myservoと実際のピンを関係づける,というような感覚ですね.
解説:servo.attach関数
次はループ関数です.
// ループ関数
void loop() {
for (pos = 0; pos <= 180; pos += 1) { // 0 -> 180度へ,1度ずつ増加
myservo.write(pos); // write関数で出力
delay(15); // 15ミリ秒のウェイトを入れる.ウェイトがないと一瞬で終わってしまう
}
for (pos = 180; pos >= 0; pos -= 1) { // 180 -> 0度へ,1度ずつ減少
myservo.write(pos);
delay(15);
}
}
for文を使って,posの値を0から180まで増やし,そのposをmyservo.write
関数を使って出力しています.
解説:servo.write関数
その後,同じ要領で180から0まで減らして出力します.
動作としては,下図のような動きを繰り返すことになりますね.
ループが1回まわる度にdelay(15);
で待ち時間を入れているのは,
これが無いとforループが一瞬で終わってしまい,サーボの角度が変わる前に次の角度がwriteされてしまうからです.
補足
このサンプルプログラムは,0->180->0という動きでループ関数が1周まわるように書かれています.
正直,このような書き方は望ましくありません.
本来ループ関数は短い時間で高速に何回も回るべき関数です.
今は,1周に15ミリ秒 x 360回 = 5.4秒かかっています.
このようなプログラムだと,例えば他のセンサ入力に反応するプログラムを書いたとしても,5.4秒後にしか対応できないことになります.(もちろん,書き方次第でfor文の中でも対応することも可能ですが)
「他事(ほかごと)できないやん!」とツッコミたくなるプログラムなのです.
例えばですが,以下のプログラムのように,
loop関数の繰り返しをうまく利用するほうが,マルチタスクで同時並行的に動作するプログラムへと発展させる余裕が残ります.
// グローバル変数
int pos = 0;
int val = 1;
// 初期化関数は省略
// ループ関数
void loop() {
if( pos == 0 ) val = 1;
if( pos == 180 ) val = -1;
pos += val;
myservo.write(pos);
delay(15);
}
シリアル通信の際のブロッキング関数ではありませんが,1回のループに長時間かけてはいけないのです.
まとめ
ラジコンサーボでは,
- Servo.hを#includeすれば使えるようになる
- 変数を作るのと同様に,Servoクラスのインスタンスを作る
- attach関数で,どのピンに出力するのかを決める
- write関数に0~180の数値を書くことで,サーボが動く
- 1周に時間がかかるloop関数を書くのは良くない
という事が分かったと思います。
目次 へ戻って次の作業を行ってください。