フリーランスの暇な時に書く技術メモ
Genki Tech

ラズパイのNodeでポテンショメータを読み取る(B10K+ADS7830)

前回の記事では、ラズパイを Web から制御して L チカするところまで出来ました。

折角Linuxが動くのでpythonではなく慣れてるnode.jsでLチカしてみます。Next.jsで軽くサーバーを立てて、Web画面からLEDの切り替えをできるようにするところをゴールとします。 VSCodeでRaspberry PiにSSH接続してる状態で以下のように環境構…

今回はポテンショメーター(可変抵抗器)の値を入力して画面に表示するところまで実装したいです。前回の Next.js の Web サイトをベースに追記していくため必要であればそちらもご覧ください。

ハードウェアの実装

B10K と言うポテンショメーターを使用します。

image-20211003145223274

可変抵抗器の値はアナログなので、デジタルに変換して取得する必要があり、今回は ADS7830 という AD コンバータを使用します。

image-20211003145104067

配線は以下の様に行いました。配線図は面倒なので省略。電圧のアナログ値 0 ~ 3.3V を 0 ~ 255 の 8bit で取るために I2C と言うシリアル通信をするため、ラズパイの SDA と SCL をそれぞれ AD コンバータの SDA と SCL に接続し、3.3V 電源も接続。

ポテンショメータは真ん中を AD コンバータの A0 につないで、左は GND、右は 3.3V に接続。

image-20211003160715237

API の実装

ラズパイ側は I2C と言うシリアル通信をする必要があるため、以下のコマンドでラズパイ自体の I2C を有効にします。

sudo apt-get update
sudo apt-get install i2c-tools
sudo raspi-config

3 Interface Options → P5 I2C と選択し、Yes で有効化します。(有効にするには再起動が必要かも)

image-20211003150306055

I2C は複数の IC などを並列に接続して使用できるように、機器ごとに決まっているアドレスを使用して情報をやり取りします。

接続状態を確認するには以下のコマンドを実行します。

その後以下のコマンドを叩くと、AD コンバータのアドレスを確認できます。この場合は「4b」がアドレスです。

i2cdetect -y 1

image-20211003161506642

node.js で I2C を制御するためのライブラリをインストールします。

npm i -S i2c-bus
npm i -D @types/i2c-bus

新しく meter.ts ファイルを api として作成し、以下のコードを記述します。

import type { NextApiRequest, NextApiResponse } from 'next';
import i2c from 'i2c-bus';

const DEVICE_NUMBER = 1;
const TARGET_IC_ADDR = 0x4b;
const TARGET_IC_PORTS = [0x84, 0xc4, 0x94, 0xd4, 0xa4, 0xe4, 0xb4, 0xf4]; // A0~A7

// デバイスオープン
const meterDevice = i2c.openSync(DEVICE_NUMBER);

const readMeter = (num: number) => {
  // 読み取りポート指定
  var writeBuf = Buffer.from([TARGET_IC_PORTS[num]]);
  meterDevice.i2cWriteSync(TARGET_IC_ADDR, writeBuf.length, writeBuf);
  // 読み取り実行
  var readBuf = Buffer.alloc(0x01);
  meterDevice.i2cReadSync(TARGET_IC_ADDR, readBuf.length, readBuf);
  return readBuf[0];
};

export default function handler(req: NextApiRequest, res: NextApiResponse<{ value: number }>) {
  const value = readMeter(0);
  res.status(200).json({ value: value });
}

大切なのは readMeter 関数で、ここで ADS7830 の仕様にそって取得したいポートを送信し、その後データを取得しています。

API を実行すると「{“value”:234}」の様に値の JSON が取得できれば OK です。

UI の実装

ダイヤルを回すと画面にリアルタイムに反映させたいので、とりあえず非効率ですが UI から API を叩きまくります。

index.tsx を以下のように変更します。

import axios from 'axios';
import type { NextPage } from 'next';
import Head from 'next/head';
import { useEffect, useState } from 'react';
import styles from '../styles/Home.module.css';

const Home: NextPage = () => {
  const [meterValue, setMeterValue] = useState(0);

  useEffect(() => {
    const interval = setInterval(async () => {
      // APIからメーター情報取得
      const value = (await axios.get<{ value: number }>('/api/meter')).data.value;
      setMeterValue(value);
    }, 100); // 1秒に10回実行
    return () => clearInterval(interval);
  }, []);

  return (
    <div className={styles.container}>
      <Head>
        <title>Raspberry Pi Controller</title>
        <meta name="description" content="Raspberry Pi Controll App" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <div>{meterValue}</div>
      </main>
    </div>
  );
};

export default Home;

テスト

こんな感じでほぼリアルタイムにダイヤル読み取りができるようになりました。(ダイヤルが 2 つあるのは気にしないでください)

次回はこの入力値を元に DC モーターを PWM 制御してみたいと思います。