Funpack 第八期 投篮运动手柄
Funpack 第八期 投篮运动手柄。投篮者可通过手持手柄(开发板)模拟投篮动作,而手柄会根据初始物理参数(可由用户设定或者系统默认值),对投篮者的命中率作出预判。
标签
嵌入式系统
cjmf
更新2021-05-18
746

一、获取原始加速度及角速度数据

采集 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();
  }
}

 

Fhe_OuqsQtYOFrGBuLbUrQyoOGpI

 

二、数据分类及模型生成

使用 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))

 

Fnn0s1EYX1cggT-sb-P406FfTovE

 

三、编译至 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);
}

 

FnUvpraRKz4IWC40TauEJPzJDHb3

四、心得体会

本次的活动用到了 TinyML 的技术,也感受到了人工智能的方便。在之后的单片机发展中,人工智能必然会占据重要的地位。感谢赞助方提供的学习的机会。

附件下载
ai.zip
train.json
团队介绍
中国计量大学
团队成员
cjmf
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号