大家好, 我叫james, 是一名hacker. 平时喜欢研究一些可编程的小东西.
第八期funpack活动的开发板是arduino nano 33 ble sensor. 搭载了nrf52840蓝牙mcu. 本期笔者实现的是"投篮运动手柄", 名为"投篮助手". 该运动手柄使用了tensorflow智能ai引擎, 能够预测投篮命中率, 并给出简单的投篮建议.
第八期可以用数值的方法实现, 但是需要比较强的物理分析和工程技术, 所以我选择了用tinyml进行实现, 以规避物理分析和数学计算.
整体上, 笔者着重参考了tensorflow lite for microcontroller的一个示例, 即magic wand. 选择这个示例作为起点的原因是这个示例完整的展示了一个应用tensorflow lite的应用开发的过程, 这个示例使用了LSM9DS1传感器采集到加速度信息, 然后基于CNN进行建模和训练, 最后把训练好的模型部署到nano33ble.
投篮助手在加速度数据的基础上增加了角速度值, 然后进行训练, 以期望得到更准确的投篮模型.
投篮助手通过nordic ble uart将结果发送到手机或者电脑.
为了更明确地区分项目中需要不同技能的任务, 笔者将任务分为"ML实现", "软件实现"和"硬件实现":
ML实现
位于model目录 包括训练, 验证, 测试的数据采集, 建模, 转换最终得到tflite格式训练好的模型, 提供对传感器输入数据的预测.
软件实现
位于basketball-mentor目录 即嵌入式软件设计和实现.
硬件实现
目前只是将开发板插入面包板, 后续可以通过3d打印制作手柄外壳, 将开发板和电池装入, 以方便实际训练使用.
cpython-v3.8.5 tensorflow-v2.4.1-noavx-cpu
此处可以使用colab云端环境, 也可以在自己的机器上安装全新的环境, 笔者使用本地环境, 更灵活一些.
virtualenv pyenv . pyenv/bin/active pip install tensorflow==2.4.1
ML基本步骤: 建模 -> 采数 -> 训练 -> 转换 -> 测试
sensor-handler.cpp
while (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) { float x, y, z; float x1, y1, z1; float x2, y2, z2; // Read each sample, removing it from the device's FIFO buffer if (!IMU.readAcceleration(x1, y1, z1)) { TF_LITE_REPORT_ERROR(error_reporter, "Failed to read data"); break; } if (!IMU.readGyroscope(x2, y2, z2)) { TF_LITE_REPORT_ERROR(error_reporter, "Failed to read data"); break; } x = (x1 + x2) / 2; y = (y1 + y2) / 2; z = (z1 + z2) / 2; }
arduinooutputhandler.cpp
#define high "有点高了" #define low "有点低了" #define good "应该会投进" #define fail "三不沾" void HandleOutput(tflite::ErrorReporter* error_reporter, int kind) { // The first time this method runs, set up our LED static bool is_initialized = false; static HardwareBLESerial &bleSerial = HardwareBLESerial::getInstance(); if (!is_initialized) { pinMode(LED_BUILTIN, OUTPUT); is_initialized = true; } if (kind == 0) { digitalWrite(LED_BUILTIN, LOW); TF_LITE_REPORT_ERROR( error_reporter, high); bleSerial.println(high); } else if (kind == 1) { digitalWrite(LED_BUILTIN, LOW); TF_LITE_REPORT_ERROR( error_reporter, low); bleSerial.println(low); } else if (kind == 2) { digitalWrite(LED_BUILTIN, HIGH); TF_LITE_REPORT_ERROR( error_reporter, good); bleSerial.println(good); } else if (kind == 3) { digitalWrite(LED_BUILTIN, LOW); TF_LITE_REPORT_ERROR( error_reporter, fail); bleSerial.println(fail); } }
目前只是将开发板插入面包板, 后续可以通过3d打印制作手柄外壳, 将开发板和电池装入, 以方便实际训练使用.
(对本活动的心得体会(包括意见或建议))
- 启发式算法和精确数学模型需要精通该领域和专家知识, 另外还需要编程能力实现这个算法. 即需要工程能力+数学能力, 但是机器学习可以使用现成的模型通过训练数据完成分类应用的实现.
- 得益于tensorflow和pytorch等深度学习框架, 机器学习应用起来不需要太强的编程和工程能力, 学习过程类似于学kicad, 需要不断尝试, 本身不需要太多知识积累.
- arduino的ide我使用的是1.8.13, 这个builder实在是慢, 不知道为啥library每次都要重新编译.
- 本期课程里面介绍的是用物理分析的方法实现, 这个难度还是比较高的.
- 例子中训练好的模型无法直接使用
- tf python包 import之后直接core dump python v3.8.5, tensorflow v2.4.0, tensorflow v2.5.0都会coredump colab上面是python-v3.7.10, 并非是版本问题, 而是tensorflow默认编译只支持带有AVX拓展指令集的cpu. 使用这个里面的安装包解决: https://github.com/yaroslavvb/tensorflow-community-wheels/issues/183
https://github.com/picospuch/eetree-funpack-workshop/tree/phase-eight
后续继续学习Tensorflow和Tensorflow Lite, 这个配合主频较高的mcu还是很有用的, 可以让嵌入式应用更"智能"
最后,感谢硬禾学堂和得捷电子,让我接触到了arduino蓝牙开发板,让我能在业余时间参与更多有趣项目的学习,也感谢群的小伙伴提供很多种实现题目功能的思路,感谢大家一路的折腾与陪伴,谢谢!