せっかくなので短めの内容で、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を作る場合は参考にしてみてください。
pwmservoを利用してサーボを動かす
とりあえずコードは以下にあります。
https://github.com/soundTricker/SampleServo
配線
以下の感じです。
build.gradle
Servoを扱うためには、com.google.android.things.contrib:driver-pwmservo
を利用します。
以下のように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の実装を参考にしながら作ってみるといいと思います。