Raspberrypi3
AndroidThings

AndroidThings & Raspberry Pi3 で猫用扇風機を作る(6)

More than 1 year has passed since last update.

2017年11月18日、19日に実施された「東北Tech道場 郡山道場 第8回」の作業内容の続きをまとめます。

LチカのプログラムをCatFansに移植したので、今度はこれを使って扇風機のファンを回します。それからができたら、サーボモータを回す処理を追加します。

1. 扇風機のファンを回す

前回のプログラムのピン名を
String pinName = "BCM6";
から
String pinName = "BCM23";
に変更するだけで、扇風機のファンが回ります。また、メソッド名を次のように変え、コメントも書き換えました。

BlinkRunnable → turnFan

こんな感じでファンが回っています。ちなみに写真の猫は我が家のライトです。(^^)
30.jpg

2. サーボを回す

サーボモータを動かしてみます。Lチカのサンプルプログラムにはサーボモータを動かすプログラム(PWM sample)も入っているので、今回はそれを使うことにしました。扇風機のファンとは逆で、猫がいなければサーボを回し、猫がいたらサーボを止めます。

(1) Lチカのプログラムの移植

(i) mChangePWMRunnableメソッドとPWMメソッドの追加

「Simple PIO」のcom.example.androidthings.simplepioの中のonCreateメソッドとmChangePWMRunnableメソッドを参考に次のようなメソッドを追加する。

CatFansActivity.java
    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メソッドを次のように修正。

CatFansActivity.java
    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メソッドを次のように修正する。

CatFansActivity.java
    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) 実行確認

以下のように扇風機のファンの下につけたサーボが、猫がいなければ回り、猫がいたら止まる。

31.jpg

第8回はまだ続きます。