ATOM MatrixのセンサとIOで、ATOM Matrixの背面のピンを調べましたが、アナログ系のI/Oはピンが固定されるものの通信系のペリフェラル機能は好きなポートに割り当てられることがわかりました。
Wio LTEに複数のI2CなGroveモジュールを繋げるの記事で作った紫外線センサ VEML6070と気温、湿度、気圧、空気の汚染度が計測できるセンサ BME680、それとGroveのCo2センサーを繋げてI2CとUARTを確認してみます。
センサとの接続
もともとATOM MatrixにはGrove互換ポートがありますが電源が5Vのため、3.3V動作のセンサは直接繋げられません。
裏のポートからブレッドボード経由で繋げても良かったのですが、専用に基板を作りました。
専用基板経由で、センサを繋げます。
BME680(I2C)の確認
まずはI2C接続のBME680だけで動作を確認してみます。BME680はストロベリーリナックスで販売されているモジュールを使用していますが、現在はseeedからもGroveのモジュールが販売されています。
使い方はどちらも同じだと思います。
プログラム
Adafruitのライブラリがありましたので、それを使用しました。BME680
で検索すれば出てきますので、インストールします。これだけでは足らなかったので、Adafruit_SensorもZipでダウンロードしてインストールします。
プログラムはほぼサンプルのままです。Wireはデフォルトのポートと異なるので、そこだけ接続しているポートに変更しています。
#include <Wire.h>
#include "Adafruit_BME680.h"
Adafruit_BME680 bme;
void setup() {
Serial.begin(115200);
Wire.begin(23,22);
bme.begin();
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
void loop() {
if (! bme.performReading()) {
Serial.println("Failed to perform reading :(");
return;
}
Serial.print("Temperature = ");
Serial.print(bme.temperature);
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bme.pressure / 100.0);
Serial.println(" hPa");
Serial.print("Humidity = ");
Serial.print(bme.humidity);
Serial.println(" %");
Serial.print("Gas = ");
Serial.print(bme.gas_resistance / 1000.0);
Serial.println(" KOhms");
Serial.println();
delay(2000);
}
結果
シリアルモニタにセンサから取得された値が出力されました。
Temperature = 23.30 *C
Pressure = 994.49 hPa
Humidity = 50.67 %
Gas = 354.47 KOhms
#Co2センサ(UART)の確認
次にUART接続のCo2センサーを確認してみます。このセンサは電源が5VでもOKなので直接繋げられますが、専用基板にも5VのGrove互換ポートを用意しているので、そちらに繋げました。
プログラム
こちらも主にサンプルのままですが、UART部分を変更しています。このセンサは温度も取得できます。
#include <HardwareSerial.h>
HardwareSerial Co2SensorSerial(1);
const unsigned char cmd_get_sensor[] =
{
0xff, 0x01, 0x86, 0x00, 0x00,
0x00, 0x00, 0x00, 0x79
};
unsigned char dataRevice[9];
int temperature;
int CO2PPM;
void setup() {
Serial.begin(115200);
Co2SensorBegin();
};
void loop() {
if(dataRecieve())
{
Serial.printf("Temperature=%d\n",temperature);
Serial.printf("Co2=%d\n",CO2PPM);
}
delay(1000);
};
void Co2SensorBegin()
{
Co2SensorSerial.begin(9600,SERIAL_8N1,25,21);
}
bool dataRecieve(void)
{
byte data[9];
int i = 0;
//transmit command data
for(i=0; i<sizeof(cmd_get_sensor); i++)
{
Co2SensorSerial.write(cmd_get_sensor[i]);
}
delay(10);
//begin reveiceing data
if(Co2SensorSerial.available())
{
while(Co2SensorSerial.available())
{
for(int i=0;i<9; i++)
{
data[i] = Co2SensorSerial.read();
}
}
}
if((i != 9) || (1 + (0xFF ^ (byte)(data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7]))) != data[8])
{
return false;
}
CO2PPM = (int)data[2] * 256 + (int)data[3];
temperature = (int)data[4] - 40;
return true;
}
結果
シリアルモニタにセンサから取得された値が出力されました。
Temperature=27
Co2=1114
Temperature=27
Co2=1110
Temperature=27
Co2=1104
Temperature=27
センサ値をAmbientにアップロード
すべてのセンサを組み合わせてAmbientにアップロードし、グラフ化してみます。
プログラム
Ambientについては、ATOM MatrixをAmbientに繋ぐを参考にしてください。
#include <HardwareSerial.h>
#include <Wire.h>
#include "Adafruit_BME680.h"
#include "Adafruit_VEML6070.h"
#include "Ambient.h"
#include <WiFi.h>
Adafruit_BME680 bme;
Adafruit_VEML6070 uv;
HardwareSerial Co2SensorSerial(1);
WiFiClient client;
Ambient ambient;
const unsigned char cmd_get_sensor[] =
{
0xff, 0x01, 0x86, 0x00, 0x00,
0x00, 0x00, 0x00, 0x79
};
unsigned char dataRevice[9];
int temperature;
int CO2PPM;
// Wi-FiのSSID
const char* ssid = "ssid";
// Wi-Fiのパスワード
const char* password = "pass";
// AmbientのチャネルID
unsigned int channelId = 100;
// Ambientのライトキー
const char* writeKey = "write key";
void setup() {
Serial.begin(115200);
// Wi-Fi APに接続
WiFi.begin(ssid, password);
// Wi-Fi AP接続待ち
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("WiFi connected\r\nIP address: ");
Serial.println(WiFi.localIP());
ambient.begin(channelId, writeKey, &client);
Co2SensorBegin();
Wire.begin(23,22);
bme.begin();
uv.begin(VEML6070_1_T);
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
};
void loop() {
Serial.printf("----------------------------------------------------------------\n");
if(bme.performReading()) {
Serial.printf("Temperature = %f *C\n",bme.temperature);
Serial.printf("Pressure = %f hPa\n",bme.pressure / 100.0);
Serial.printf("Humidity = %f %%\n",bme.humidity);
Serial.printf("Gas = %f KOhms\n",bme.gas_resistance / 1000.0);
ambient.set(1, bme.temperature);
ambient.set(2, bme.pressure / 100.0);
ambient.set(3, bme.humidity);
ambient.set(4, bme.gas_resistance / 1000.0);
}
Serial.printf("UvLightLevel = %d \n",uv.readUV());
ambient.set(5, (float)uv.readUV());
if(dataRecieve())
{
Serial.printf("Co2 = %d ppm\n",CO2PPM);
ambient.set(6, (float)CO2PPM);
}
ambient.send();
Serial.printf("----------------------------------------------------------------\n\n");
delay(30000);
};
void Co2SensorBegin()
{
Co2SensorSerial.begin(9600,SERIAL_8N1,25,21);
}
bool dataRecieve(void)
{
byte data[9];
int i = 0;
//transmit command data
for(i=0; i<sizeof(cmd_get_sensor); i++)
{
Co2SensorSerial.write(cmd_get_sensor[i]);
}
delay(10);
//begin reveiceing data
if(Co2SensorSerial.available())
{
while(Co2SensorSerial.available())
{
for(int i=0;i<9; i++)
{
data[i] = Co2SensorSerial.read();
}
}
}
if((i != 9) || (1 + (0xFF ^ (byte)(data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7]))) != data[8])
{
return false;
}
CO2PPM = (int)data[2] * 256 + (int)data[3];
temperature = (int)data[4] - 40;
return true;
}
結果
センサから取得した各値がAmbient上でグラフ化されました。
(室内で計測したため、UV Levelは0のままです。日に当てると変化することは確認しています)
あとがき
センサーの精度と計測環境的に値の精度はそれほど高くないと思います。どちらかというと変化を検出したいのでAIで解析させて、環境の状態通知をやってみたいと思いました。