この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
CX事業本部の平内(SIN)です。
AWS IoTでエッジデバイスから温度センサーなどデータを処理している時、デバック用にそれらしいデータが欲しくなる場面があります。
ダミーのデータを生成する要領は、色々あると思いますが、今回は、ボリュームを回す感覚で、それらしいデータが生成できるジェネレーターを作ってみました。(冬休みの自由研究的な)
最初に利用している様子です。
ジェネレーターで生成したデータを逐次MQTTで送信しています。
本記事は、MQTTの送信には触れておりません、単にデータを生成するデバイスの工作に関するものです。それでも良いって方は、読み進めて頂ければ嬉しいです。
2 構成
構成は、図のとおりです。
データの生成は、可変抵抗で行っています。RaspberryPIには、アナログポートが無いため、ADS1115でAD変換を行っています。
生成されたデータを表示しているのは、4桁の7セグメントLEDとNeopixelのLEDです。
ADS1115と7セグメントLEDは、I2Cバスで接続されています。
NeoPixelのLEDは、内部のICで制御されており、専用のコントローラー(ライブラリー使用)が、RaspberryPIで動作しています。
3 RaspberryPI
使用したRaspberryPIは、以下のとおりです。
ハード
3 Model B
$ cat /proc/cpuinfo | grep Revision
Revision : a32082
OSイメージ
OSイメージは、Raspbian Buster with desktop and recommended softwareの2019.9.24です。
uname -a
Linux raspberrypi 4.19.75-v7+ #1270 SMP Tue Sep 24 18:45:11 BST 2019 armv7l GNU/Linux
$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 10 (buster)
Release: 10
Codename: buster
4 AD変換
AD変換は、ADS1115 16Bit ADC 4チャンネル I2Cのユニットを使用しています。
https://www.amazon.co.jp/gp/product/B07TZ56M65/
接続は、以下のとおりです。ADS1115は、電源とI2Cバスで接続され、アナログポート(A0)でボリュームで変化する電圧を取得しています。下記の構成では、電圧は、2.5〜4.0の間で変化するので、Node.jsのプログラムで、解像度1000で数値化しています。
ADS1115のI2Cバス上のアドレスは、デフォルトで0x48です。
$ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
下記は、取得したデータを数値化しているコードです。
"use strict";
const I2C = require('raspi-i2c').I2C;
const ADS1x15 = require('raspi-kit-ads1x15');
class ADConv{
constructor(i2c){
this.adc = new ADS1x15({
i2c,
chip: ADS1x15.chips.IC_ADS1015,
address: ADS1x15.address.ADDRESS_0x48,
pga: ADS1x15.pga.PGA_4_096V,
sps: ADS1x15.spsADS1015.SPS_250
});
this.channel = ADS1x15.channel.CHANNEL_0;
this.min = 1270; // 最低値
this.max = 2027; // 最高値
this.range = this.max - this.min;
}
async read(){
return new Promise((resolve,reject)=> {
this.adc.readChannel(this.channel, (err, value, volts) => {
if (err) {
console.error('Failed to fetch value from ADC', err);
reject(err);
} else {
let val = value - this.min;
val = val / this.range * 100;
if(val < 0){
val = 0;
}
if(100 <= val){
val = 100;
}
resolve(Math.round(val * 10) / 10); // 小数第一位を基準
}
})
});
}
}
async function main() {
const i2c = new I2C();
const adconv = new ADConv(i2c);
while(true){
const value = await adconv.read();
console.log(value);
await sleep(100);
}
}
main();
データの生成をテストしている様子です。
5 4桁7セグメントLED
数値の表示は、4桁7セグメントLEDディスプレイモジュール HT16K33を使用しています。
https://www.amazon.co.jp/gp/product/B07QVGTVDV/
接続は、電源とI2Cバスで接続されています。
各桁は、メモリ上のワード配列と一致しています。
また、各セグメントは、下記のビットに対応しています。7セグメント(ドットを入れると8セグメント)なので、8ビットで表現できるため、ワードの上位バイトは関係ないことになります。
下記は、1,2,3を表示する場合のビット例です。
HT16K33のI2Cバス上のアドレスは、0x70です。
$ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- -- -- -- -- -- --
そして、数字を表示しているコードの例です。
class SevenSegLED {
constructor(i2c){
this.i2c = i2c;
this.number = [0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f];
this.HT16K33 = 0x70;
this.buffer = new Buffer.alloc(0x20);
// initiaruize
this.i2c.writeByteSync(this.HT16K33, (0x20 | 0x01), 1);
this.i2c.writeByteSync(this.HT16K33, (0x80 | 0b00000001), 1);
}
disp(n){
let str = n.toFixed(1);
str = ('000' + str).slice(-5);
// .1桁
this.buffer[9] = this.number[Number(str[str.length-1])];
// 0桁
this.buffer[7] = this.number[Number(str[str.length-3])];
this.buffer[7] |= 0x80; // 小数点
// 10桁
this.buffer[3] = this.number[Number(str[str.length-4])];
// 100桁
this.buffer[1] = this.number[Number(str[str.length-5])];
// 0パディングは表示しない
if(this.buffer[1] == 0x3f){
this.buffer[1] = 0;
if(this.buffer[3] == 0x3f){
this.buffer[3] = 0;
}
}
for(var i=0;i<10;i++){
this.i2c.writeByteSync(this.HT16K33, i, this.buffer[i+1]);
}
}
}
async function main() {
const sevenSegLED = new SevenSegLED(i2c);
let value = 0;
while(true){
console.log(value);
sevenSegLED.disp(value);
value += 0.1;
await sleep(10);
}
}
main();
テストしている様子です。
6 WS2812B neopixel PCB 8連
レベルメーターのように使用しているLEDは、フルカラーが表現できるneopixelのWS2812Bです。
https://www.amazon.co.jp/waves-WS2812B-neopixel-PCB-8%E9%80%A3/dp/B07G45H23Y/
本体内の各LEDがICで制御されているため、接続は、電源以外に1線だけで終わりです。
そして、制御しているコードは、以下のようになっています。
var ws281x = require('rpi-ws281x-v2');
class Pixels {
constructor(){
const config = {
leds: 8,
//dma: 10, // Use DMA
brightness: 100,//255, // 0-255
gpio: 18,// BMC18(12pin)
strip: 'rgb' // "rgb", "rbg", "grb", "gbr", "bgr", "brg".
};
ws281x.configure(config);
this.pixels = new Uint32Array(config.leds);
}
// dat=0..100
show(dat){
const n = dat * 0.08
for(var i=0; i < 8; i++) {
if(i < n){
if (i < 4) {
this.pixels[i] = 0xFF0000; // GREEN
} else if(i < 6) {
this.pixels[i] = 0xFFFF00; // YELLOW
} else if(i < 7) {
this.pixels[i] = 0x88FF00; // ORANGE
} else {
this.pixels[i] = 0x00FF00; // RED
}
} else {
this.pixels[i] = 0x000000;
}
}
ws281x.render(this.pixels);
}
}
async function main() {
const pixels = new Pixels();
let value = 0;
while(true){
console.log(value);
pixels.show(value);
value += 0.1;
await sleep(10);
}
}
main();
表示をテストしている様子です。
7 接続テスト
全部繋いでテストしています。
そして、ユニバーサル基盤に載せたところです。
8 最後に
これで、AWS IoTのデバッグが捗れば(楽しくなれば)本望です。
すべてのコードは、下記に置きました。
https://github.com/furuya02/generator.git