Stm32角度减法计算器,处理角度突变

问题:

Stm32处理角度数据时,比如接受姿态传感器数据,偏航角范围在-180度到180度,那么我们控制系统输入误差信号时,角度差就会产生突变问题,比如说:从170度转到179度,等于179-170=9度,正方向旋转9度,从170度转到-179度,等于-179-170=-349度,但其实我们只需要正向旋转11度即可。问题在于,我们的减法作用于线性区域,而角度域应为环形域。

cd4abd31fbc945b3a1d59c90e0e6685f.png

 解决方案一:

作差限幅法,对于角度差值,小于-180,加上360,对于角度差值,大于180,减上360。上例中,-349<-180,那么-349+360=11度,为正确输入信号。我们将上述过程写成函数,每次角度作差调用函数即可。函数较简单,这里不列出。

解决方案二:

复数计算法,上文提到,问题的主要来源在于角度域是环形域,那么有没有可以表示环形域的量进行运算可以解决这个问题。答案是利用单位复数向量,我们将角度转化为单位复数向量,两个复数相除,获得的新复数取其相角即为答案,上例过程如下:

8c1fb4464b6b49f099de35a77d3e4217.png

由于手动计算,中间保留过程造成了误差扩大,但C语言计算,误差非常小,完全可以忽略。

下面贴出stm32代码: 

#include <math.h>
#include <complex.h>

float subangle(float angle0, float angle1)
{
    float complex comangle0, comangle1;
    comangle0 = cos(angle0 / 180 * Pi) + sin(angle0 / 180 * Pi) * I;
    comangle1 = cos(angle1 / 180 * Pi) + sin(angle1 / 180 * Pi) * I;
    float y = 180.0 * carg(comangle0 / comangle1) / Pi;
    return y;
}

注意:这段代码在STM32F103的工程中,KEIL 的AC6会报错无法运行,KEIL的AC5可以正常运行,我这里用的是v5.06update7(bulid 960)。希望有大佬可以试试AC6怎样配置才可以运行,顺便踢我一下。

当然,在函数的第二个参数取相反数可以完成求和操作。

<think>好的,用户现在问的是“具体讲一下角度角度结算”,我需要先理解他具体想知道什么。之前他问过关于M2006生成角度环代码的问题,现在可能是在那个基础上想更深入的角度计算部分。 首先,我需要回顾之前的回答。之前的回答里提到了角度环的结构体定义、初始化、PID计算,以及编码器数据的获取和归一化处理。用户现在可能对角度结算的具体步骤、编码器数据处理、归一化方法、多圈处理等细节感兴趣。 用户可能在使用M2006电机时遇到了角度计算的问题,比如如何处理编码器的原始数据,如何转换成弧度,如何处理多圈的情况,或者归一化到-π到π的过程中出现的问题。也有可能他在调试过程中发现角度环不稳定,想知道是不是角度结算部分有错误。 接下来,我需要分解角度角度结算的关键点。首先,编码器值的读取,包括机械角度和电角度的区别。然后是如何将编码器的原始值转换为弧度,可能需要解释分辨率8192 CPR的计算。之后是多圈累计的问题,因为编码器是单圈的,需要记录转过的圈数。然后是角度的归一化,防止超出-π到π的范围,避免跳变。此外,可能还要处理角度和机械角度的转换,特别是对于多极对数的电机。 还需要考虑实际应用中可能遇到的问题,比如断电后的位置保存,如何通过CAN协议获取编码器数据,以及处理角度过零时的跳变情况。这些都是在实际开发中需要注意的地方。 用户可能没有提到的深层需求是,如何确保角度计算的准确性和稳定性,尤其是在高速旋转或长时间运行的情况下。此外,可能还需要了解如何处理不同电机的极对数,因为M2006可能与其他电机有不同的配置。 在回答时,需要结构清晰,分步骤解释每个部分,并给出具体的公式和代码示例,比如如何将编码器值转换为弧度,如何计算多圈角度,归一化的代码实现等。同时,结合之前的代码,说明这些步骤在代码中的位置,比如在PID计算前获取实际角度并进行处理。 还需要注意用户可能对某些术语不太熟悉,比如机械角度与电角度的区别,极对数的概念,这时候需要适当解释,但不要过于深入,保持回答的实用性。另外,强调实际开发中的注意事项,比如断电保存、CAN通信的数据解析、过零处理等,帮助用户避免常见错误。 最后,总结关键点,确保用户理解角度结算的流程和重要性,以及如何在实际中应用这些步骤来确保角度环的稳定控制。</think>好的,我将详细讲解**角度角度结算**的核心逻辑和实现细节。这是机器人关节控制中**最关键的传感器数据处理环节**,直接影响控制精度和稳定性。 --- ### **一、角度结算的核心任务** 将电机编码器原始数据转换为**连续、无跳变、物理意义明确的弧度值**,主要解决以下问题: 1. **机械角度 ↔ 弧度转换** 2. **单圈角度归一化**(-π ~ π) 3. **多圈累计计数** 4. **电角度处理**(针对多极对数电机) --- ### **二、具体实现步骤分解** #### **1. 编码器原始数据读取** - **M2006编码器特性**: - 分辨率:8192 CPR(每转计数值) - 输出范围:0 ~ 8191(单圈绝对值) - 通信方式:通过CAN总线发送原始值 ```c // 示例代码:从CAN报文解析编码器值 uint16_t raw_encoder = (can_data[0] << 8) | can_data[1]; // 大端序解析 ``` #### **2. 机械角度计算** - **公式**: $$ \theta_{\text{机械}} = \frac{\text{raw\_encoder} \times 2\pi}{8192} $$ - **代码实现**: ```c float mechanical_angle = (raw_encoder * 2.0f * M_PI) / 8192.0f; ``` #### **3. 多圈计数处理** - **核心问题**:编码器只能输出单圈绝对值,需通过软件累计转数 - **实现方法**: 1. 记录上一周角度 $\theta_{\text{prev}}$ 2. 计算角度变化量 $\Delta\theta = \theta_{\text{current}} - \theta_{\text{prev}}$ 3. 检测过零跳变: - 若 $\Delta\theta > \pi$ → 实际为**逆时针转一圈** → 圈数-1 - 若 $\Delta\theta < -\pi$ → 实际为**顺时针转一圈** → 圈数+1 ```c // 全局变量 float total_angle = 0.0f; float prev_mechanical_angle = 0.0f; void UpdateTotalAngle() { float delta = mechanical_angle - prev_mechanical_angle; // 过零检测 if(delta > M_PI) { total_angle -= 2*M_PI; // 逆时针过零点 } else if(delta < -M_PI) { total_angle += 2*M_PI; // 顺时针过零点 } total_angle += delta; prev_mechanical_angle = mechanical_angle; } ``` #### **4. 角度归一化处理** - **目的**:将任意角度映射到 [-π, π) 区间,避免数值溢出 - **数学方法**: $$ \theta_{\text{norm}} = \theta - 2\pi \cdot \left\lfloor \frac{\theta + \pi}{2\pi} \right\rfloor $$ - **代码优化实现**: ```c float NormalizeAngle(float angle) { angle = fmod(angle, 2*M_PI); // 先取模 if(angle > M_PI) { angle -= 2*M_PI; } else if(angle < -M_PI) { angle += 2*M_PI; } return angle; } ``` #### **5. 电角度处理(针对FOC控制)** - **M2006电机参数**: - 极对数:7对极 → 电角度 = 机械角度 × 7 - 电角度公式: $$ \theta_{\text{电}} = \theta_{\text{机械}} \times \text{极对数} $$ ```c #define POLE_PAIRS 7 // M2006的极对数 float electrical_angle = mechanical_angle * POLE_PAIRS; ``` --- ### **三、关键问题处理技巧** #### **1. 断电位置保存** - 在EEPROM中存储 `total_angle`,上电时读取恢复 - 需配合绝对值编码器使用(M2006内置霍尔编码器支持) #### **2. CAN通信优化** - 使用**0x205~0x207的扩展ID**获取完整编码器数据 - 解析示例: ```c if(can_id == 0x205) { // 电机1数据 raw_encoder = (data[0] << 8) | data[1]; // 同时解析转速、电流等数据... } ``` #### **3. 过零跳变处理** - 在PID计算前必须完成归一化: ```c // 在PID更新函数中 pid->actual_angle = NormalizeAngle(total_angle); ``` --- ### **四、实际调试建议** 1. **验证环节**: - 手动旋转电机,观察`total_angle`是否连续变化 - 测试过零时归一化是否正确 - 检查电角度是否按7倍机械角度变化 2. **示波器监测**: - 监控`target_angle`与`actual_angle`的跟随误差 - 观察角度跳变时的微分项突变 3. **参数影响**: - 角度结算延迟会直接导致相位裕度下降 - 建议控制周期≤1ms --- ### **五、完整数据流总结** ``` 编码器原始值 → 机械角度 → 多圈累计 → 总角度 → 归一化处理 → 实际角度(PID输入) ↑ 极对数乘法 → 电角度(FOC控制) ``` 实际工程中需要配合**卡尔曼滤波器**或**观测器**处理噪声问题。建议使用`Q格式定点数`优化计算效率(尤其在无FPU的MCU上)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chiremingyue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值