
前回は3軸加速度センサKXR94-2050モジュールを使用して加速度データをXBeeを用いて無線送信する方法を解説しました。今回はローカルXBeeで受信したフレームからX,Y,Z軸方向の加速度データを読み取り、Processing を用いてリアルタイムでデータを表示するスクロールグラフをご紹介します。
Processingについては5月24日の「XBeeモジュールの使い方(アナログ温度センサの温度データ可視化)」の記事を参考にしてください。今回はこのときの記事で記載した設定条件でスクロールグラフを作成しました。
下の画像は前回の解説で示したローカルXBeeが受信するフレームを再掲しております。今回はこのフレームの中からProcessing を用いて加速度データを読み取り描画します。
リモートXBeeのMicroPython Terminalに書き込みます。加速度が正や負の値となってもフレーム長は変化しないようにdata_payload の中で{:+.3f}のように設定しています。
4行目のCOORDINATOR_64BIT_ADDRはご自分のローカルXBeeのシリアルナンバーに変更してください。
import xbee
import time
from machine import Pin, ADC
COORDINATOR_64BIT_ADDR = b'\x00\x13\xA2\x00\x41\xAE\x36\x69'
adc_pin0 = Pin("D0", Pin.IN, Pin.PULL_UP)
adcx = ADC(adc_pin0)
adc_pin1 = Pin("D1", Pin.IN, Pin.PULL_UP)
adcy = ADC(adc_pin1)
adc_pin2 = Pin("D2", Pin.IN, Pin.PULL_UP)
adcz = ADC(adc_pin2)
while True:
voltage_mv = xbee.atcmd('%V')
supply_voltage_v = voltage_mv / 1000.0
raw_adcx_value = adcx.read()
raw_adcy_value = adcy.read()
raw_adcz_value = adcz.read()
accelx = ((raw_adcx_value / 4095.0) * supply_voltage_v - supply_voltage_v / 2) / 0.66
accely = ((raw_adcy_value / 4095.0) * supply_voltage_v - supply_voltage_v / 2) / 0.66
accelz = ((raw_adcz_value / 4095.0) * supply_voltage_v - supply_voltage_v / 2) / 0.66
data_payload = "Vref: {:.3f}V, Accel_x: {:+.3f}g, Accel_y: {:+.3f}g, Accel_z: {:+.3f}g".format(
supply_voltage_v, accelx, accely, accelz
)
try:
xbee.transmit(COORDINATOR_64BIT_ADDR, data_payload.encode('utf8'))
except Exception as e:
print("Error sending data: {}".format(e))
上記のコードによりローカルXBeeに送信されたフレームを示します。XYZ方向の加速度が検出されていることがわかります。
Receive Packet (API 1)
7E 00 4E 90 00 13 A2 00 41 AE 36 24 B0 CE 01 56 72 65 66 3A 20 33 2E 32 39 32 56 2C 20 41 63 63 65 6C 5F 78 3A 20 2D 30 2E 30 33 33 67 2C 20 41 63 63 65 6C 5F 79 3A 20 2D 30 2E 30 34 30 67 2C 20 41 63 63 65 6C 5F 7A 3A 20 2B 31 2E 30 30 31 67 1F
Start delimiter: 7E
Length: 00 4E (78)
Frame type: 90 (Receive Packet)
64-bit source address: 00 13 A2 00 41 AE 36 24
16-bit source address: B0 CE
Receive options: 01
RF data (HEX): 56 72 65 66 3A 20 33 2E 32 39 32 56 2C 20 41 63 63 65 6C 5F 78 3A 20 2D 30 2E 30 33 33 67 2C 20 41 63 63 65 6C 5F 79 3A 20 2D 30 2E 30 34 30 67 2C 20 41 63 63 65 6C 5F 7A 3A 20 2B 31 2E 30 30 31 67
RF data (ASCII): Vref: 3.292V, Accel_x: -0.033g, Accel_y: -0.040g, Accel_z: +1.001g
Checksum: 1F
以下のコードで加速度データをスクロールグラフで表示できます。以下のコードをProcessingで実行する前に、ご自分のローカルXBeeとのシリアル通信のCOMポート番号とボーレートを33行目に入力してください。
xbee = new Serial (this, “COM12”, 115200);
import processing.serial.*;
import java.util.ArrayList;
import java.io.PrintWriter; // CSV
import java.util.Date;
import java.text.SimpleDateFormat;
Serial xbee; ///Xeeからの入力シリアルポート
int ps = 82;
byte[] packet = new byte[ps]; //受信パケット
int byteCounter; //keeps track of where you are in the packet
int fontSize = 24; // size of the text on the screen
int lastReading = 0; //value of the previous incoming byte
int rssi = 0; // received signal strength
int dc = 0; //データ数
boolean dataStarted = false; // データの受信開始フラグ
int bufferIndex = 0; //
ArrayList<Float> xData = new ArrayList<>(); //X Data
ArrayList<Float> yData = new ArrayList<>(); //Y Data
ArrayList<Float> zData = new ArrayList<>(); //Z Data
//int MSBx, LSBx, MSBy, LSBy, MSBz, LSBz;
//int thisSamplex = (MSBx * 256) + LSBx;
//int thisSampley = (MSBy * 256) + LSBy;
//int thisSamplez = (MSBz * 256) + LSBz;
float thisSamplex;
float thisSampley;
float thisSamplez;
int maxDataPoints = 100; // 表示するデータポイントの最大数
PrintWriter output; // CSV Printeriter
boolean saved = false; //保存フラグ
void setup() {
size (1520, 780);
PFont myFont = createFont (PFont. list()[5], 24);
textFont (myFont);
println(Serial. list());
xbee = new Serial (this, "COM12", 115200);
//デスクトップパスを取得
String desktopPath = sketchPath();
println(desktopPath);
// デスクトップに Dataフォルダを作成
String dataFolderPath = desktopPath + "/Data";
// CSVファイルを「Data」フォルダ内に作成
String timestamp = timestamp();
String fileName = dataFolderPath + timestamp +".csv";
output = createWriter(fileName);
output. println("X,Y,Z");
}
void draw() {
background (0);
stroke (255, 255, 255);
line(0, 260, 1520, 260);
line (0, 520, 1520, 520);
strokeWeight (2);
noFill ();
stroke(100); // 薄いグレー
textSize(16);
for (int i = 0; i <= 10; i++) {
// X軸グラフの横線とラベル
line(50, i*26, width, i*26);
// Y軸グラフの横線とラベル
line(50, i*26+260, width, i*26+260);
// Z軸グラフの横線とラベル
line(50, i*26+520, width, i*26+520);
}
textSize(26);
text("X", 8, 130);
text("Y", 8, 130+260);
text("Z", 8, 130+260*2);
stroke (255, 255, 255);
line(0, 260, 1520, 260);
line (0, 520, 1520, 520);
//Xデータ
stroke (255, 0, 0); // red
beginShape();
for (int i = 0; i < xData.size(); i++) {
float x = map(i, 0, maxDataPoints, width - 50, 50);
float y = map(xData.get(i), -2, 2, 260, 0);
vertex (x, y);
}
endShape();
//Yデータ
stroke (0, 255, 0); // green
beginShape();
for (int i = 0; i < yData.size(); i++) {
float x = map(i, 0, maxDataPoints, width - 50, 50);
float y = map(yData.get(i), -2, 2, 520, 260);
vertex (x, y);
}
endShape();
//Zデータ
stroke (244, 229, 17); // blue
beginShape();
for (int i = 0; i < zData.size(); i++) {
float x = map(i, 0, maxDataPoints, width - 50, 50);
float y = map(zData.get(i), -2, 2, 780, 520);
vertex (x, y);
}
endShape();
fill (255);
}
void serialEvent (Serial xbee) {
int thisByte = xbee.read();
if (!dataStarted && thisByte == 0x7E) {
dataStarted = true;
bufferIndex = 0;
packet [bufferIndex++] = (byte) thisByte;
} else if (dataStarted) {
packet [bufferIndex++] = (byte) thisByte;
if (bufferIndex == ps) {
parseData (packet);
dataStarted = false;
}
}
}
void parseData(byte[] packet) {
int adSx = 38;
char cx1 = (char)(packet[adSx] & 0xFF);
char cx2 = (char)(packet[adSx+1] & 0xFF);
char cx3 = (char)(packet[adSx+2] & 0xFF);
char cx4 = (char)(packet[adSx+3] & 0xFF);
char cx5 = (char)(packet[adSx+4] & 0xFF);
char cx6 = (char)(packet[adSx+5] & 0xFF);
String crx = "" + cx1 + cx2 + cx3 + cx4 + cx5 + cx6;
println ("cx=" + crx);
thisSamplex = Float.parseFloat(crx);
println("X: " + thisSamplex);
int adSy = adSx + 18;
char cy1 = (char)(packet[adSy] & 0xFF);
char cy2 = (char)(packet[adSy+1] & 0xFF);
char cy3 = (char)(packet[adSy+2] & 0xFF);
char cy4 = (char)(packet[adSy+3] & 0xFF);
char cy5 = (char)(packet[adSy+4] & 0xFF);
char cy6 = (char)(packet[adSy+5] & 0xFF);
String cry = "" + cy1 + cy2 + cy3 + cy4 + cy5 + cy6;
println ("cy=" + cry);
thisSampley = Float.parseFloat(cry);
println("Y: " + thisSampley);
int adSz = adSy + 18;
char cz1 = (char)(packet[adSz] & 0xFF);
char cz2 = (char)(packet[adSz+1] & 0xFF);
char cz3 = (char)(packet[adSz+2] & 0xFF);
char cz4 = (char)(packet[adSz+3] & 0xFF);
char cz5 = (char)(packet[adSz+4] & 0xFF);
char cz6 = (char)(packet[adSz+5] & 0xFF);
String crz = "" + cz1 + cz2 + cz3 + cz4 + cz5 + cz6;
println ("cz=" + crz);
thisSamplez = Float.parseFloat(crz);
println("Z: " + thisSamplez);
println(" ------------- ");
//CSVファイルにデータを書き込む
output.println(thisSamplex + "," + thisSampley + "," + thisSamplez);
dc++;
//データをリストに追加
xData.add (thisSamplex);
yData.add (thisSampley);
zData.add (thisSamplez);
//最大データポイント数を超えたら古いデータを削除
if (xData.size() > maxDataPoints) {
xData.remove (0);
yData.remove (0);
zData.remove (0);
}
}
void keyPressed() {
if (key == 's'&& !saved || key == 'S'&& !saved ) {
//s or Sキーを押すとファイルをタイムスタンプ付きのファイル名で保存
output.flush(); //現在のデータを書き込む
output. close(); // file close
exit(); //スケッチ終了
}
}
String timestamp() {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd-HHmmss-SSS") ;
return sdf.format (date);
}
サンプリングレート間隔25msで3軸加速度センサKXR94-2050の加速度データをスクロールグラフで表示することができました。
