Help us understand the problem. What is going on with this article?

Android ThingsでPeripheral Driver Libraryを使って、サーボを動かす

More than 1 year has passed since last update.

せっかくなので短めの内容で、Advent Calendarを埋めていきたいと思います。
今回はAndroid ThingsでPeripheral Driver Libraryを使って、サーボを動かしてみます。

Peripheral Driver Library

Peripheral Driver Libraryは一般的によく使われるセンサーや、電子部品を、
アプリケーションで使いやすくするためのライブラリ群です。

Peripheral Driver Libraryは
サーボなどのよく使う電子部品を扱いやすいようにラップしたものと、
GPS、Button等をAndroid Frameworkに組み込んで利用するUser Driverが含まれています。

通常、一部のセンサーは、センサーメーカーが、アプリケーションから扱いやすいようにライブラリなどを提供しています。
ただ現状ではメーカーがAndroidThings向けにこういったライブラリを提供していることはなく、
このPeripheral Driver Libraryから探すか、自分で作るかしかありません。

現状Peripheral Driver Libraryはgithubにまとまっています。自分でライブラリを作ったり、
User-Driverを作る場合は参考にしてみてください。

https://github.com/androidthings/contrib-drivers

pwmservoを利用してサーボを動かす

とりあえずコードは以下にあります。
https://github.com/soundTricker/SampleServo

配線

以下の感じです。

servo.png

build.gradle

Servoを扱うためには、com.google.android.things.contrib:driver-pwmservoを利用します。
以下のようにbuild.gradleで指定します。

build.gradle
implementation 'com.google.android.things.contrib:driver-pwmservo:0.3'

AndroidManifest.xml

特に追加のPermissionはありません。
AndroidThings用にuses-libraryとintent-filterを追加します。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.github.soundtricker.androidthings.sampleservo">

    <application>
        <uses-library android:name="com.google.android.things" />

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.IOT_LAUNCHER" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>

MainActivity#onCreate

onCreateでServoクラスを初期化します。setAngleRangeで最大最小の角度を設定。
setPulseDurationRangeでpwmの周波数の最大値と最小値を設定します。
周波数の最大値、最小値はサーボごとで異なるので、datasheetを御覧ください。
安いところで買うとついてない時もありますが....

またUI Threadを邪魔しないようにHandlerThreadを使います。UIがないならHandlerだけでもいいです。多分。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        try {
            mServo = Servo(PIN_PWM)
            mServo!!.setAngleRange(0.0, 180.0)
            mServo!!.setPulseDurationRange(MIN_PULSE_MS, MAX_PULSE_MS)
            mServo!!.setEnabled(true)
        } catch (e: Exception) {
            Log.e(TAG, "Error creating Servo", e)
            return
        }
        mHandlerThread = HandlerThread("servo")
        mHandlerThread.start()
        mHandler = Handler(mHandlerThread.looper)
        currentAngle.text = "0.0"
        angleText.setText("0.0")
        speedText.setText("5.0")
        setAngle(0.0)
    }

MainActivity#setAngle

角度の設定を行います。
通常PWMサーボだと速度が設定できないので適当な角度ごとにインクリメントして、スピード調整をします。
mServo!!.angle = targetAngleだけでサーボを動かせるので楽ですね。
もしServoライブラリを使っていない場合は自分でDutyの計算をする必要があります。

private fun setAngle(angle: Double) {
        mAngle = angle
        mHandler.post(mRunnable)
    }


    private val mRunnable = Runnable {
        if (mServo == null) {
            return@Runnable
        }
        try {
            while (mAngle != mServo!!.angle) {

                var targetAngle: Double
                if (mAngle > mServo!!.angle) {
                    targetAngle = mServo!!.angle + mSpeed
                    targetAngle = Math.min(targetAngle, mAngle)
                } else {
                    targetAngle = mServo!!.angle - mSpeed
                    targetAngle = Math.max(targetAngle, mAngle)
                }

                targetAngle = Math.min(targetAngle, mServo!!.maximumAngle)
                targetAngle = Math.max(targetAngle, mServo!!.minimumAngle)

                mServo!!.angle = targetAngle
                runOnUiThread {
                    currentAngle.text = targetAngle.toString()
                }
                Thread.sleep(1)
            }
        } catch (e: IOException) {
            Log.e(TAG, "Error setting Servo angle")
        }

    }

まとめ

とりあえず今回はサーボを動かしてみました。
まだまだPeripheral Driver Libraryは数が少ないのです。自分が使おうとしているセンサーのライブラリがないことが多々あるので、Peripheral Driver Libraryの実装を参考にしながら作ってみるといいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした