Android ThingsとA/D変換(MCP3008)


今日はAndroid Things on Raspberry PIでA/D変換をします。
Raspberry Piにはアナログ入力がないので、アナログ入力が必要な場合はA/Dコンバーターが必要です。
手元にあるA/Dコンバーターが[MCP3008](http://akizukidenshi.com/catalog/g/gI-09485/)しか無いので、MCP3008を使ってやります。

## ハードウェア

以下の構成です。
可変抵抗から読み取った値を使ってサーボを動かします。

![potentionmeter.png](https://qiita-image-store.s3.amazonaws.com/0/2965/822f385d-656a-f4e2-6c91-849d7e6ec44d.png "potentionmeter.png")


可変抵抗から読み取ったアナログ値をMCP3008を使ってA/D変換します。

## コード

MCP3008の公式Peripheral Driver Libraryは現在ありません。
個人で作った方がいるようです。
https://github.com/PaulTR/AndroidThingsMCP3008ADC

ただ、maven repositoryには登録してない臭いので、コピペして使います。
サーボについては、Peripheral Driver LibraryにあるPwmServoを利用します。

今回のコードは以下においてあります。
https://github.com/soundTricker/analog-digital-convert

### メインどころ

複雑なところはあんまりないですね
センサーからデータを読み取ることろは、Handlerを使って、キューに積んで処理しています。

またmap関数は読み取り値→角度の変換処理を主に行ってます。



```kotlin:MainActivity.kt

package com.github.soundtricker.androidthings.analogdigitalconvert

import android.app.Activity
import android.os.Bundle
import android.os.Handler
import android.util.Log
import com.google.android.things.contrib.driver.pwmservo.Servo
import java.io.IOException


class MainActivity : Activity() {


    companion object {
        private val TAG = MainActivity::class.java.simpleName

        private val PIN_CS = "BCM25"
        private val PIN_CLOCK = "BCM17"
        private val PIN_MOS_IN = "BCM24"
        private val PIN_MOS_OUT = "BCM23"
        private val PIN_SERVO = "PWM1"

        private val CHANNEL_POTENTIONMETER = 0x0
        private val MIN_VOL = 0
        private val MAX_VOL = 410
        private val MIN_ANGLE = 0
        private val MAX_ANGLE = 180

    }

    private lateinit var mcp3008: MCP3008
    private lateinit var mcpHandler: Handler

    private lateinit var servo: Servo

    private val readChannelMoveServo = Runnable {
        readAndMoveServo(CHANNEL_POTENTIONMETER)
    }

    private fun readAndMoveServo(readChannel: Int) {
        val vol = this.mcp3008.readAdc(readChannel)
        Log.i(TAG, "ADC $readChannel: $vol")

        val angle = map(vol, MIN_VOL, MAX_VOL, MIN_ANGLE, MAX_ANGLE)
        val prevAngle = this.servo.angle

        if (Math.abs(prevAngle - angle) <= 3) {
            return
        }
        Log.i(TAG, "ANGLE $readChannel: $angle")
        this.servo.angle = angle
        runReadChannel()
    }


    private fun runReadChannel() {
        this.mcpHandler.postDelayed(this.readChannelMoveServo, 10L)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        try {
            this.servo = Servo(PIN_SERVO)
            this.servo.setPulseDurationRange(0.6, 2.35)
        } catch (e: IOException) {
            Log.e(TAG, "servo can't initialized", e)
            return
        }
        this.mcp3008 = MCP3008(PIN_CS, PIN_CLOCK, PIN_MOS_IN, PIN_MOS_OUT)
        try {
            this.mcp3008.register()

        } catch (e: IOException) {
            Log.e(TAG, "mcp can't initialized", e)
            return
        }
        mcpHandler = Handler()
        mcpHandler.post(this.readChannelMoveServo)


    }

    override fun onDestroy() {
        super.onDestroy()
        this.mcp3008.unregister()
        this.servo.close()
    }

    private fun map(x: Int, inMin: Int, inMax: Int, outMin: Int, outMax: Int): Double {
        return ((x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin).toDouble()
    }


}
```


## まとめ

やはりAndroid Thingsだと公式にはライブラリが出てないので、めんどくさいのですが、
よく使われているものはちょこちょこライブラリを作ってくれている人もいるので、探してみるといいと思います。

## 参考

https://github.com/amitshekhariitbhu/awesome-android-things