ラズパイ WiringPi 連続回転サーボ


20160505_raspi_servo

LED明暗 に続いて、ラズパイで WiringPi を使って、連続回転サーボを制御します。
LED明暗と同様に、ハードウェア PWM を使います。

設定
設定には、5つの関数を使用します。
それぞれ、ラズパイの BCM2835 / BCM2836 のレジスタと関連しています。

pinMode
pin のモードとして、PWM_OUTPUT を設定します。
これを最初に設定しないと、以降の関数が効かなかったです。

pwmSetMode
PWMのモードを設定します。
PWM には、2つのモードがあります。
バランスド (balanced) と マーク・スペース (mark:space) です。
スペースは周期で、マークはパルス幅です。
バランスドは、デューティ比 50% です。
20160530_wiringpi_pwm_mode

サーボに必要なのは、下記のような信号なので、マーク・スペースに設定します。
20160425_servo_control_2

pwmSetClock
クロックの分周比を設定します。
PWMのクロックは、19.2 MHz です。
サーボでは、パルス幅 ±0.5ms で制御します。
制御の刻みを 100 とすると、分周比は 96 です。
0.5ms / 100 = 5μs (200 KHz)
19.2 MHz / 200 KHz = 96

pwmSetRange
PWMの周期となるクロック数を設定します。
サーボのパルス周期は、20ms なので、クロック数は 400 です。
20ms / 5μs = 4000

pwmWrite
パルス幅となるクロック数を設定します。
1.5ms のときは、300 です。
1.5ms / 5μs = 300

動作確認
サーボには3本の線があります。
赤を Pin4 (+5v)、黒を Pin6 (GND)、白を Pin12 (GPIO18) に接続します。

wiringpi_servo_pulse.py (github)
パルス幅のクロック数 を 200、290、300、310、400 と変化させて、
時計周り(高速)、時計周り(低速)、停止、反時計周り(低速)、 反時計周り(高速) となることを確認します。

wiringpi_servo_speed.py (github)
パルス幅で指定するのは使い難いので、速度で指定するようにしました。
速度の範囲は、−100 から 100 です。

オシロでの測定
周期 20ms、パルス幅 1.5ms となっています。
RPi.GPIO では、ジッタ が見られましたが、今回は綺麗です。

周期 20ms
20160530_wiringpi_pwm_20ms

パルス幅 1.5ms
20160530_wiringpi_pwm_1_5ms

参考
Raspberry Pi Specifics – Wiring Pi
・void pinMode (int pin, int mode)
pin に対して、mode として、INPUT、 OUTPUT、 PWM_OUTPUT、または GPIO_CLOCK のいずれかを設定します。

・pwmSetMode (int mode)
PWMジェネレータは、 2つのモードで実行することができます。
バランスド (balanced) と マーク・スペース (mark:space) です。
マーク・スペースが伝統的な方式ですが、ラズパイのデフォルトのモードはバランスドです。
mode にパラメータを設定することで、モードを切り替えることができます。
PWM_MODE_BAL か PWM_MODE_MS です。

・pwmSetRange (unsigned int range)
PWMジェネレータ内のレンジ・レジスタを設定します。
デフォルトは1024です。

・pwmSetClock (int divisor)
PWMクロックの分周比を設定します。

・void pwmWrite (int pin, int value)
指定されたピンのPWMレジスタに値を書き込みます。

Control Hardware PWM frequency – Raspberry Pi
PWMクロックは19.2 MHz です。
pwmSetClock の値で分周されます。
分周された周波数で、PWMカウンタが増加します。


ラズパイ sumobot turn


sumobot turn は、Sumobot が左回転と右回転を繰り返すプログラムです。
sumobot_turn.py と sumobot_turn_check.py の2つがあります。
後者は、前者に、ピンの状態をチェックする処理を追加したものです。

インストール
Github から持ってきて、ラズパイの好きな場所 (例えば /home/pi/sumobot/ ) に置きます。

起動

$ sudo python /home/pi/sumobot/sumobot_turn.py

Sumobot が左回転と右回転を繰り返します。

注意
無線LANでログインして起動してください。
有線LANだと、LANケーブルが絡まります。

自動起動
電源を投入したときに、自動的に起動するようにします。
しかし、常に Sumobot が動き出すと、扱いにくいのです。
sumobot_turn_check.py を使用します。
これは、特定のピン (P13) の状態をチェックして、Sumobot を動かさずに、プログラムを終了する処理を追加したものです。

自動起動するには、/etc/rc.local を変更します。
exit 0 の前に、1行追加します。

$ sudo nano /etc/rc.local
...
# add
python /home/pi/sumobot/sumobot_turn_check.py
exit 0 

ハードの設定
P13(GPIO27) と P17(3.3V) の間に10KΩの抵抗を入れます。
プログラムが自動起動して、Sumobot は動き続けます。
P17(3.3V) に代わりに P14(GND) につなぐと、プログラムは終了して、Sumobot Jr は停止したままです。
20160505_raspi_circuit_p13


ラズパイ Sumobot Jr


20160505_raspi_completion

Arduino に続いて、ラズパイで Sumobot Jr を制御します。

部品
Raspberry Pi 2 B
モバイルバッテリ
・連続回転サーボ SM-S4303R x 2個
16mm ボール
・ネジとナット M2.6x10mm x 12本、M2.6x15mm x 2本
・結索バンド 20cm x 2本
・ゴムバンド #25 3mm幅 x 2本
・線材 少々

加工品
レーザー加工機
・車体 (設計データ) Arduino版と同じです
20160501_sumobot_laser_body

3Dプリンタ
・ボールキャスタ (設計データ) Arduino版と同じです
20160501_sumobot_3d_printer_ball_caster

サーボの動作確認
サーボが所望の動作をするか確認します。
特に、停止を指定したときに、ちゃんと停止しているか。

参考
ラズパイ WiringPi 連続回転サーボ
ラズパイ 連続回転サーボ

車体の組み立て
車体の作り方は、Arduino版 と同じです。
違うのは、上板に Arduino ではなくラズパイを固定すること。
20160505_raspi_upper

配線
20160505_raspi_curuit

(1) オスとメスのジャンパー線を半田付けして、オス2口とメス1口のジャンパー線にします。
20160505_raspi_wiring

(2) モバイルバッテリーを車体に入れます。
モバイルバッテリーの上下に厚紙を入れると、ほどよい感じで固定されます。
20160505_raspi_battery_back

(3) ラズパイと2個のサーボを結線します。ラズパイとモバイルバッテリーを結線します。
20160505_raspi_battery_wire

プログラム
ラズパイにプログラム sumobot_turn を設定します。
電源を入れます。
Sumobot Jr が左回転と右回転を繰り返せば、OKです。

課題
スペーサが3mm厚では足りなかった。
10mmくらい必要です。

(1) 上板にラズパイを固定すると、コネクタの足があたり、基板がしなります。
どうやら、木材のスペーサだと、締め付けると、潰れるようです。
20160505_raspi_problem_1

(2) ラズパイに電源ケーブルを挿す時に、横板が邪魔になり、ケーブルが挿さりません。
応急処置として、横板を切断しました。
20160505_raspi_problem_2_2

YouTube Preview Image

ラズパイ 連続回転サーボ (speed)


20160505_raspi_servo

ラズパイ 連続回転サーボ (duty) に続いて、ラズパイで連続回転サーボを制御します。

ServoSpeed クラス
RPi.GPIO の PWM モードでは、PWMのパルス幅を、デューティ比 で指定します。
デューティ比の範囲は、5.0 から 10.0 です。

これでは使い難いので、速度で指定するクラスを作成しました。
速度の範囲は、−100 から 100 です。
duty のときの確認でわかったように、停止の指定が、計算値よりも少しずれています。
そこで、オフセットを設定して、速度 0 を指定した時に、停止するようにしました。

ソースは、github で公開しています。
rpi_servo_speed.py

確認
試してみたことろ、オフセット=0、速度=0 のときは、微速で回転して、停止しませんでした。
速度 -10 から -26 で、停止しました

オフセットを−18に設定して、速度を -100、-10、0、10、100 と変化させます。
時計周り(高速)、時計周り(低速)、停止、反時計周り(低速)、 反時計周り(高速) となることを確認しました。

課題
停止を指定しても、クリッと音がして、サーボが微動することがあります。
これは、パルスがジッタを持ってるためと思われます。
今回の用途では、割り切って、このままで使用します。


ラズパイ 連続回転サーボ (duty)


Arduino に続いて、ラズパイで連続回転サーボを制御します。

接続
サーボには3本の線があります。
赤を+5v(pin4)、黒をGND(pin6)、白を制御ピン(pin15)に接続します。
20160505_raspi_servo
20160410_raspi_pin

RPi.GPIO の PWM モード
ラズパイには、GPIOを制御するための python ライブラリ RPi.GPIO が用意されています。
さらに、RPi.GPIO には、PWMモード が用意されています。
PWMの周期は周波数で指定します。
周期 20ms なので、 50 Hz です。
PWMのパルス幅は、デューティ比 で指定します。
停止のときのデューティ比は、周期 20ms、パルス幅 1.5ms なので、7.5% です。

servo.oy

import RPi.GPIO as GPIO
PIN = 15
duty = 7.5
GPIO.setmode(GPIO.BOARD)
GPIO.setup(PIN, GPIO.OUT)
servo = GPIO.PWM(PIN, 50)
servo.start(duty)

上記のコードを改版して、dutyの値をキー入力で設定できるようにしたものを、github で公開しています。
rpi_servo_duty.py

duty を 5.0、7.0、7.5、8.0、10.0 と変化させて、
時計周り(高速)、時計周り(低速)、停止、反時計周り(低速)、 反時計周り(高速) となることを確認します。

試してみたことろ、duty=7.5 では微速で回転して、停止しませんでした。
duty=7.2 くらいで、停止しました。

オシロでの測定
オシロで測定したところ。
duty=7.5 では、パルス幅は 1.5ms より少し大きくなり。
duty=7.2 では、パルス幅は 1.5ms になりました。
また、若干の ジッター が見られました。

周期 20ms
20160505_servo_cycle_20ms

duty=7.5
20160505_servo_duty_75

duty=7.2
20160505_servo_duty_72

なお、RPIO.PWM, PWM via DMA for the Raspberry Pi は動かなかった。
This module can only be run on a Raspberry Pi というエラーが出ます。
調べてみると、ラズパイ 2 では対応していないようです。
RPIO issues 53 -SystemError: This module can only be run on a Raspberry Pi!


Sumobot Jr


20160501_sumobot_completion

Sumobot Jr はオープンソースのロボットカーのキットです。

オリジナルから設計データを少し変更しています。
設計データやプログラムなど Github で公開しました。

部品
Arduino Uno
電池ボックス (単三x4本)
・単三電池 x 4本
・連続回転サーボ SM-S4303R x 2個
16mm ボール
・ネジとナット M2.6x10mm x 12本、M2.6x15mm x 2本
・結索バンド 20cm x 2本
・ゴムバンド #25 3mm幅 x 2本
・線材 少々
20160501_sumobot_parts_2

加工品
レーザー加工機
・車体 (設計データ)
20160501_sumobot_laser_body

3Dプリンタ
・ボールキャスタ (設計データ)
20160501_sumobot_3d_printer_ball_caster

サーボの動作確認
サーボが所望の動作をするか確認します。
特に、停止を指定したときに、ちゃんと停止しているか。
参考: Arduino 連続回転サーボ

車体の組み立て
動画が公開されています。
Sumobot Jr Assembly video for Nodebots Day 7/27

(1) ボールキャスタの穴をキリでM2.6のネジが入るように大きくします。
20160501_sumobot_ball_hall_blue

(2) ボールキャスタを底板にネジで固定します。
20160501_sumobot_ball_calter_blue

(3) サーボホーン (サーボの付属品) の穴をキリでM2.6のネジが入るように大きくします。
20160501_sumobot_servo_horn_holl

(4) サーボホーンを車輪にネジで固定します。
20160501_sumobot_servo_horn

(5) サーボを底板に結索バンドで固定します。
20160501_sumobot_servo_mount_2

(6) Arduino を上板にスペーサーをかましてネジで固定します。
20160501_sumobot_srduino_parts20160501_sumobot_arduino

(7) 上板を車体に取り付けます。
20160501_sumobot_upper

(8) 車輪を車体に木ネジ (サーボの付属品) で取り付けます。
20160501_sumobot_wheel_2

(9) 前板を車体に取り付けます。
20160501_sumobot_front_2

(10) ボールをボールキャスタにはめ込みます。
20160501_sumobot_ball_mount_blue

配線
20160501_sumobot_circuit

(11) 電池ボックスにメスのジャンパー線を半田付けします。
(12) オスのジャンパー線を半田付けして、4つ口にします。
20160501_sumobot_soldering

(13) Arduinoと電池ボックスと2個のサーボを結線します。
20160501_sumobot_wiring

(14) 電池ボックスを車体に入れます。
電池ボックスの上下に厚紙を入れると、ほどよい感じで固定されます。
20160501_sumobot_battery

(15) 完成です。
20160501_sumobot_completion

プログラム
Arduino にスケッチ sumobot_turn を書き込みます。
電源を入れます。
Sumobot Jr が左回転と右回転を繰り返せば、OKです。

課題
ゴムバンドがすぐに車輪から外れる。
20160501_sumobot_wheel_and_rubber

YouTube Preview Image

Arduino Uno : Servo と AltSoftSerial は同時に使用できない


Arduino Uno で Servo クラスと AltSoftSerial クラスを同時に使用すると、コンパイル・エラーになります。

multiple definition of `__vector_11'

どちらのクラスも16ビットタイマーを必要としていて、そのための割込みが衝突しています。
Arduino Uno のハード仕様による制約で、回避する方法はありません。

対策として、Arduino Mega などハード仕様を満たすものを使う方法もありますが。
ひとまず、SoftSerial クラスを使って凌ぎました。

参考
AltSoftSerial and Servo libraries fails to compile


Arduino 連続回転サーボ


20160425_arduino_servo

一般的なサーボ は、180度くらいの可変範囲を持っています。
連続回転サーボ (Continuous Rotation Servo) は、360度以上の可変範囲を持ち、連続して回転することができます。
モータの代わりに使用することができます。

今回は、SpringRC SM-S4303R を使用しました。
国内では扱っているところがなかったので、米国の Pololu から購入しました。

制御信号
制御信号は、周期的なパルスで、周期 20ms、パルス幅 1.0ms – 2.0ms です。
パルス幅 1.5ms で停止、1.0 – 1.5ms で時計周り、1.5 – 2.0ms で反時計周りです。
停止の 1.5ms から離れるに従い回転数が増えます。
20160425_servo_control_2

Arduino で制御する
サーボには3本の線があります。
赤を+5v、黒をGND、白を制御ピンに接続します。

(1) digitalWrite
制御信号を digitalWrite で生成します。
width を 1000、1400、1500、1600、2000 と変化させて、
時計周り(高速)、時計周り(低速)、停止、反時計周り(低速)、 反時計周り(高速) となることを確認します。

servo-digitalwrite.ino

 
int PIN = 13;
int width = 1500;
void setup() {
 	pinMode(PIN, OUTPUT);
}
void loop() {
	digitalWrite(PIN, HIGH);
	delayMicroseconds(width);
	digitalWrite(PIN, LOW);
	delayMicroseconds(3000 - width);
	delay(17); // wait 17 ms
}

(2) Servo クラス
Arduino には、サーボ制御のためのクラス Servo が用意されています。ハードウェア・タイマーを利用しています。
Servo#write で、回転のスピードを設定します。0にするとフルスピードで回転し、180にすると、反対方向にフルスピードで回転します。90のときは停止します。

speed を 0、80、90、100、180 と変化させて、
時計周り(高速)、時計周り(低速)、停止、反時計周り(低速)、 反時計周り(高速) となることを確認します。

servo-test.ino

 
#include <Servo.h>
Servo myservo;
int PIN = 13;
int speed = 90;
void setup() { 
	myservo.attach(PIN);
	myservo.write(speed);
} 
void loop() {}

(3) コマンド
パラメータを変えるたびに、プログラムを書き換えるのは面倒です。
シリアルモニタからコマンドを送って、変更できるようにしました。
servo_command.ino

コマンドの形式は、s + 3桁の数字です。

s000 : 時計周り 高速
s090 : 停止
s180 : 反時計周り 高速

参考
Pololu SM-S4303R
SM 33R/43R/81R Datasheet
Servo#write : Arduino日本語リファレンス