Add initial board, HAL, and executor modules
This commit is contained in:
1 parent
3b9e129c88
commit
0b2eebe76d
82 files changed
+20611
No files matched your search
@@ -0,0 +1,625 @@
|
||||
#include "gyroscope.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
|
||||
Gyroscope::Gyroscope()
|
||||
{
|
||||
bus_handle_ = nullptr;
|
||||
on_shake_callback_ = nullptr; // 初始化回调函数
|
||||
on_pickup_callback_ = nullptr; // 初始化拿起回调函数
|
||||
on_putdown_callback_ = nullptr; // 初始化放置回调函数
|
||||
on_tilt_callback_ = nullptr; // 初始化倾斜回调函数
|
||||
timer_handle_ = nullptr; // 初始化定时器句柄
|
||||
pGyroscopeTaskStackBuffer_ = nullptr;
|
||||
pxGyroscopeTaskBuffer_ = nullptr;
|
||||
|
||||
// 初始化滤波相关变量
|
||||
last_filtered_x_ = 0;
|
||||
last_filtered_y_ = 0;
|
||||
last_filtered_z_ = 0;
|
||||
is_first_sample_ = true;
|
||||
}
|
||||
|
||||
Gyroscope::~Gyroscope()
|
||||
{
|
||||
// 删除定时器
|
||||
DeleteTimer();
|
||||
|
||||
if (pGyroscopeTaskStackBuffer_) {
|
||||
free(pGyroscopeTaskStackBuffer_);
|
||||
pGyroscopeTaskStackBuffer_ = nullptr;
|
||||
}
|
||||
if (pxGyroscopeTaskBuffer_) {
|
||||
vPortFree(pxGyroscopeTaskBuffer_);
|
||||
pxGyroscopeTaskBuffer_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建500ms周期定时器
|
||||
* @return esp_err_t 创建结果
|
||||
*/
|
||||
esp_err_t Gyroscope::CreateTimer()
|
||||
{
|
||||
if (timer_handle_ != nullptr) {
|
||||
ESP_LOGW(TAG_GYROSCOPE, "定时器已存在");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// 配置定时器参数
|
||||
esp_timer_create_args_t timer_args = {};
|
||||
timer_args.callback = &TimerCallback; // 静态回调函数
|
||||
timer_args.arg = this; // 传入实例指针
|
||||
timer_args.name = "gyro_timer"; // 定时器名称
|
||||
timer_args.dispatch_method = ESP_TIMER_TASK; // 使用任务调度
|
||||
timer_args.skip_unhandled_events = false; // 不跳过未处理事件
|
||||
|
||||
// 创建定时器
|
||||
esp_err_t err = esp_timer_create(&timer_args, &timer_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "创建定时器失败: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 启动定时器,500ms周期重复
|
||||
err = esp_timer_start_periodic(timer_handle_, 50000); // 50000微秒 = 50ms 20hz
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "启动定时器失败: 0x%x", err);
|
||||
esp_timer_delete(timer_handle_);
|
||||
timer_handle_ = nullptr;
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "50ms周期定时器创建并启动成功");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 停止并删除定时器
|
||||
*/
|
||||
void Gyroscope::DeleteTimer()
|
||||
{
|
||||
if (timer_handle_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 停止定时器
|
||||
esp_err_t err = esp_timer_stop(timer_handle_);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "停止定时器失败: 0x%x", err);
|
||||
}
|
||||
|
||||
// 删除定时器
|
||||
err = esp_timer_delete(timer_handle_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "删除定时器失败: 0x%x", err);
|
||||
}
|
||||
|
||||
timer_handle_ = nullptr;
|
||||
ESP_LOGI(TAG_GYROSCOPE, "定时器已删除");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 静态定时器回调函数
|
||||
* @param arg 传入的Gyroscope实例指针
|
||||
*/
|
||||
void Gyroscope::TimerCallback(void* arg)
|
||||
{
|
||||
Gyroscope* gyroscope = static_cast<Gyroscope*>(arg);
|
||||
if (gyroscope) {
|
||||
gyroscope->TimerInterruptHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 定时器中断处理函数
|
||||
* 每50ms调用一次,可以在这里执行周期性任务
|
||||
*/
|
||||
void Gyroscope::TimerInterruptHandler()
|
||||
{
|
||||
// 在这里添加定时器中断处理逻辑
|
||||
// 例如:读取传感器数据、检测动作、发送状态等
|
||||
AccelerationData accel_data_ = {0};
|
||||
|
||||
esp_err_t err = GetAcceleration(&accel_data_);
|
||||
if (err == ESP_OK) {
|
||||
// 根据实际安装方式重新定义姿态判断
|
||||
// 平放状态:Y轴接近±1g(因为Y轴垂直于桌面),X和Z轴接近0
|
||||
bool is_flat = (fabs(accel_data_.y) > 0.85 && fabs(accel_data_.y) < 1.15) &&
|
||||
(fabs(accel_data_.x) < 0.15 && fabs(accel_data_.z) < 0.15);
|
||||
|
||||
// 手持状态:Y轴接近0,X和Z轴中至少有一个有明显值
|
||||
bool is_held = (fabs(accel_data_.y) < 0.7) &&
|
||||
(fabs(accel_data_.x) > 0.15 || fabs(accel_data_.z) > 0.15);
|
||||
|
||||
// 计算合成加速度(总加速度大小)
|
||||
float total_accel = sqrt(accel_data_.x * accel_data_.x +
|
||||
accel_data_.y * accel_data_.y +
|
||||
accel_data_.z * accel_data_.z);
|
||||
|
||||
// 计算与上次合成加速度的差值(加速度变化量)
|
||||
float total_accel_diff = fabs(total_accel - total_accel_last_);
|
||||
|
||||
// 计算Y轴加速度变化
|
||||
float y_diff = accel_data_.y - accel_data_y_last_;
|
||||
|
||||
// 检测是否处于平放稳定状态
|
||||
if(is_flat) {
|
||||
stable_count_++;
|
||||
if(stable_count_ >= 8) { // 连续8次检测到平放状态(400ms),减少误判
|
||||
stable_count_ = 8; // 防止溢出
|
||||
if(!is_stable_) {
|
||||
ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到稳定平放状态 (x:%.2f, y:%.2f, z:%.2f, total:%.2f)",
|
||||
accel_data_.x, accel_data_.y, accel_data_.z, total_accel);
|
||||
is_stable_ = true;
|
||||
is_lifted_ = false; // 重置拿起状态
|
||||
putdown_count_ = 0; // 重置放置计数器
|
||||
lift_count_ = 0; // 重置拿起计数器
|
||||
|
||||
// 调用放置回调
|
||||
if (on_putdown_callback_) {
|
||||
on_putdown_callback_();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
stable_count_ = 0; // 不在范围内则重置稳定计数器
|
||||
|
||||
// 如果之前是稳定状态,检测是否有拿起动作
|
||||
if(is_stable_) {
|
||||
// 检测拿起动作的多种特征:
|
||||
// 1. Y轴从接近1g变为接近0g(位置变化)
|
||||
// 2. 合成加速度有显著变化(表示有加速度)
|
||||
bool y_change_indicates_lift = fabs(y_diff) > 0.25;
|
||||
bool total_accel_change_indicates_lift = total_accel_diff > 0.3; // 检测加速度突变
|
||||
|
||||
if(y_change_indicates_lift || total_accel_change_indicates_lift) {
|
||||
lift_count_++;
|
||||
if(lift_count_ >= 1) { // 降低拿起检测阈值,提高灵敏度
|
||||
ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到拿起动作 (x:%.2f, y:%.2f, z:%.2f, total:%.2f, y_diff:%.2f, accel_diff:%.2f)",
|
||||
accel_data_.x, accel_data_.y, accel_data_.z, total_accel, y_diff, total_accel_diff);
|
||||
is_stable_ = false; // 重置状态
|
||||
is_lifted_ = true; // 设置拿起状态
|
||||
lift_count_ = 0;
|
||||
stable_count_ = 0;
|
||||
|
||||
// 调用拿起回调
|
||||
if (on_pickup_callback_) {
|
||||
on_pickup_callback_();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lift_count_ = 0; // 变化不符合预期,重置拿起计数器
|
||||
}
|
||||
}
|
||||
// 如果之前是被拿起状态,检测是否有放置动作
|
||||
else if(is_lifted_) {
|
||||
// 检测从手持到平放的变化 - Y轴从接近0g变为接近1g
|
||||
bool y_change_indicates_putdown = (y_diff > 0.25 && y_diff < 0.80);
|
||||
|
||||
if(y_change_indicates_putdown) {
|
||||
putdown_count_++;
|
||||
if(putdown_count_ >= 3) { // 连续3次检测到缓慢变化
|
||||
ESP_LOGI(TAG_GYROSCOPE, "定时器: 检测到缓慢放置动作 (x:%.2f, y:%.2f, z:%.2f, total:%.2f, y_diff:%.2f)",
|
||||
accel_data_.x, accel_data_.y, accel_data_.z, total_accel, y_diff);
|
||||
is_lifted_ = false; // 重置拿起状态
|
||||
putdown_count_ = 0;
|
||||
|
||||
// 调用放置回调
|
||||
if (on_putdown_callback_) {
|
||||
on_putdown_callback_();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
putdown_count_ = 0; // 变化不符合预期,重置放置计数器
|
||||
}
|
||||
}
|
||||
|
||||
// 检测倾斜动作 - 仅当手持时才触发倾斜
|
||||
if (is_held && (fabs(accel_data_.x) > 0.3f || fabs(accel_data_.z) > 0.3f)) {
|
||||
// 检测到倾斜,调用倾斜回调
|
||||
if (on_tilt_callback_) {
|
||||
on_tilt_callback_();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 保存当前值作为下一次的上一次值
|
||||
accel_data_y_last_ = accel_data_.y;
|
||||
total_accel_last_ = total_accel;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief 注册摇晃检测回调函数
|
||||
*
|
||||
* @param callback 当检测到摇晃时调用的回调函数
|
||||
*/
|
||||
void Gyroscope::OnShake(std::function<void()> callback)
|
||||
{
|
||||
on_shake_callback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册拿起检测回调函数
|
||||
*
|
||||
* @param callback 当检测到设备被拿起时调用的回调函数
|
||||
*/
|
||||
void Gyroscope::OnPickUp(std::function<void()> callback)
|
||||
{
|
||||
on_pickup_callback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册放置检测回调函数
|
||||
*
|
||||
* @param callback 当检测到设备被放置时调用的回调函数
|
||||
*/
|
||||
void Gyroscope::OnPutDown(std::function<void()> callback)
|
||||
{
|
||||
on_putdown_callback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册倾斜检测回调函数
|
||||
*
|
||||
* @param callback 当检测到设备倾斜时调用的回调函数
|
||||
*/
|
||||
void Gyroscope::OnTilt(std::function<void()> callback)
|
||||
{
|
||||
on_tilt_callback_ = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 静态中断处理函数
|
||||
*
|
||||
* @param arg 传入的Gyroscope实例指针
|
||||
*/
|
||||
void IRAM_ATTR Gyroscope::GpioIsrHandler(void* arg)
|
||||
{
|
||||
Gyroscope* gyroscope = static_cast<Gyroscope*>(arg);
|
||||
if (gyroscope) {
|
||||
gyroscope->interrupt_flag_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向陀螺仪寄存器写入数据
|
||||
*
|
||||
* @param reg 寄存器地址
|
||||
* @param data 要写入的数据
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::WriteRegister(uint8_t reg, uint8_t data)
|
||||
{
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "I2C总线未初始化");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return i2c_bus_write_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, &data, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从陀螺仪寄存器读取数据
|
||||
*
|
||||
* @param reg 寄存器地址
|
||||
* @param data 读取到的数据指针
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::ReadRegister(uint8_t reg, uint8_t* data)
|
||||
{
|
||||
if (bus_handle_ == nullptr || data == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "参数错误或I2C总线未初始化");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return i2c_bus_read_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, data, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 批量读取陀螺仪寄存器数据
|
||||
*
|
||||
* @param reg 起始寄存器地址
|
||||
* @param data 读取到的数据指针
|
||||
* @param length 要读取的字节数
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::ReadRegisters(uint8_t reg, uint8_t* data, size_t length)
|
||||
{
|
||||
if (bus_handle_ == nullptr || data == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "参数错误或I2C总线未初始化");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return i2c_bus_read_bytes(bus_handle_, GYROSCOPE_I2C_SLAVE_ADDR << 1, ®, 1, data, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化陀螺仪中断GPIO
|
||||
*
|
||||
* @param gpio_num 要初始化的GPIO引脚号
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::InterruptGpioInit(gpio_num_t gpio_num)
|
||||
{
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_POSEDGE; // 上升沿触发
|
||||
io_conf.pin_bit_mask = (1ULL<<gpio_num);
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; // 禁用上拉,因为INT1已经是推挽输出
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; // 启用下拉
|
||||
|
||||
esp_err_t err = gpio_config(&io_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "GPIO配置失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 配置中断服务
|
||||
err = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3 | ESP_INTR_FLAG_IRAM);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "GPIO中断服务安装失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 注册中断处理函数
|
||||
err = gpio_isr_handler_add(gpio_num, GpioIsrHandler, this);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "GPIO中断处理函数添加失败,错误码: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 清除任何待处理的中断
|
||||
gpio_intr_disable(gpio_num);
|
||||
gpio_intr_enable(gpio_num);
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "GPIO%d中断初始化完成", gpio_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清除中断标志
|
||||
*
|
||||
* 该函数会读取唤醒源寄存器和功能源寄存器来清除中断标志
|
||||
*
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::ClearInterruptFlags()
|
||||
{
|
||||
esp_err_t err;
|
||||
uint8_t wake_up_src = 0;
|
||||
uint8_t func_src1 = 0;
|
||||
// 读取唤醒源寄存器和功能源寄存器来清除中断
|
||||
err = ReadRegister(WAKE_UP_SRC, &wake_up_src);
|
||||
if (err != ESP_OK) return err;
|
||||
err = ReadRegister(FUNC_SRC1, &func_src1);
|
||||
if (err != ESP_OK) return err;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化陀螺仪
|
||||
*
|
||||
* @param bus_handle I2C总线句柄
|
||||
* @return esp_err_t ESP_OK表示成功
|
||||
*/
|
||||
esp_err_t Gyroscope::Init(i2c_bus_handle_t bus_handle)
|
||||
{
|
||||
bus_handle_ = bus_handle;
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "I2C总线句柄为空");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "开始初始化陀螺仪...");
|
||||
|
||||
// 1. 验证设备连接和通信
|
||||
uint8_t who_am_i = 0;
|
||||
esp_err_t err = ReadRegister(0x0F, &who_am_i); // WHO_AM_I寄存器
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "无法读取陀螺仪ID: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (who_am_i != 0x6A) { // LSM6DS3TR-C的WHO_AM_I值
|
||||
ESP_LOGE(TAG_GYROSCOPE, "设备ID不匹配,期望0x6A,实际0x%02X", who_am_i);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG_GYROSCOPE, "陀螺仪设备ID验证成功: 0x%02X", who_am_i);
|
||||
|
||||
// 2. 初始化中断引脚
|
||||
err = InterruptGpioInit(GYROSCOPE_INPUT_PIN_SEL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "中断引脚初始化失败: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
ESP_LOGI(TAG_GYROSCOPE, "开始配置唤醒中断...");
|
||||
|
||||
// 1. 软件复位陀螺仪
|
||||
err = WriteRegister(CTRL3_C, 0x01); // SW_RESET
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // 等待复位完成
|
||||
|
||||
// 3. 配置加速度计: 104Hz ODR, ±2g满量程
|
||||
err = WriteRegister(CTRL1_XL, 0x50); // 0b01010000 - 104Hz ODR, ±2g
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 4. 配置陀螺仪: 104Hz ODR, ±125dps满量程
|
||||
err = WriteRegister(CTRL2_G, 0x50); // 0b01010000
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 5. 配置控制寄存器3: 高电平有效,推挽输出
|
||||
err = WriteRegister(CTRL3_C, 0x44); // 0b01000100
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 6. 禁用陀螺仪低功耗模式
|
||||
err = WriteRegister(CTRL7_G, 0x00); // 禁用低功耗模式
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 7. 配置唤醒功能: 启用X轴的唤醒检测
|
||||
err = WriteRegister(TAP_CFG, 0x81); // 0b10000000 - 仅启用高通滤波器
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 8. 配置唤醒阈值: 非常灵敏的设置
|
||||
err = WriteRegister(WAKE_UP_THS, 0x3F); // 31.25mg - 最灵敏的阈值
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 9. 配置唤醒持续时间: 6个ODR周期
|
||||
err = WriteRegister(WAKE_UP_DUR, 0x06);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 10. 配置中断1路由: 将唤醒中断路由到INT1
|
||||
err = WriteRegister(MD1_CFG, 0x20); // 0b00100000 - 仅唤醒中断到INT1
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 11. 配置中断2路由: 禁用所有中断
|
||||
err = WriteRegister(MD2_CFG, 0x00);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 12. 配置INT1_CTRL: 启用唤醒中断到INT1
|
||||
err = WriteRegister(INT1_CTRL, 0x20); // 0b00100000
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 13. 启用嵌入式功能
|
||||
err = WriteRegister(CTRL10_C, 0x3C); // 0b00111000
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// 14. 等待配置生效
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
CreateTimer();
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "陀螺仪唤醒中断配置完成");
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "陀螺仪初始化完成");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建陀螺仪读取任务
|
||||
*
|
||||
* 该任务会周期性读取陀螺仪数据并处理中断
|
||||
*/
|
||||
void Gyroscope::CreateGyroReadTask()
|
||||
{
|
||||
if (bus_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "I2C总线未初始化,无法启动陀螺仪任务");
|
||||
return;
|
||||
}
|
||||
|
||||
xTaskCreateWithCaps(
|
||||
GyroReadTask,
|
||||
"gyro_read_task",
|
||||
4096,
|
||||
this,
|
||||
5, // Reduced priority to allow other tasks to run
|
||||
&xGyroscopeTaskHandle_,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT
|
||||
);
|
||||
|
||||
if (xGyroscopeTaskHandle_ == NULL) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "Failed to create static gyro read task");
|
||||
} else {
|
||||
ESP_LOGI(TAG_GYROSCOPE, "Static gyro read task created successfully");
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t Gyroscope::ReadRawAcceleration(int16_t* x, int16_t* y, int16_t* z) {
|
||||
// 1. 参数合法性检查
|
||||
if (x == nullptr || y == nullptr || z == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "参数为空指针");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// 2. 读取原始加速度数据(6字节:X_L/X_H/Y_L/Y_H/Z_L/Z_H)
|
||||
uint8_t accel_data_[6] = {0};
|
||||
esp_err_t err = ReadRegisters(ACCEL_X_L, accel_data_, 6);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "读取加速度寄存器失败: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// 3. 组合高低字节为int16_t(二进制补码,适配传感器输出)
|
||||
int16_t current_raw_x = (int16_t)((accel_data_[1] << 8) | accel_data_[0]);
|
||||
int16_t current_raw_y = (int16_t)((accel_data_[3] << 8) | accel_data_[2]);
|
||||
int16_t current_raw_z = (int16_t)((accel_data_[5] << 8) | accel_data_[4]);
|
||||
|
||||
// 4. 一阶α滤波(整数版,无浮点运算,避免精度丢失)
|
||||
int16_t filtered_x, filtered_y, filtered_z;
|
||||
if (is_first_sample_) {
|
||||
// 首次采样:直接初始化滤波值为原始值
|
||||
filtered_x = current_raw_x;
|
||||
filtered_y = current_raw_y;
|
||||
filtered_z = current_raw_z;
|
||||
is_first_sample_ = false; // 标记首次采样完成
|
||||
} else {
|
||||
// 核心滤波公式(整数版):α*原始值 + (1-α)*上一次滤波值
|
||||
// WEIGHTFACTOR=0.9; (1-WEIGHTFACTOR)=0.1
|
||||
const int32_t weight_scaled = (int32_t)(WEIGHTFACTOR * 10); // 9
|
||||
const int32_t inv_weight_scaled = 10 - weight_scaled; // 1
|
||||
|
||||
filtered_x = (weight_scaled * (int32_t)current_raw_x +
|
||||
inv_weight_scaled * last_filtered_x_) / 10;
|
||||
filtered_y = (weight_scaled * (int32_t)current_raw_y +
|
||||
inv_weight_scaled * last_filtered_y_) / 10;
|
||||
filtered_z = (weight_scaled * (int32_t)current_raw_z +
|
||||
inv_weight_scaled * last_filtered_z_) / 10;
|
||||
}
|
||||
|
||||
// 5. 转换为int16_t输出(filtered_x/y/z是int32_t,范围仍在int16_t内)
|
||||
*x = (int16_t)filtered_x;
|
||||
*y = (int16_t)filtered_y;
|
||||
*z = (int16_t)filtered_z;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Gyroscope::GetAcceleration(AccelerationData* data) {
|
||||
if (data == nullptr) {
|
||||
ESP_LOGE(TAG_GYROSCOPE, "数据指针为空");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
int16_t raw_x, raw_y, raw_z;
|
||||
esp_err_t err = ReadRawAcceleration(&raw_x, &raw_y, &raw_z);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// 转换公式:加速度(g) = 原始值 × 灵敏度(mg/LSB) × 10^-3
|
||||
data->x = raw_x * ACCEL_SENSITIVITY_2G / 1000.0f;
|
||||
data->y = raw_y * ACCEL_SENSITIVITY_2G / 1000.0f;
|
||||
data->z = raw_z * ACCEL_SENSITIVITY_2G / 1000.0f;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 陀螺仪读取任务
|
||||
* Y轴立起 Z轴躺下
|
||||
* 该任务会周期性读取陀螺仪数据并处理中断
|
||||
*/
|
||||
void IRAM_ATTR Gyroscope::GyroReadTask(void* pvParameters)
|
||||
{
|
||||
Gyroscope* gyroscope = static_cast<Gyroscope*>(pvParameters);
|
||||
uint32_t interrupt_count = 0;
|
||||
while (1) {
|
||||
if (gyroscope->interrupt_flag_) {
|
||||
interrupt_count++;
|
||||
gyroscope->ClearInterruptFlags();
|
||||
gyroscope->interrupt_flag_ = false;
|
||||
|
||||
// 调用用户注册的回调函数
|
||||
if (gyroscope->on_shake_callback_) {
|
||||
gyroscope->on_shake_callback_();
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_GYROSCOPE, "累计中断次数: %lu", interrupt_count);
|
||||
if(interrupt_count >= 2){
|
||||
interrupt_count = 0;
|
||||
ESP_LOGI(TAG_GYROSCOPE, "检测到摇晃>>>>>>>>>>");
|
||||
}
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); // 50ms检查一次,更快的响应
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
#ifndef GYROSCOPE_H
|
||||
#define GYROSCOPE_H
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_check.h>
|
||||
#include <esp_timer.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "i2c_bus.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include "esp_err.h"
|
||||
#include "config.h"
|
||||
#include "io_expansion_board.h"
|
||||
#include <functional>
|
||||
#include "esp_timer.h"
|
||||
|
||||
// 加速度数据结构体
|
||||
typedef struct {
|
||||
float x; // X轴加速度 (g)
|
||||
float y; // Y轴加速度 (g)
|
||||
float z; // Z轴加速度 (g)
|
||||
} AccelerationData;
|
||||
|
||||
// 一阶滤波系数
|
||||
#define WEIGHTFACTOR 0.93f
|
||||
|
||||
/* 陀螺仪寄存器定义 */
|
||||
#define CTRL1_XL 0x10 // 加速度计控制寄存器1
|
||||
#define CTRL2_G 0x11 // 陀螺仪控制寄存器2
|
||||
#define CTRL3_C 0x12 // 控制寄存器3
|
||||
#define CTRL4_C 0x13 // 控制寄存器4
|
||||
#define CTRL5_C 0x14 // 控制寄存器5
|
||||
#define CTRL6_C 0x15 // 控制寄存器6
|
||||
#define CTRL7_G 0x16 // 陀螺仪控制寄存器7
|
||||
#define CTRL8_XL 0x17 // 加速度计控制寄存器8
|
||||
#define CTRL9_XL 0x18 // 加速度计控制寄存器9
|
||||
#define CTRL10_C 0x19 // 控制寄存器10
|
||||
#define INT1_CTRL 0x0D // 中断1控制寄存器
|
||||
#define WAKE_UP_DUR 0x5B // 唤醒持续时间寄存器
|
||||
#define WAKE_UP_THS 0x5C // 唤醒阈值寄存器
|
||||
#define TAP_CFG 0x58 // 敲击配置寄存器
|
||||
#define TAP_THS_6D 0x59 // 6D方向阈值寄存器
|
||||
#define INT_DUR2 0x5A // 中断持续时间寄存器
|
||||
#define MD1_CFG 0x5E // 中断1配置寄存器
|
||||
#define MD2_CFG 0x5F // 中断2配置寄存器
|
||||
#define FUNC_SRC1 0x53 // 功能源寄存器1
|
||||
#define WAKE_UP_SRC 0x1B // 唤醒源寄存器
|
||||
|
||||
#define ACCEL_X_L 0x28 // OUTX_L_XL
|
||||
#define ACCEL_X_H 0x29 // OUTX_H_XL
|
||||
#define ACCEL_Y_L 0x2A // OUTY_L_XL
|
||||
#define ACCEL_Y_H 0x2B // OUTY_H_XL
|
||||
#define ACCEL_Z_L 0x2C // OUTZ_L_XL
|
||||
#define ACCEL_Z_H 0x2D // OUTZ_H_XL
|
||||
|
||||
#define ACCEL_SENSITIVITY_2G 0.061f // 2g 灵敏度 (g/LSB)
|
||||
|
||||
#define I2C_MASTER_TIMEOUT_MS 1000 // I2C主设备超时时间(毫秒)
|
||||
|
||||
/**
|
||||
* @class Gyroscope
|
||||
* @brief 陀螺仪驱动类,封装芯片操作
|
||||
*/
|
||||
#define TAG_GYROSCOPE "Gyroscope"
|
||||
class Gyroscope
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
Gyroscope();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~Gyroscope();
|
||||
|
||||
/**
|
||||
* @brief 初始化中断引脚
|
||||
* @param gpio_num 中断引脚编号
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t InterruptGpioInit(gpio_num_t gpio_num);
|
||||
|
||||
/**
|
||||
* @brief 创建陀螺仪读取任务
|
||||
*/
|
||||
void CreateGyroReadTask();
|
||||
|
||||
/**
|
||||
* @brief 初始化陀螺仪
|
||||
* @return esp_err_t 初始化结果
|
||||
*/
|
||||
esp_err_t Init(i2c_bus_handle_t bus_handle);
|
||||
|
||||
/**
|
||||
* @brief 清除中断标志
|
||||
* @return esp_err_t 清除结果
|
||||
*/
|
||||
esp_err_t ClearInterruptFlags();
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取当前加速度数据
|
||||
* @param data 指向AccelerationData结构体的指针,用于存储读取到的加速度数据
|
||||
* @return esp_err_t 获取结果
|
||||
*/
|
||||
esp_err_t GetAcceleration(AccelerationData* data);
|
||||
|
||||
/**
|
||||
* @brief 创建500ms周期定时器
|
||||
* @return esp_err_t 创建结果
|
||||
*/
|
||||
esp_err_t CreateTimer();
|
||||
|
||||
/**
|
||||
* @brief 停止并删除定时器
|
||||
*/
|
||||
void DeleteTimer();
|
||||
|
||||
/**
|
||||
* @brief 注册摇晃检测回调函数
|
||||
* @param callback 当检测到摇晃时调用的回调函数
|
||||
*/
|
||||
void OnShake(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* @brief 注册拿起检测回调函数
|
||||
* @param callback 当检测到设备被拿起时调用的回调函数
|
||||
*/
|
||||
void OnPickUp(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* @brief 注册放置检测回调函数
|
||||
* @param callback 当检测到设备被放置时调用的回调函数
|
||||
*/
|
||||
void OnPutDown(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
* @brief 注册倾斜检测回调函数
|
||||
* @param callback 当检测到设备倾斜时调用的回调函数
|
||||
*/
|
||||
void OnTilt(std::function<void()> callback);
|
||||
|
||||
i2c_bus_handle_t bus_handle_ = nullptr; // I2C总线句柄
|
||||
volatile uint8_t interrupt_count_ = 0; // 中断计数
|
||||
volatile bool interrupt_flag_ = false; // 中断标志位)(判断是否需要处理)
|
||||
|
||||
private:
|
||||
static void GpioIsrHandler(void* arg); // 中断处理函数
|
||||
static void GyroReadTask(void* pvParameters);
|
||||
static void TimerCallback(void* arg); // 定时器回调函数
|
||||
|
||||
void TimerInterruptHandler(); // 定时器中断处理函数
|
||||
|
||||
esp_err_t WriteRegister(uint8_t reg, uint8_t data);
|
||||
esp_err_t ReadRegister(uint8_t reg, uint8_t* data);
|
||||
esp_err_t ReadRegisters(uint8_t reg, uint8_t* data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief 读取原始加速度数据
|
||||
* @param x 指向X轴加速度存储的指针
|
||||
* @param y 指向Y轴加速度存储的指针
|
||||
* @param z 指向Z轴加速度存储的指针
|
||||
* @return esp_err_t 读取结果
|
||||
*/
|
||||
esp_err_t ReadRawAcceleration(int16_t* x, int16_t* y, int16_t* z);
|
||||
|
||||
std::function<void()> on_shake_callback_; // 摇晃回调函数
|
||||
std::function<void()> on_pickup_callback_; // 拿起回调函数
|
||||
std::function<void()> on_putdown_callback_; // 放置回调函数
|
||||
std::function<void()> on_tilt_callback_; // 倾斜回调函数
|
||||
|
||||
esp_timer_handle_t timer_handle_ = nullptr; // 定时器句柄
|
||||
|
||||
/**
|
||||
* @brief 分配静态任务所需的内存
|
||||
* @return bool 分配是否成功
|
||||
*/
|
||||
bool AllocateStaticTaskMemory();
|
||||
|
||||
/**
|
||||
* @brief 释放静态任务分配的内存
|
||||
*/
|
||||
void FreeStaticTaskMemory();
|
||||
|
||||
TaskHandle_t xGyroscopeTaskHandle_ = nullptr;
|
||||
StackType_t* pGyroscopeTaskStackBuffer_ = nullptr; // 任务栈指针(PSRAM)
|
||||
StaticTask_t* pxGyroscopeTaskBuffer_ = nullptr; // 任务控制块指针(内部RAM)
|
||||
|
||||
// 滤波相关成员变量
|
||||
int16_t last_filtered_x_ = 0; // 上一次滤波后的X轴值
|
||||
int16_t last_filtered_y_ = 0; // 上一次滤波后的Y轴值
|
||||
int16_t last_filtered_z_ = 0; // 上一次滤波后的Z轴值
|
||||
bool is_first_sample_ = true; // 是否为第一次采样标志
|
||||
|
||||
// 状态检测相关成员变量
|
||||
float accel_data_y_last_ = 0.0f; // 保存上一次Y轴数据
|
||||
float total_accel_last_ = 1.0f; // 保存上一次合成加速度值,初始值为1g(平放时的典型值)
|
||||
uint8_t stable_count_ = 0; // 稳定状态计数器
|
||||
uint8_t lift_count_ = 0; // 拿起动作计数器
|
||||
uint8_t putdown_count_ = 0; // 放置动作计数器
|
||||
bool is_stable_ = false; // 是否处于稳定平放状态
|
||||
bool is_lifted_ = false; // 是否处于被拿起状态
|
||||
};
|
||||
|
||||
#endif // GYROSCOPE_H
|
||||
@@ -0,0 +1,16 @@
|
||||
# main/05_executors/gyroscope/module.cmake
|
||||
|
||||
|
||||
# 判断 menuconfig 中的开关
|
||||
if(NOT CONFIG_ENABLE_EXEC_GYROSCOPE AND NOT EARLY_EXPANSION)
|
||||
message(STATUS " [Skip] gyroscope module disabled by menuconfig.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
list(APPEND MODULE_SRCS
|
||||
"05_executors/gyroscope/gyroscope.cc"
|
||||
)
|
||||
|
||||
list(APPEND MODULE_INCLUDE_DIRS
|
||||
"05_executors/gyroscope"
|
||||
)
|
||||
Reference in new issue
Block a user