- 2024-12-30
-
加入了学习《【Follow me】第二季第四期任务汇总》,观看 任务汇总提交
-
发表了主题帖:
【Follow me第二季第4期】任务汇总
本帖最后由 iexplore123 于 2024-12-30 16:07 编辑
# 【Follow_me】第二季第四期任务汇总
[EE大学堂视频链接](https://training.eeworld.com.cn/course/68907 "EE大学堂")
## 1.任务概述
大家好,这里是iex123。最近刚结束期末考试,所以汇总帖耽搁了一下。这次活动是基于Arduino Nano RP2040 Connect开发板,通过一系列任务来学习和探索Arduino Nano RP2040 Connect的功能和应用。在这个活动中,我们将学习Arduino Nano RP2040 Connect的硬件特性、使用Arduino IDE开发、调试IMU传感器、PDM麦克风、RGB LED、串口通信等功能,最终通过机器学习算法识别运动状态。
### 1.1 使用的硬件
- Arduino Nano RP2040 Connect开发板
- USB micro-B数据线
- 电脑
### 1.2 使用的软件
- VS Code
- PlatformIO
- Arduino LSM6DSOX库
- Arduino PDM库
- WifiNINA库
- Edge Impulse
## 2.任务进度
- [x] 搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
> 使用PlatformIO搭建开发环境,通过Arduino框架控制WifiNINA连接的共阳极三色LED,实现LED闪烁效果,并通过串口打印Hello DigiKey & EEWorld!
- [x] 学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据。
> 学习IMU传感器的基础知识,调试Arduino LSM6DSOX库,通过串口打印六轴原始数据。
- [x] 学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
> 学习PDM麦克风的技术知识,调试Arduino PDM库,使用串口工具SerialTest查看PDM麦克风采集到的音频数据。
- [x] 通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小。
> 对PDM麦克风采集到的音频数据进行处理,通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小。
- [x] 通过IMU数据结合机器学习算法,识别运动状态,并通过串口打印。
> 使用Edge Impulse平台构建机器学习模型,通过IMU数据识别运动状态,并串口打印。
## 3.任务详情
### 任务1-4 :
#### 帖子链接:
- 任务一:[【Follow me第二季第4期】 搭建环境+点灯+串口打印](https://bbs.eeworld.com.cn/thread-1300009-1-1.html)
- 任务二:[【Follow me第二季第4期】 IMU传感器六轴数据打印](https://bbs.eeworld.com.cn/thread-1300010-1-1.html)
- 任务三:[【Follow me第二季第4期】 PDM麦克风音频波形打印](https://bbs.eeworld.com.cn/thread-1300019-1-1.html)
- 任务四:[【Follow me第二季第4期】 RGB LED显示PDM麦克风收音大小](https://bbs.eeworld.com.cn/thread-1301191-1-1.html)
#### 任务代码:
```cpp
#include
#include
#include
#include
#include
static const char channels = 1; // 麦克风通道数
static const int sampleRate = 16000; // 音频采样率
short sampleBuffer[512]; // 音频缓冲区
volatile int samplesRead = 0; // 音频采样数
int minSoundThreshold = 100; // 动态最小声音检测阈值
#define SMOOTHING_FACTOR 0.9 // 平滑因子
float smoothedSample = 0; // 平滑后的采样值
void onPDMData() { // PDM麦克风数据回调函数
int numSamples = PDM.available(); // 获取可用采样数
if (numSamples > 0) {
PDM.read(sampleBuffer, numSamples);
samplesRead = numSamples / 2; // 16位采样,每个采样占2字节
}
}
void setup() {
// 初始化串口
Serial.begin(115200);
while (!Serial); // 等待串口连接
// 初始化LED引脚
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
// 打印欢迎信息
Serial.println("Hello DigiKey & EEWorld!");
// 初始化IMU传感器
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
// 初始化PDM麦克风
PDM.onReceive(onPDMData);
if (!PDM.begin(channels, sampleRate)) {
Serial.println("Failed to initialize PDM!");
while (1);
}
// 初始化LED_Buildin引脚
pinMode(LED_BUILTIN, OUTPUT);
}
void blinkLEDs() { // 闪烁三色LED
digitalWrite(LEDR, HIGH);
delay(500);
digitalWrite(LEDR, LOW);
digitalWrite(LEDG, HIGH);
delay(500);
digitalWrite(LEDG, LOW);
digitalWrite(LEDB, HIGH);
delay(500);
digitalWrite(LEDB, LOW);
}
void printIMUData() { // 读取IMU传感器数据,共有6个轴
float x, y, z, x_g, y_g, z_g;
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(x, y, z); // 读取加速度数据
IMU.readGyroscope(x_g, y_g, z_g); // 读取陀螺仪数据
Serial.print("Acceleration X: ");
Serial.print(x);
Serial.print(", Y: ");
Serial.print(y);
Serial.print(", Z: ");
Serial.println(z);
Serial.print("Gyroscope X: ");
Serial.print(x_g);
Serial.print(", Y: ");
Serial.print(y_g);
Serial.print(", Z: ");
Serial.println(z_g);
}
}
void printPDMData() { // 读取PDM麦克风数据
for (int i = 0; i < samplesRead; i++) {
Serial.println(sampleBuffer);
}
}
void displaySoundLevelWithAnimation() {
int maxSample = 0;
for (int i = 0; i < samplesRead; i++) {
maxSample = max(maxSample, abs(sampleBuffer));
}
// 平滑处理
smoothedSample = SMOOTHING_FACTOR * smoothedSample + (1 - SMOOTHING_FACTOR) * maxSample;
int targetBrightness = (smoothedSample > minSoundThreshold) ? map(smoothedSample, minSoundThreshold, 32767, 0, 255) : 0;
static int currentBrightness = 0;
Serial.print("maxSample: ");
Serial.print(maxSample);
Serial.print(" smoothedSample: ");
Serial.print(smoothedSample);
Serial.print(" minSoundThreshold: ");
Serial.print(minSoundThreshold);
Serial.print(" targetBrightness: ");
Serial.print(targetBrightness);
Serial.print(" currentBrightness: ");
Serial.println(currentBrightness);
// 渐变动画
int step = 1; // 增加变化步长,降低灵敏度
if (currentBrightness < targetBrightness) {
currentBrightness = min(currentBrightness + step, targetBrightness);
} else if (currentBrightness > targetBrightness) {
currentBrightness = max(currentBrightness - step, targetBrightness);
}
// 根据亮度值设置RGB LED颜色
int brightness = 255 - currentBrightness;
analogWrite(LEDR, brightness);
analogWrite(LEDG, brightness);
analogWrite(LEDB, brightness);
// 根据音量大小点亮LED_Builtin
digitalWrite(LED_BUILTIN, smoothedSample > 2000 ? HIGH : LOW);
}
void loop() {
// 闪烁三色LED
blinkLEDs(); //任务1
// 读取IMU传感器数据
printIMUData(); //任务2
// 显示声音大小并添加动画
displaySoundLevelWithAnimation(); //任务4
// 读取PDM麦克风数据 //任务3
if (samplesRead) {
printPDMData();
samplesRead = 0;
}
delay(500);
}
```
流程图:
#### 效果展示:
[localvideo]f03a8cafbde121eb794598ff5a1a10b7[/localvideo]
[localvideo]1abca255672305d55267cbd86e84b327[/localvideo]
### 任务5:
#### 帖子链接:
- 任务五:[【Follow me第二季第4期】 EdgeImpluse在线训练机器学习模型并部署](https://bbs.eeworld.com.cn/thread-1302955-1-1.html)
#### 任务代码:
## 4.任务总结
本期活动通过一系列任务,我们学习了Arduino Nano RP2040 Connect的硬件特性、使用Arduino IDE开发、调试IMU传感器、PDM麦克风、RGB LED、串口通信等功能,最终通过机器学习算法识别运动状态。在这个过程中,我们学习了Arduino Nano RP2040 Connect的硬件特性和使用方法,学习了IMU传感器和PDM麦克风的工作原理和使用方法,学习了Edge Impulse平台的使用方法,学习了机器学习模型的训练和部署方法。通过这个活动,我们对Arduino Nano RP2040 Connect的功能和应用有了更深入的了解,对嵌入式机器学习有了初步的认识,对嵌入式开发有了更多的实践经验。
最后,感谢DigiKey和EEWorld提供的这次活动机会,让我们有机会学习和探索Arduino Nano RP2040 Connect的功能和应用,也感谢各位参与活动的朋友们,希望大家在这个活动中有所收获,也希望大家能够继续关注和支持DigiKey和EEWorld的活动,让我们一起学习和成长!
## 5.代码下载
[附件下载中心](https://download.eeworld.com.cn/detail/iexplore123/635473 "附件下载中心")
------------
感谢阅读。
-
上传了资料:
得捷followme第二季第四期Raspberry Pi RP2040
-
加入了学习《Arduino? Nano RP2040 Connect 任务视频》,观看 串口工具初尝试
- 2024-12-29
-
加入了学习《Arduino? Nano RP2040任务讲解视频》,观看 Arduino Nano RP2040任务讲解视频
- 2024-12-27
-
发表了主题帖:
【Follow me第二季第4期】EdgeImpluse在线训练机器学习模型并部署
本帖最后由 iexplore123 于 2024-12-27 01:54 编辑
# 【Follow me第二季第4期】 通过IMU数据结合机器学习算法,识别运动状态,并通过串口打印
## 任务概述
在这个任务中,我们将使用Edge Impulse平台构建机器学习模型,通过IMU数据识别运动状态,并串口打印。
任务二中我们已经读取了nano RP2040 Connect板载的IMU传感器(LSM6DSOX)的六轴原始数据,它包含三轴加速度计和三轴陀螺仪的数据,可以用于运动检测和姿态跟踪。接下来我们将采集IMU数据构建数据集,并使用简单的分类模型
## Edge Impulse
[Edge Impulse](https://www.edgeimpulse.com/)是一个端到端的开发平台,可以帮助开发者快速构建、部署和管理嵌入式机器学习模型。Edge Impulse提供[在线开发工具](https://studio.edgeimpulse.com/),包括数据采集、特征提取、模型训练和部署功能,支持多种硬件平台和开发环境,适合嵌入式开发者和机器学习爱好者低门槛地进行机器学习模型开发。
### 使用Edge Impulse构建机器学习模型
1. 注册Edge Impulse账号,创建一个新项目。
> 我创建的项目名为`RP2040`,项目是公开的,可以在[https://studio.edgeimpulse.com/public/586314/live](https://studio.edgeimpulse.com/public/586314/live)查看。
项目界面如下:
左边是项目导航栏,仪表盘(Dashboard)显示项目的概览信息,数据(Data Acquisition)提供数据采集和标注功能,**Impulse Design**栏目是我们的重头戏,包括特征提取、模型训练和验证等功能,Deployment栏目提供模型部署功能。
2. 数据采集
Edge Impulse Studio提供了数据采集功能,可以通过Web浏览器采集数据。Edge Impulse Studio提供了nano RP2040 Connect的官方固件,可以直接在板子上运行固件与web端连接,采集数据。
>Edge Impluse提供的RP2040固件(UF2)下载地址:[https://cdn.edgeimpulse.com/firmware/raspberry-rp2040.zip](https://cdn.edgeimpulse.com/firmware/raspberry-rp2040.zip)
>该固件源码仓库:[https://github.com/edgeimpulse/firmware-pi-rp2040](https://https://github.com/edgeimpulse/firmware-pi-rp2040)
确保刷上固件后,就可以通过WebUSB连接到网页端直接采集数据啦。我们这里在Sensor下拉菜单中选择`Inertial`,即IMU传感器,填写数据标签,点击`Start sampling`采集数据。我在这里录入了五种动作的数据:`静止`,`画圈`,`上下摆动`,`左右摆动`,`挥舞`,每种动作划分了12条数据(其中两条作为测试集),每条数据持续5秒,共计60条数据。
3. 设计Impulse
数据采集完成后,我们就可以进行特征提取、模型训练和验证了。Edge Impulse Studio提供了多种特征提取器和模型,我们可以根据数据特点选择合适的特征提取器和模型。在这里我们选择`Spectral features`特征提取器和`Classification`分类模型,特征提取器提取频谱特征,分类模型进行动作分类。
接下来我们在Spectral features下设置参数,然后点击`Save Impulse`保存。
生成特征后我们发现录入的五种动作的数据在频谱特征下有明显的区分度,接下来我们就可以训练模型了。
我们直接使用默认的神经网络参数,点击`Save & train`开始训练模型。训练完成后我们可以查看模型的准确率和混淆矩阵。
训练完的模型我们也可以直接在网页上进行模型效果的实时验证,连接开发板进行在线采样后模型在线进行推理并给出结果。
4. 部署模型
模型训练完成后,我们可以部署模型到nano RP2040 Connect板子上。Edge Impulse可以将模型导出为各种常用的库类型。点击`Deployment`栏目,选择`Arduino Library`,然后点击`Build`编译模型库。编译完成后,我们可以下载模型库,然后在Arduino IDE中导入库,库中包含简单的示例代码,编译烧录`rp2040_fusion`即可在板子上运行改模型。
### 代码实现(rp2040_fusion)
```cpp
/* Includes ---------------------------------------------------------------- */
#include
#include //Click here to get the library: http://librarymanager/All#Arduino_LSM6DSOX
enum sensor_status {
NOT_USED = -1,
NOT_INIT,
INIT,
SAMPLED
};
/** Struct to link sensor axis name to sensor value function */
typedef struct{
const char *name;
float *value;
uint8_t (*poll_sensor)(void);
bool (*init_sensor)(void);
int8_t status; // -1 not used 0 used(unitialized) 1 used(initalized) 2 data sampled
} eiSensors;
/* Constant defines -------------------------------------------------------- */
#define CONVERT_G_TO_MS2 9.80665f
#define MAX_ACCEPTED_RANGE 4.0f // starting 03/2022, models are generated setting range to +-2,
// but this example use Arudino library which set range to +-4g.
// If you are using an older model, ignore this value and use 4.0f instead
/** Number sensor axes used */
#define N_SENSORS 7
/* Forward declarations ------------------------------------------------------- */
float ei_get_sign(float number);
static bool ei_connect_fusion_list(const char *input_list);
bool init_IMU(void);
uint8_t poll_acc(void);
uint8_t poll_gyr(void);
uint8_t poll_mag(void);
uint8_t poll_temp(void);
/* Private variables ------------------------------------------------------- */
static const bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal
static float data[N_SENSORS];
static int8_t fusion_sensors[N_SENSORS];
static int fusion_ix = 0;
/* Function declarations --------------------------------------------------- */
void print_inference_result(ei_impulse_result_t result);
/** Used sensors value function connected to label name */
eiSensors sensors[] =
{
"accX", &data[0], &poll_acc, &init_IMU, NOT_USED,
"accY", &data[1], &poll_acc, &init_IMU, NOT_USED,
"accZ", &data[2], &poll_acc, &init_IMU, NOT_USED,
"gyrX", &data[3], &poll_gyr, &init_IMU, NOT_USED,
"gyrY", &data[4], &poll_gyr, &init_IMU, NOT_USED,
"gyrZ", &data[5], &poll_gyr, &init_IMU, NOT_USED,
"temperature", &data[6], &poll_temp, &init_IMU, NOT_USED,
};
/**
* @brief Arduino setup function
*/
void setup()
{
/* Init serial */
Serial.begin(115200);
// comment out the below line to cancel the wait for USB connection (needed for native USB)
while (!Serial);
Serial.println("Edge Impulse Sensor Fusion Inference\r\n");
/* Connect used sensors */
if(ei_connect_fusion_list(EI_CLASSIFIER_FUSION_AXES_STRING) == false) {
ei_printf("ERR: Errors in sensor list detected\r\n");
return;
}
/* Init & start sensors */
for(int i = 0; i < fusion_ix; i++) {
if (sensors[fusion_sensors].status == NOT_INIT) {
sensors[fusion_sensors].status = (sensor_status)sensors[fusion_sensors].init_sensor();
if (!sensors[fusion_sensors].status) {
ei_printf("%s axis sensor initialization failed.\r\n", sensors[fusion_sensors].name);
}
else {
ei_printf("%s axis sensor initialization successful.\r\n", sensors[fusion_sensors].name);
}
}
}
}
/**
* @brief Get data and run inferencing
*/
void loop()
{
ei_printf("\nStarting inferencing in 2 seconds...\r\n");
delay(2000);
if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != fusion_ix) {
ei_printf("ERR: Sensors don't match the sensors required in the model\r\n"
"Following sensors are required: %s\r\n", EI_CLASSIFIER_FUSION_AXES_STRING);
return;
}
ei_printf("Sampling...\r\n");
// Allocate a buffer here for the values we'll read from the sensor
float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };
for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME) {
// Determine the next tick (and then sleep later)
int64_t next_tick = (int64_t)micros() + ((int64_t)EI_CLASSIFIER_INTERVAL_MS * 1000);
for(int i = 0; i < fusion_ix; i++) {
if (sensors[fusion_sensors].status == INIT) {
sensors[fusion_sensors].poll_sensor();
sensors[fusion_sensors].status = SAMPLED;
}
if (sensors[fusion_sensors].status == SAMPLED) {
buffer[ix + i] = *sensors[fusion_sensors].value;
sensors[fusion_sensors].status = INIT;
}
}
int64_t wait_time = next_tick - (int64_t)micros();
if(wait_time > 0) {
delayMicroseconds(wait_time);
}
}
// Turn the raw buffer in a signal which we can the classify
signal_t signal;
int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
if (err != 0) {
ei_printf("ERR:(%d)\r\n", err);
return;
}
// Run the classifier
ei_impulse_result_t result = { 0 };
err = run_classifier(&signal, &result, debug_nn);
if (err != EI_IMPULSE_OK) {
ei_printf("ERR:(%d)\r\n", err);
return;
}
print_inference_result(result);
}
/**
* @brief Go through sensor list to find matching axis name
*
* @param axis_name
* @return int8_t index in sensor list, -1 if axis name is not found
*/
static int8_t ei_find_axis(char *axis_name)
{
int ix;
for(ix = 0; ix < N_SENSORS; ix++) {
if(strstr(axis_name, sensors[ix].name)) {
return ix;
}
}
return -1;
}
/**
* @brief Check if requested input list is valid sensor fusion, create sensor buffer
*
* @param[in] input_list Axes list to sample (ie. "accX + gyrY + magZ")
* @retval false if invalid sensor_list
*/
static bool ei_connect_fusion_list(const char *input_list)
{
char *buff;
bool is_fusion = false;
/* Copy const string in heap mem */
char *input_string = (char *)ei_malloc(strlen(input_list) + 1);
if (input_string == NULL) {
return false;
}
memset(input_string, 0, strlen(input_list) + 1);
strncpy(input_string, input_list, strlen(input_list));
/* Clear fusion sensor list */
memset(fusion_sensors, 0, N_SENSORS);
fusion_ix = 0;
buff = strtok(input_string, "+");
while (buff != NULL) { /* Run through buffer */
int8_t found_axis = 0;
is_fusion = false;
found_axis = ei_find_axis(buff);
if(found_axis >= 0) {
if(fusion_ix < N_SENSORS) {
fusion_sensors[fusion_ix++] = found_axis;
sensors[found_axis].status = NOT_INIT;
}
is_fusion = true;
}
buff = strtok(NULL, "+ ");
}
ei_free(input_string);
return is_fusion;
}
/**
* @brief Return the sign of the number
*
* @param number
* @return int 1 if positive (or 0) -1 if negative
*/
float ei_get_sign(float number) {
return (number >= 0.0) ? 1.0 : -1.0;
}
bool init_IMU(void) {
static bool init_status = false;
if (!init_status) {
init_status = IMU.begin();
}
return init_status;
}
uint8_t poll_acc(void) {
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(data[0], data[1], data[2]);
for (int i = 0; i < 3; i++) {
if (fabs(data) > MAX_ACCEPTED_RANGE) {
data = ei_get_sign(data) * MAX_ACCEPTED_RANGE;
}
}
data[0] *= CONVERT_G_TO_MS2;
data[1] *= CONVERT_G_TO_MS2;
data[2] *= CONVERT_G_TO_MS2;
}
return 0;
}
uint8_t poll_gyr(void) {
if (IMU.gyroscopeAvailable()) {
IMU.readGyroscope(data[3], data[4], data[5]);
}
return 0;
}
uint8_t poll_temp(void) {
if (IMU.temperatureAvailable()) {
int temp;
IMU.readTemperature(temp);
data[6] = temp;
}
return 0;
}
void print_inference_result(ei_impulse_result_t result) {
// Print how long it took to perform inference
ei_printf("Timing: DSP %d ms, inference %d ms, anomaly %d ms\r\n",
result.timing.dsp,
result.timing.classification,
result.timing.anomaly);
ei_printf("Predictions:\r\n");
for (uint16_t i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++) {
ei_printf(" %s: ", ei_classifier_inferencing_categories);
ei_printf("%.5f ", result.classification.value);
}
ei_printf("\r\n");
// Print anomaly result (if it exists)
#if EI_CLASSIFIER_HAS_ANOMALY == 1
ei_printf("Anomaly prediction: %.3f\r\n", result.anomaly);
#endif
}
#if !defined(EI_CLASSIFIER_SENSOR) || (EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_FUSION && EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER)
#error "Invalid model for current sensor"
#endif
```
### 程序说明
该程序使用Edge Impulse SDK进行机器学习推理。代码主要负责进行初始化、传感器数据采集和推理。
在setup函数中,首先初始化串口通信,并等待USB连接。然后调用ei_connect_fusion_list函数连接所需的传感器。该函数解析传感器轴列表,并将匹配的传感器标记为未初始化状态。接下来,程序遍历所有连接的传感器并初始化它们。
loop主循环中首先打印推理开始的提示信息,并延迟两秒。然后检查所需的传感器数量是否与模型匹配,如果不匹配则打印错误信息并返回。接下来,程序开始采样传感器数据,将数据存储在缓冲区中。每次采样后,程序计算下一次采样的时间,并在需要时延迟以保持采样间隔一致。
采样完成后,程序将原始数据缓冲区转换为信号,并调用run_classifier函数进行推理。推理结果通过print_inference_result函数打印,包括推理时间、分类结果和异常检测结果(如果存在)。
传感器初始化和数据采集函数包括init_IMU、poll_acc、poll_gyr和poll_temp。init_IMU函数初始化IMU传感器,poll_acc函数采集加速度数据并进行范围限制和单位转换,poll_gyr函数采集陀螺仪数据,poll_temp函数采集温度数据。
#### 效果展示
静止状态下模型预测idle的可能性接近100%,其他动作的可能性接近0%。
左右平移运动时模型对left-right的预测概率也相当高,能够很好的区分左右平移与左右挥舞。
最后附上作为arduino库导出的分类模型:
## 任务进度
- [x] 搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
- [x] 学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据。
- [x] 学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
- [x] 通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小。
- [x] 通过IMU数据结合机器学习算法,识别运动状态,并通过串口打印。
- 2024-12-07
-
发表了主题帖:
【Follow me第二季第4期】RGB LED显示PDM麦克风收音大小
# 【Follow me第二季第4期】 通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小
## 通过RGB LED显示声音大小
话不多说,我们直接上代码。
### 程序代码
```cpp
#include
#include
#include
#include
#include
/*
1.Blink三色LED / 串口打印Hello DigiKey & EEWorld!
2.调试IMU传感器,通过串口打印六轴原始数据
3.调试PDM麦克风,通过串口打印收音数据和音频波形。
*/
static const char channels = 1; // 麦克风通道数
static const int sampleRate = 16000; // 音频采样率
short sampleBuffer[512]; // 音频缓冲区
volatile int samplesRead = 0; // 音频采样数
int minSoundThreshold = 100; // 动态最小声音检测阈值
#define SMOOTHING_FACTOR 0.9 // 平滑因子
float smoothedSample = 0; // 平滑后的采样值
void onPDMData() { // PDM麦克风数据回调函数
int numSamples = PDM.available(); // 获取可用采样数
if (numSamples > 0) {
PDM.read(sampleBuffer, numSamples);
samplesRead = numSamples / 2; // 16位采样,每个采样占2字节
}
}
void setup() {
// 初始化串口
Serial.begin(115200);
while (!Serial); // 等待串口连接
// 初始化LED引脚
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
// 打印欢迎信息
Serial.println("Hello DigiKey & EEWorld!");
// 初始化IMU传感器
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
// 初始化PDM麦克风
PDM.onReceive(onPDMData);
if (!PDM.begin(channels, sampleRate)) {
Serial.println("Failed to initialize PDM!");
while (1);
}
// 初始化LED_Buildin引脚
pinMode(LED_BUILTIN, OUTPUT);
}
void blinkLEDs() { // 闪烁三色LED
digitalWrite(LEDR, HIGH);
delay(500);
digitalWrite(LEDR, LOW);
digitalWrite(LEDG, HIGH);
delay(500);
digitalWrite(LEDG, LOW);
digitalWrite(LEDB, HIGH);
delay(500);
digitalWrite(LEDB, LOW);
}
void printIMUData() { // 读取IMU传感器数据,共有6个轴
float x, y, z, x_g, y_g, z_g;
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(x, y, z); // 读取加速度数据
IMU.readGyroscope(x_g, y_g, z_g); // 读取陀螺仪数据
Serial.print("Acceleration X: ");
Serial.print(x);
Serial.print(", Y: ");
Serial.print(y);
Serial.print(", Z: ");
Serial.println(z);
Serial.print("Gyroscope X: ");
Serial.print(x_g);
Serial.print(", Y: ");
Serial.print(y_g);
Serial.print(", Z: ");
Serial.println(z_g);
}
}
void printPDMData() { // 读取PDM麦克风数据
for (int i = 0; i < samplesRead; i++) {
Serial.println(sampleBuffer);
}
}
void displaySoundLevelWithAnimation() {
int maxSample = 0;
for (int i = 0; i < samplesRead; i++) {
maxSample = max(maxSample, abs(sampleBuffer));
}
// 平滑处理
smoothedSample = SMOOTHING_FACTOR * smoothedSample + (1 - SMOOTHING_FACTOR) * maxSample;
int targetBrightness = (smoothedSample > minSoundThreshold) ? map(smoothedSample, minSoundThreshold, 32767, 0, 255) : 0;
static int currentBrightness = 0;
Serial.print("maxSample: ");
Serial.print(maxSample);
Serial.print(" smoothedSample: ");
Serial.print(smoothedSample);
Serial.print(" minSoundThreshold: ");
Serial.print(minSoundThreshold);
Serial.print(" targetBrightness: ");
Serial.print(targetBrightness);
Serial.print(" currentBrightness: ");
Serial.println(currentBrightness);
// 渐变动画
int step = 1; // 增加变化步长,降低灵敏度
if (currentBrightness < targetBrightness) {
currentBrightness = min(currentBrightness + step, targetBrightness);
} else if (currentBrightness > targetBrightness) {
currentBrightness = max(currentBrightness - step, targetBrightness);
}
// 根据亮度值设置RGB LED颜色
int brightness = 255 - currentBrightness;
analogWrite(LEDR, brightness);
analogWrite(LEDG, brightness);
analogWrite(LEDB, brightness);
// 根据音量大小点亮LED_Builtin
digitalWrite(LED_BUILTIN, smoothedSample > 2000 ? HIGH : LOW);
}
void loop() {
// 闪烁三色LED
// blinkLEDs();
// 读取IMU传感器数据
// printIMUData();
// 显示声音大小并添加动画
displaySoundLevelWithAnimation();
// 读取PDM麦克风数据
// if (samplesRead) {
// printPDMData();
// samplesRead = 0;
// }
// delay(500);
}
```
### 程序说明
在上一个任务的基础上,我们添加了显示声音大小并添加动画的功能。
1. **初始化部分**:
- 初始化串口通信,设置波特率为115200。
- 初始化LED引脚,包括三色LED和板载LED。
- 初始化IMU传感器和PDM麦克风。
2. **PDM麦克风数据回调函数**:
- `onPDMData`函数用于处理PDM麦克风的数据,将采集到的数据存储在缓冲区中。
3. **显示声音大小并添加动画**:
- `displaySoundLevelWithAnimation`函数用于根据麦克风采集到的音频数据,计算声音的大小,并通过RGB LED和板载LED显示出来。
- 使用平滑因子对采样值进行平滑处理,避免数据波动过大。
- 根据平滑后的采样值,计算目标亮度,并通过渐变动画的方式调整当前亮度。
- 根据亮度值设置RGB LED的颜色,并根据音量大小点亮板载LED。
4. **主循环**:
- 在主循环中调用`displaySoundLevelWithAnimation`函数,不断更新LED的显示效果。
#### 效果展示
[localvideo]b25e63cb98942e1c094cc78fd1f4ea9f[/localvideo]
## 任务进度
- [x] 搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
- [x] 学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据。
- [x] 学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
- [x] 通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小。
- [ ] 通过IMU数据结合机器学习算法,识别运动状态,并通过串口打印。(选做)
- 2024-11-27
-
回复了主题帖:
【Follow me第二季第4期】活动备忘录
lightxixi 发表于 2024-11-27 11:07
可以提一下宝贵意见哈,我们改进~~
那个```flow流程图渲染和[TOC]不好用,在线md编辑器里面混用bbscode没有预览
- 2024-11-25
-
发表了主题帖:
【Follow me第二季第4期】PDM麦克风音频波形打印
# 【Follow me第二季第4期】 学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形
## 学习PDM麦克风技术知识
PDM(Pulse Density Modulation)麦克风是一种数字麦克风,通过PDM信号输出音频数据。PDM麦克风的优点是抗干扰能力强,适用于噪声环境下的音频采集。
### PDM麦克风工作原理
PDM麦克风通过MEMS传感器将声音转换为电信号,然后通过PDM编码器将模拟信号转换为PDM信号。PDM信号是一种脉冲密度调制信号,通过脉冲的密度来表示模拟信号的幅度。
### PDM麦克风接口
通过查阅Arduino Nano RP2040 Connect的原理图,我们可以找到PDM麦克风的接口:
图中PDM麦克风的输出是PDMCLK和PDMDIN两个信号,PDMCLK是PDM时钟信号,PDMDIN是PDM数据信号。
## 调试PDM麦克风
### PDM库
Arduino官方已经提供了PDM库,可以方便地读取PDM麦克风的数据。
>[官方教程](https://docs.arduino.cc/tutorials/nano-rp2040-connect/rp2040-microphone-basics/)
### 通过串口打印收音数据和音频波形
```cpp
#include
#include
#include
static const char channels = 1; // 麦克风通道数
static const int sampleRate = 16000; // 音频采样率
short sampleBuffer[512]; // 音频缓冲区
volatile int samplesRead = 0; // 音频采样数
void onPDMData() { // PDM麦克风数据回调函数
int numSamples = PDM.available(); // 获取可用采样数
if (numSamples > 0) {
PDM.read(sampleBuffer, numSamples);
samplesRead = numSamples/2; // 16位采样,每个采样占2字节
}
}
void setup() {
// 初始化串口
while (!Serial); // 等待串口连接
Serial.begin(115200); // 串口波特率设置为115200
Serial.println("Hello DigiKey & EEWorld !"); // 初次连接到串口时打印欢迎信息
// 初始化PDM麦克风
PDM.onReceive(onPDMData);
if (!PDM.begin(channels, sampleRate)) {
Serial.println("Failed to initialize PDM!");
while (1);
}
}
void printPDMData() { // 读取PDM麦克风数据
for (int i = 0; i < samplesRead; i++) {
Serial.println(sampleBuffer);
}
}
void loop() {
if (samplesRead) {
printPDMData();
samplesRead = 0;
}
delay(500); // 延时500ms, 降低串口输出速率
}
```
#### 效果展示
> 通过串口打印收音数据和音频波形,我们可以看到PDM麦克风采集到的音频数据。
> 使用的串口助手是使用Qt开发的开源软件[SerialTest](https://github.com/wh201906/SerialTest/)。
## 任务进度
- [x] 搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
- [x] 学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据。
- [x] 学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
- [ ] 通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小。(选做)
- [ ] 通过IMU数据结合机器学习算法,识别运动状态,并通过串口打印。(选做)
- 2024-11-24
-
发表了主题帖:
【Follow me第二季第4期】IMU传感器六轴数据打印
# 【Follow me第二季第4期】 学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据
## 学习IMU基础知识
IMU(Inertial Measurement Unit)是一种惯性测量单元,通常包含三轴加速度计和三轴陀螺仪,用于测量物体的加速度和角速度。IMU常用于运动检测、姿态跟踪、导航等领域。
### 加速度计
加速度计是一种测量物体加速度的传感器,通常使用MEMS技术制造。加速度计可以测量物体在三个轴向的加速度,单位是m/s²。
### 陀螺仪
陀螺仪是一种测量物体角速度的传感器,通常使用MEMS技术制造。陀螺仪可以测量物体在三个轴向的角速度,单位是rad/s。
### IMU数据融合
IMU数据融合是将加速度计和陀螺仪的数据进行融合,得到物体的姿态信息。常用的融合算法有卡尔曼滤波、互补滤波、四元数等。
## 调试IMU传感器
Arduino Nano RP2040 Connect集成了ST LSM6DSOXTR 6轴惯性测量单元(IMU),我们可以通过Arduino_LSM6DSOX库读取IMU的数据。
### 安装Arduino_LSM6DSOX库
在PlatformIO Home中搜索Arduino_LSM6DSOX库,点击`Install`安装库:
### 通过串口打印六轴原始数据
```cpp
#include
#include
#include
void setup() {
// 初始化串口
while (!Serial); // 等待串口连接
Serial.begin(115200); // 串口波特率设置为115200
Serial.println("Hello DigiKey & EEWorld !"); // 初次连接到串口时打印欢迎信息
// 初始化IMU
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
}
void loop() {
// 读取IMU数据
float accX, accY, accZ;
float gyroX, gyroY, gyroZ;
IMU.readAcceleration(accX, accY, accZ);
IMU.readGyroscope(gyroX, gyroY, gyroZ);
// 串口打印六轴原始数据
Serial.print("Acceleration: ");
Serial.print(accX);
Serial.print(", ");
Serial.print(accY);
Serial.print(", ");
Serial.println(accZ);
Serial.print("Gyroscope: ");
Serial.print(gyroX);
Serial.print(", ");
Serial.print(gyroY);
Serial.print(", ");
Serial.println(gyroZ);
delay(1000);
}
```
#### 程序流程图
#### 效果展示
## 任务进度
- [x] 搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
- [x] 学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据。
- [ ] 学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
- [ ] 通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小。(选做)
- [ ] 通过IMU数据结合机器学习算法,识别运动状态,并通过串口打印。(选做)
-
发表了主题帖:
【Follow me第二季第4期】搭建环境+点灯+串口打印
# 【Follow me第二季第4期】 搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
[TOC]
## 关于我
大家好,这里是iex123。一眨眼,距离上次参加第一期的活动已经过去两个月了,对技(bai)术(piao)的热情一直没有减退,这次我再次参加第四季的活动,希望能够和大家一起学习和进步。
这次活动的主角是Arduino® Nano RP2040 Connect,这是一款基于Raspberry Pi RP2040微控制器的开发板,它集成了U-blox® Nina W102模块,可以通过Wi-Fi和蓝牙与其他设备进行通信。这款开发板的特点是小巧轻便,集速度计、陀螺仪、RGB LED和麦克风于一体,可玩性很高。
### 认识Arduino® Nano RP2040 Connect
Arduino® Nano RP2040 Connect搭载了功能强大的Raspberry Pi RP2040微控制器,拥有133MHz的32位双核Arm® Cortex®-M0+处理器和264kB的片上SRAM,支持高达16MB的外置Flash存储器。它还配备了U-blox® Nina W102模块,支持Wi-Fi和蓝牙4.2通信。
> 图片来源:[Arduino® Nano RP2040 Connect 引脚说明](https://docs.arduino.cc/resources/pinouts/ABX00053-full-pinout.pdf)
其他资料:
> 开发板电路原理图:[ABX00053-schematics.pdf](https://docs.arduino.cc/resources/schematics/ABX00053-schematics.pdf)
> 开发板手册(英文):[ABX00053-datasheet.pdf](https://docs.arduino.cc/resources/datasheets/ABX00053-datasheet.pdf)
#### 板载外设
- RGB LED:一个三色LED,电路部分是共阳极连接到NINA W102模块的GPIO引脚。
- ST LSM6DSOXTR 6轴惯性测量单元(IMU):一个六轴传感器,包含一个三轴加速度计和一个三轴陀螺仪,常用于运动检测和姿态跟踪。
- ST MP34DT06JTR MEMS麦克风:64dB信噪比的PDM麦克风,效果还可以。
- Microchip® ATECC608A加密协处理器:用于安全存储密钥和加密数据,没接触过,看看其他大佬怎么玩的。
此外,开发板还提供了14个数字引脚和8个模拟引脚,支持UART、SPI和I2C接口,方便DIY项目的扩展和开发。
RP2040特有的PIO(Programmable I/O)引脚可以自己实现I/O时序控制,支持SD卡、I2S、VGA等外设,非常灵活。
### 开发环境搭建
我个人比较喜欢使用Visual Studio Code进行Arduino开发,因此我选择使用作为VSC插件支持的PlatformIO IDE进行开发,其他开发环境搭建方法可以参考[官方文档](https://docs.arduino.cc/tutorials/nano-rp2040-connect/rp2040-01-technical-reference/)。
#### 安装PlatformIO IDE
使用快捷键`Ctrl+P`打开VSC命令面板,输入`ext install platformio.platformio-ide`安装PlatformIO IDE:
#### 新建项目
打开PlatformIO Home,点击`Open`打开一个项目,选择`New Project`,选择`Arduino Nano RP2040 Connect`开发板,点击`Finish`创建项目:
> 注意:建立项目时Platformio会自动从`registry.platformio.org`源下载`Platforms`中的`Raspberry Pi RP2040`开发环境包(包含gcc编译工具链),由于网络原因可能会下载失败,可以尝试多次下载或者使用代理。
PlatformIO自带库管理器,可以方便地搜索和安装库,麦克风和IMU的库都可以在这里找到。
### 开启第一步:Blink三色LED / 串口打印Hello DigiKey & EEWorld!
#### 三色LED
三色LED的引脚分别连接到NINA W102模块的GPIO引脚,我们可以通过控制引脚输出高低电平来控制LED的亮灭。
> 三色LED的引脚分别是GPIO 25、GPIO 26和GPIO 27, 共阳极连接,在WIFININA库中定义了宏`LEDR`, `LEDG`和`LEDB`, 分别对应三色LED的红、绿、蓝引脚。
```cpp
#include
#include
void setup() {
// 初始化三色LED引脚
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
}
void loop() {
// 交替点亮三色LED
digitalWrite(LEDR, HIGH);
delay(500);
digitalWrite(LEDR, LOW);
digitalWrite(LEDG, HIGH);
delay(500);
digitalWrite(LEDG, LOW);
digitalWrite(LEDB, HIGH);
delay(500);
digitalWrite(LEDB, LOW);
}
```
#### 串口打印
串口打印是调试程序的重要手段,我们可以通过串口打印输出调试信息,查看程序运行状态。
> Arduino Nano RP2040 Connect的串口可以直接通过USB连接到计算机,可以使用`Serial`对象进行串口通信。
```cpp
#include
void setup() {
// 初始化串口
Serial.begin(9600);
}
void loop() {
// 串口打印Hello DigiKey & EEWorld!
Serial.println("Hello DigiKey & EEWorld!");
delay(1000);
}
```
#### 结合三色LED和串口打印
我们可以将三色LED的点亮状态和串口打印结合起来,再加上一点小细节。
```cpp
#include
#include
void setup() {
// 初始化三色LED引脚
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
// 初始化串口
while (!Serial); // 等待串口连接
Serial.begin(115200); // 串口波特率设置为115200
Serial.println("Hello DigiKey & EEWorld !"); // 初次连接到串口时打印欢迎信息
}
// 将三色LED点亮封装成一个函数
void BlinkLED(int pin, int delay_ms) {
digitalWrite(pin, HIGH);
delay(delay_ms);
digitalWrite(pin, LOW);
}
void loop() {
// 交替点亮三色LED
BlinkLED(LEDR, 500);
BlinkLED(LEDG, 500);
BlinkLED(LEDB, 500);
// 在循环中串口打印Hello DigiKey & EEWorld!
//Serial.println("Hello DigiKey & EEWorld!");
}
```
#### 效果展示
[localvideo]1c315b247abf97706ed2f600e39697c8[/localvideo]
### 其他要说明的内容
PlatformIO IDE下载的Arduino Nano RP2040 Connect开发环境实际上是arduino-mbed-os,这是一个基于Mbed OS的Arduino核心,支持Arduino库和Mbed OS库。
`platformio.ini`文件中的`lib_deps`字段用于指定项目依赖的库,可以通过`lib_deps`字段下载指定版本的库,也可以通过`lib_deps`字段下载指定GitHub仓库的库。
例如,下载WiFiNINA库和Arduino_LSM6DSOX库:
```ini
[env:nanorp2040connect]
platform = raspberrypi
board = nanorp2040connect
framework = arduino
lib_deps =
arduino-libraries/WiFiNINA@^1.8.14
arduino-libraries/Arduino_LSM6DSOX@^1.1.2
; arduino-libraries/ArduinoSound@^0.2.1 ; 注释掉的库
```
## 任务进度
- [x] 搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
- [ ] 学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据。
- [ ] 学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
- [ ] 通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小。(选做)
- [ ] 通过IMU数据结合机器学习算法,识别运动状态,并通过串口打印。(选做)
- 2024-11-23
-
回复了主题帖:
【Follow me第二季第4期】进阶任务二 imu机器学习识别运动状态
你这个示例程序就是把量化好的模型在运行的时候塞给传感器自带的机器学习核心让它处理传感器数据,直接跳过准备步骤来到部署了
哥们你找的资料还挺好用,我都没注意到有个机器学习核心
- 2024-11-21
-
回复了主题帖:
入围名单公布:嵌入式工程师AI挑战营(进阶)的挑战者们,领取板卡啦
个人信息已确认,领取板卡,可继续完成任务。
- 2024-11-19
-
回复了主题帖:
嵌入式工程师AI挑战营(进阶):在RV1106部署InsightFace算法的多人实时人脸识别实战
申请理由:
我是一名电子信息工程大三学生,对深度学习有一定的了解,曾经使用过Scikit-learn框架进行学习和实验。熟悉C++、Python等主流编程语言,擅长ai辅助编程。我希望通过这次机会接触嵌入式AI的实际工程项目,深入了解如何在资源有限的嵌入式环境中部署和优化AI算法,从而提升自己的专业技能和解决实际问题的能力。
简述InsightFace和如何在RV1106上部署该算法的思路:
InsightFace是一个开源的人脸识别库,具有先进的2D和3D人脸分析算法,能够将人脸图像转化为特征向量,从而实现高效且准确的面部识别。该库支持多种推理后端(如CPU、GPU、NPU),并提供了SDK和API接口,方便用户将其集成到自己的应用中。对于嵌入式设备RV1106,我们需要考虑设备的计算能力及资源限制,因此在部署时需要优化算法以提高效率。
部署的具体思路如下:
1. 交叉编译和环境配置:RV1106通常运行Linux系统,需要配置适合该平台的交叉编译工具链。编译适用于RV1106的二进制文件,并确保所需的依赖库(如Python 3、OpenCV、NumPy)已正确安装且能支持硬件加速。
2. 模型优化:由于RV1106是嵌入式设备,计算能力有限,需要对InsightFace的模型进行量化、裁剪,或者转化为rkkn等优化格式,以便更高效地在硬件上运行。
3. 人脸检测和对齐:可以使用轻量级的检测算法,如RetinaFace,首先对视频流进行人脸检测。检测到的人脸区域通过人脸对齐算法(如SDUNet)进行标准化,确保后续识别精度。
4. 实时视频流处理:使用OpenCV或其他视频流处理框架,捕获摄像头输入,并实时进行人脸检测和识别。每帧图像中的人脸会被提取出来,进行特征向量的提取。
5. 身份匹配:通过提取的人脸特征向量,可以使用基于最近邻(KNN)或支持向量机(SVM)的算法进行比对,从而确定每张人脸的身份。
计划部署的应用:
在此基础上,我打算将该系统应用于宿舍迎宾铃,识别到特定人物时播放欢迎语音。通过实时识别来实现自动化迎宾的功能。
- 2024-09-01
-
加入了学习《【Follow me】第二季第一期任务汇总》,观看 任务汇总提交
-
发表了主题帖:
【Follow me】第二季第一期任务汇总
本帖最后由 iexplore123 于 2024-9-1 04:28 编辑
# 【Follow_me】第二季第一期任务汇总
![](https://www.eeworld.com.cn/huodong/digikey_follow_me_2024/image/banner1-1.png)
[localvideo]a0aa117c7978d54c939af6f49629edef[/localvideo]
[EE大学堂](https://training.eeworld.com.cn/course/68620)
## 1. 任务简介
大家好,这里是iex123,我来交作业了。本期任务是【Follow_me】第二季第一期,任务主要是通过板载传感器和LED灯,实现环境温度和光线检测,接近检测,不倒翁运动过程中的灯光效果,以及可穿戴装饰的音频频谱动画效果。
### 1.1 使用的硬件
- Adafruit Circuit Playground Express
- 电池(可选)
- 电脑(Win11)
### 1.2 使用的软件
- VSCode
- PlatformIO
- Adafruit_CircuitPlayground库
## 2. 任务进度
- [x] [入门任务:开发环境搭建,板载LED点亮](https://bbs.eeworld.com.cn/thread-1289127-1-1.html)
>使用PlatformIO搭建开发环境,通过Arduino框架控制板载LED点亮
- [x] [基础任务一:控制板载炫彩LED,跑马灯点亮和颜色变换](https://bbs.eeworld.com.cn/thread-1289127-1-1.html)
>在入门任务的基础上,通过控制板载炫彩LED实现跑马灯效果和颜色变换
- [X] [基础任务二:监测环境温度和光线,通过板载LED展示舒适程度](https://bbs.eeworld.com.cn/thread-1289127-1-1.html)
>通过板载温度传感器和光敏传感器检测环境温度和光线强度,并通过板载LED展示舒适程度
- [X] [基础任务三:接近检测——设定安全距离并通过板载LED展示,检测到入侵时,发起声音报警](https://bbs.eeworld.com.cn/thread-1289127-1-1.html)
>通过板载光线传感器或红外ADC检测距离,检测到入侵时,通过板载蜂鸣器发起声音报警
- [x] [进阶任务:制作不倒翁——展示不倒翁运动过程中的不同灯光效果](https://bbs.eeworld.com.cn/thread-1291466-1-1.html)
>通过板载加速度计检测不倒翁的俯仰角和横滚角,通过LED展示不同灯光效果
- [_] [创意任务(选做,选择其中一个或多个都可)]
- [x] [创意任务一:有创意的可穿戴装饰——可结合多种传感器和灯光效果展示](https://bbs.eeworld.com.cn/thread-1291469-1-1.html)
>通过板载麦克风检测环境声音,通过板载LED展示
- [ ] 创意任务二:章鱼哥——章鱼哥的触角根据环境声音的大小,章鱼哥的触角可舒展或者收缩
- [ ] 创意任务三:水果钢琴——通过触摸水果弹奏音乐,并配合灯光效果
## 3. 任务详情
### 3.1 入门任务:开发环境搭建,板载LED点亮
#### 3.1.1 环境搭建
1. 下载安装VSCode
2. 安装PlatformIO插件
3. 创建项目
4. 安装Adafruit_CircuitPlayground库
5. 编写代码
#### 3.1.2 板载LED点亮
[localvideo]9ba1e2fae92e95ba727aa22cb82b679c[/localvideo]
代码流程图如下:
通过Adafruit_CircuitPlayground库简单初始化板子之后,点亮板载LED,延时500ms后熄灭LED,达到红色闪烁的效果。
### 3.2 基础任务一:控制板载炫彩LED,跑马灯点亮和颜色变换
[localvideo]57ca9938291803ffac6ddb18edd54c55[/localvideo]
[localvideo]9ac1bd10b7ff54765fce0d5e93e986a4[/localvideo]
代码流程图如下:
通过检测滑动开关是否打开,轮流点亮板载LED为红色、绿色、蓝色或彩虹色流动。
### 3.3 基础任务二:监测环境温度和光线,通过板载LED展示舒适程度
代码流程图如下:
通过获取环境温度和光线强度,通过if语句判断温度和光线强度是否大于设定值,设置LED为红色、绿色或蓝色。
### 3.4 基础任务三:接近检测——设定安全距禀并通过板载LED展示,检测到入侵时,发起声音报警
[localvideo]e4f7fa82eaf2fd6ed86a92a99f7bf5c2[/localvideo]
代码流程图如下:
通过初始化红外ADC,发射红外,通过if语句判断接近传感器的值是否大于设定值,设置LED颜色,发出声音报警。
### 3.5 进阶任务:制作不倒翁——展示不倒翁运动过程中的不同灯光效果
[localvideo]af74e278de411a948cae5a6777a4e65d[/localvideo]
代码流程图如下:
通过获取加速度计数据,计算俯仰角和横滚角,映射俯仰角和横滚角到颜色rgb,设置LED颜色,显示LED颜色。
### 3.6 创意任务一:有创意的可穿戴装饰——可结合多种传感器和灯光效果展示
[localvideo]febbab6a0d832c3d36afb0fdd1a3a836[/localvideo]
代码流程图如下:
通过获取麦克风传感器的数据,进行FFT变换,获取音频频谱数据,获取音量大小,根据频谱数据和音量大小设置LED颜色分量,播放LED动画。
## 4. 任务总结
本期任务主要是通过板载传感器和LED灯,实现了环境温度和光线检测,接近检测,不倒翁运动过程中的灯光效果,以及可穿戴装饰的音频频谱动画效果。在任务中,我们学习了如何使用板载传感器和LED灯,如何通过if语句判断传感器的值,如何通过颜色rgb设置LED灯颜色,如何通过音频频谱数据设置LED颜色分量,如何通过FFT变换获取音频频谱数据等。
非常感谢得捷和EEWORLD论坛为我们提供了这次的学习机会,我们在这次的学习中学到了很多知识,也收获了很多快乐,希望在接下来的学习中,我们可以更好的学习和进步。
## 5. 代码下载
[附件下载中心](https://download.eeworld.com.cn/detail/iexplore123/634237 "下载中心")
------------
感谢阅读。
-
加入了学习《得捷Follow me第二季第1期视频》,观看 得捷Follow me第二季第1期视频
- 2024-08-31
-
上传了资料:
得捷followme第二季第一期Adafruit项目代码
- 2024-08-30
-
上传了资料:
得捷followme第四季第一期项目文件
- 2024-08-29
-
加入了学习《【Follow me第二季第1期】汇总任务报告》,观看 【Follow me第二季第1期】汇总任务报告