2017年11月18日、19日に実施された「東北Tech道場 郡山道場 第8回」の作業内容の続きをまとめます。
LチカのプログラムをCatFansに移植したので、今度はこれを使って扇風機のファンを回します。それからができたら、サーボモータを回す処理を追加します。
#1. 扇風機のファンを回す
前回のプログラムのピン名を
String pinName = "BCM6";
から
String pinName = "BCM23";
に変更するだけで、扇風機のファンが回ります。また、メソッド名を次のように変え、コメントも書き換えました。
BlinkRunnable → turnFan
こんな感じでファンが回っています。ちなみに写真の猫は我が家のライトです。(^^)
#2. サーボを回す
サーボモータを動かしてみます。Lチカのサンプルプログラムにはサーボモータを動かすプログラム(PWM sample)も入っているので、今回はそれを使うことにしました。扇風機のファンとは逆で、猫がいなければサーボを回し、猫がいたらサーボを止めます。
##(1) Lチカのプログラムの移植
###(i) mChangePWMRunnableメソッドとPWMメソッドの追加
「Simple PIO」のcom.example.androidthings.simplepioの中のonCreateメソッドとmChangePWMRunnableメソッドを参考に次のようなメソッドを追加する。
private Pwm mPwm;
private boolean mIsPulseIncreasing = true;
private double mActivePulseDuration;
// Parameters of the servo PWM
private static final double MIN_ACTIVE_PULSE_DURATION_MS = 0.8;
private static final double MAX_ACTIVE_PULSE_DURATION_MS = 2.3;
private static final double PULSE_PERIOD_MS = 20; // Frequency of 50Hz (1000/20)
// Parameters for the servo movement over time
private static final double PULSE_CHANGE_PER_STEP_MS = 0.08;
:
:
//サーボモータの処理
private void mChangePWMRunnable(boolean onoff){
// Exit Runnable if the port is already closed
if (mPwm == null) {
Log.w(TAG, "Stopping runnable since mPwm is null");
return;
}
// Change the duration of the active PWM pulse, but keep it between the minimum and
// maximum limits.
// The direction of the change depends on the mIsPulseIncreasing variable, so the pulse
// will bounce from MIN to MAX.
if (mIsPulseIncreasing) {
mActivePulseDuration += PULSE_CHANGE_PER_STEP_MS;
} else {
mActivePulseDuration -= PULSE_CHANGE_PER_STEP_MS;
}
// Bounce mActivePulseDuration back from the limits
if (mActivePulseDuration > MAX_ACTIVE_PULSE_DURATION_MS) {
mActivePulseDuration = MAX_ACTIVE_PULSE_DURATION_MS;
mIsPulseIncreasing = !mIsPulseIncreasing;
} else if (mActivePulseDuration < MIN_ACTIVE_PULSE_DURATION_MS) {
mActivePulseDuration = MIN_ACTIVE_PULSE_DURATION_MS;
mIsPulseIncreasing = !mIsPulseIncreasing;
}
Log.d(TAG, "Changing PWM active pulse duration to " + mActivePulseDuration + " ms");
try {
// Duty cycle is the percentage of active (on) pulse over the total duration of the
// PWM pulse
if(onoff){
mPwm.setPwmDutyCycle(100 * mActivePulseDuration / PULSE_PERIOD_MS);
}
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
}
}
private void PWM(){
//サーボモータの処理
PeripheralManagerService service = new PeripheralManagerService();
try {
String pinName = "PWM0";
mActivePulseDuration = MIN_ACTIVE_PULSE_DURATION_MS;
mPwm = service.openPwm(pinName);
// Always set frequency and initial duty cycle before enabling PWM
mPwm.setPwmFrequencyHz(1000 / PULSE_PERIOD_MS);
mPwm.setEnabled(true);
// Post a Runnable that continuously change PWM pulse width, effectively changing the
// servo position
Log.d(TAG, "Start changing PWM pulse");
mChangePWMRunnable(false);
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
}
}
Lチカと同じようにピンは固定にするので、
String pinName = "PWM0";
とする。
ラズパイのピン名は基本BCM~になるが、サーボモータのみPWM0、PWM1となる。また、サーボモータはパルス幅で回転する位置が決まり、パルス幅はパルス波の周期とデューティー比で求まる。
###(ii) onCreateメソッドの修正
OnCreateメソッドの最後に
PWM();
を追加。
###(iii) onDestroyメソッドの修正
onDestroyメソッドを次のように修正。
protected void onDestroy() {
:
:
//サーボ
// Remove pending Runnable from the handler.
mChangePWMRunnable(false);
// Close the PWM port.
Log.i(TAG, "Closing port");
try {
mPwm.close();
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
} finally {
mPwm = null;
}
}
###(iv) onPictureTakenの修正
onPictureTakenメソッドを次のように修正する。
private void onPictureTaken(final byte[] imageBytes) {
:
:
if (annotations != null) {
//猫画像なら
if (annotations.containsKey("cat") == true) {
if (annotations.get("cat") >= 0.8F) {
// イメージをfirebaseにアップロードする
log.child("timestamp").setValue(ServerValue.TIMESTAMP);
log.child("image").setValue(imageStr);
log.child("annotations").setValue(annotations);
mChangePWMRunnable(false);
turnFan(true);
Log.d(TAG, "Turn the fan");
} else {
mChangePWMRunnable(true);
turnFan(false);
Log.d(TAG, "Stop the fan");
}
}
else {
mChangePWMRunnable(true);
turnFan(false);
Log.d(TAG, "Stop the fan");
}
}
} catch (IOException e) {
Log.e(TAG, "Cloud Vison API error: ", e);
}
}
});
}
}
###(v) 実行確認
以下のように扇風機のファンの下につけたサーボが、猫がいなければ回り、猫がいたら止まる。
第8回はまだ続きます。