内容介绍
内容介绍
一、获取原始加速度及角速度数据
采集 4 秒内的数据,以串口形式输出。
#include <ScheduleTable.h>
#include <Arduino_LSM9DS1.h>
#include <LibPrintf.h>
#define PIN_LED (13u)
#define LED_BUILTIN PIN_LED
#define LEDR (22u)
#define LEDG (23u)
#define LEDB (24u)
#define LED_PWR (25u)
SchedTable<2> blinkcycle(2000);
SchedTable<1> datacycle(6000);
SchedTable<1> serialcycle(2000);
String write_string = "[";
bool data_collect = false;
void setup() {
datacycle.at(4000, nextSecond);
serialcycle.at(1000, serialout);
blinkcycle.at(0, loop1);
blinkcycle.at(1000, loop2);
blinkcycle.start();
Serial.begin(115200);
printf("\033[32m[*] Started\r\n\033[0m");
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LED_PWR, OUTPUT);
pinMode(LEDR, OUTPUT);
if (!IMU.begin()) {
printf("\033[31m[!] Failed to initialize IMU!\033[0m");
while (1);
}
printf("[*] Accelerometer sample rate = %.2f Hz\r\n", IMU.accelerationSampleRate());
printf("[*] Gyroscope sample rate = %.2f Hz\r\n", IMU.gyroscopeSampleRate());
float x, y, z;
while (!IMU.accelerationAvailable() || !IMU.gyroscopeAvailable()) {}
IMU.readGyroscope(x, y, z);
printf("\033[34m[*] Gyroscope x = %.2f\ty =%.2f\tz =%.2f\r\n\033[0m", x, y, z);
IMU.readAcceleration(x, y, z);
printf("\033[34m[*] Accelerometer x = %.2f\ty =%.2f\tz =%.2f\r\n\033[0m", x, y, z);
blinkcycle.stop();
datacycle.start(1);
data_collect = true;
}
void loop() {
ScheduleTable::update();
if (data_collect) {
getIMUData();
}
}
void nextSecond() {
data_collect = false;
write_string[write_string.length() - 1] = ']';
serialcycle.start();
blinkcycle.start();
}
void getIMUData() {
float x, y, z;
if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
IMU.readAcceleration(x, y, z);
write_string += String(x, 6);
write_string += ",";
write_string += String(y, 6);
write_string += ",";
write_string += String(z, 6);
write_string += ",";
IMU.readGyroscope(x, y, z);
write_string += String(x, 6);
write_string += ",";
write_string += String(y, 6);
write_string += ",";
write_string += String(z, 6);
write_string += ",";
}
}
void loop1() {
digitalWrite(LED_BUILTIN, HIGH);
digitalWrite(LED_PWR, HIGH);
digitalWrite(LEDR, HIGH);
}
void loop2() {
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(LED_PWR, LOW);
digitalWrite(LEDR, LOW);
}
bool digit(String s) {
for (auto c : s) {
if (!isDigit(c)) {
return false;
}
}
return true;
}
void serialout() {
if (Serial) {
printf("%lu\n", write_string.length());
printf("%s\n", write_string.c_str());
serialcycle.stop();
}
}
二、数据分类及模型生成
使用 Python+Tensorflow 2.0 进行学习。因为数据量过大,所以提前每四个一组进行优化。
这里使用两个 ReLU 层来进行学习。
import os
import numpy as np
from tensorflow.keras import Sequential, layers
from tensorflow.keras.utils import to_categorical
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from tinymlgen import port
from decimal import Decimal
import tensorflow as tf
X = np.loadtxt('1.txt', dtype=np.float32, delimiter=',')
y = [1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
y = np.array(y)
y = to_categorical(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
X_train, X_valid, y_train, y_valid = train_test_split(
X_train, y_train, test_size=0.3)
input_dim = X_train.shape[1:]
output_dim = y.shape[1]
nn = Sequential()
nn.add(layers.Dense(units=50, activation='relu', input_shape=input_dim))
nn.add(layers.Dense(units=15, activation='tanh'))
nn.add(layers.Dense(units=15, activation='relu'))
nn.add(layers.Dense(output_dim, activation='softmax'))
nn.compile(loss='categorical_crossentropy',
optimizer='adam', metrics=['accuracy'])
nn.fit(X_train, y_train, validation_data=(
X_valid, y_valid), epochs=10, verbose=1)
print('Accuracy: %.1f' % nn.evaluate(X_test, y_test)[1])
with open('output.h', 'w+') as f:
f.write(port(nn, variable_name='lq', pretty_print=True, optimize=False))
三、编译至 Arduino
生成的 output.h 作为头文件,使用 TinyML 库调用,命中绿色。串口会输出概率。
#include <TensorFlowLite.h>
#include <tensorflow/lite/micro/all_ops_resolver.h>
#include <tensorflow/lite/micro/micro_error_reporter.h>
#include <tensorflow/lite/micro/micro_interpreter.h>
#include <tensorflow/lite/schema/schema_generated.h>
#include <tensorflow/lite/version.h>
#include <Arduino_LSM9DS1.h>
#include <LibPrintf.h>
#include "output.h"
#define PIN_LED (13u)
#define LED_BUILTIN PIN_LED
#define LEDR (22u)
#define LEDG (23u)
#define LEDB (24u)
#define LED_PWR (25u)
float X_test[708] = {};
int count = 0;
int once = 0;
int total = 0;
float sum[6];
tflite::MicroErrorReporter tflErrorReporter;
tflite::AllOpsResolver tflOpsResolver;
const tflite::Model* tflModel = nullptr;
tflite::MicroInterpreter* tflInterpreter = nullptr;
TfLiteTensor* tflInputTensor = nullptr;
TfLiteTensor* tflOutputTensor = nullptr;
constexpr int tensorArenaSize = 16 * 1024;
byte tensorArena[tensorArenaSize];
const char* GESTURES[] = {
"0",
"1"
};
#define NUM_GESTURES (sizeof(GESTURES) / sizeof(GESTURES[0]))
void setup() {
Serial.begin(115200);
// while (!Serial) {};
printf("\033[32m[*] Started\r\n\033[0m");
tflModel = tflite::GetModel(lq);
if (tflModel->version() != TFLITE_SCHEMA_VERSION) {
Serial.println("Model schema mismatch!");
while (1);
} else {
printf("Load Success\n");
}
tflInterpreter = new tflite::MicroInterpreter(tflModel, tflOpsResolver, tensorArena, tensorArenaSize, &tflErrorReporter);
tflInterpreter->AllocateTensors();
tflInputTensor = tflInterpreter->input(0);
tflOutputTensor = tflInterpreter->output(0);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LED_PWR, OUTPUT);
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
DOWN();
if (!IMU.begin()) {
printf("\033[31m[!] Failed to initialize IMU!\033[0m");
while (1);
}
printf("[*] Accelerometer sample rate = %.2f Hz\r\n", IMU.accelerationSampleRate());
printf("[*] Gyroscope sample rate = %.2f Hz\r\n", IMU.gyroscopeSampleRate());
while (!IMU.accelerationAvailable() || !IMU.gyroscopeAvailable()) {}
while (count < 708) {
float x, y, z;
while (!IMU.accelerationAvailable() || !IMU.gyroscopeAvailable()) {}
if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
total++;
IMU.readAcceleration(x, y, z);
sum[0] += x;
sum[1] += y;
sum[2] += z;
IMU.readGyroscope(x, y, z);
sum[3] += x;
sum[4] += y;
sum[5] += z;
once++;
if (once >= 4) {
once = 0;
tflInputTensor->data.f[count] = sum[0] / 4;
count++;
tflInputTensor->data.f[count] = sum[1] / 4;
count++;
tflInputTensor->data.f[count] = sum[2] / 4;
count++;
tflInputTensor->data.f[count] = sum[3] / 4;
count++;
tflInputTensor->data.f[count] = sum[4] / 4;
count++;
tflInputTensor->data.f[count] = sum[5] / 4;
count++;
for (int i = 0; i <= 5; i++) {
sum[i] = 0;
}
}
}
}
printf("Data Collected\n");
TfLiteStatus invokeStatus = tflInterpreter->Invoke();
if (invokeStatus != kTfLiteOk) {
Serial.println("Invoke failed!");
while (1);
return;
} else {
printf("SUCC\n");
}
printf("%d\n%d\n", total, count);
for (int i = 0; i < 2; i++) {
Serial.print(GESTURES[i]);
Serial.print(": ");
Serial.println(tflOutputTensor->data.f[i], 6);
}
if (tflOutputTensor->data.f[0] > tflOutputTensor->data.f[1]) {
R();
} else {
G();
}
Serial.println();
}
void loop() {
}
void G() {
digitalWrite(LEDR, HIGH); digitalWrite(LEDG, HIGH); digitalWrite(LEDB, HIGH);
digitalWrite(LED_BUILTIN, HIGH);
digitalWrite(LED_PWR, HIGH);
digitalWrite(LEDG, LOW);
}
void R() {
digitalWrite(LEDR, HIGH); digitalWrite(LEDG, HIGH); digitalWrite(LEDB, HIGH);
digitalWrite(LED_BUILTIN, HIGH);
digitalWrite(LED_PWR, HIGH);
digitalWrite(LEDR, LOW);
}
void DOWN() {
digitalWrite(LED_BUILTIN, HIGH);
digitalWrite(LED_PWR, HIGH);
digitalWrite(LEDR, HIGH); digitalWrite(LEDG, HIGH); digitalWrite(LEDB, LOW);
}
四、心得体会
本次的活动用到了 TinyML 的技术,也感受到了人工智能的方便。在之后的单片机发展中,人工智能必然会占据重要的地位。感谢赞助方提供的学习的机会。
附件下载
ai.zip
train.json
团队介绍
中国计量大学
团队成员
cjmf
评论
0 / 100
查看更多
猜你喜欢
Funpack第八期:基于Arduino Nano 33 BLE的投篮运动手柄利用NANO-33 BLE的加速度及角速度感应器,设计一款用于虚拟练习投篮的手柄。
实现根据篮球抛物线轨迹是否穿过篮筐附近的矩形框计算是否投中,根据自定义的命中率函数计算命中率,将投篮结果通过串口和oled屏幕输出。
锅包肉
1362
Funpack第八期—用Nano 33 BLE Sense做的投篮Nano 33 BLE Sense 蓝牙,作业,投篮 、IMU、加速度、角速度
aramy
1577
Funpack第八期-使用tensorflow lite实现投篮运动手柄使用tensorflow lite + arduino nano 33 ble sensor初步实现建议投篮运动手柄
james
1193