该文档为解释MotorTask .h以及.cpp文件的解释说明文档,将分为两个部分进行阐述。
一、结构体 ESCC6x0RxMsg_t
1.1 概述
对于结构体
ESCC6x0RxMsg_t:
typedef struct {
int16_t angle;//角度
int16_t rotateSpeed;//转速
int16_t moment;//扭矩
} ESCC6x0RxMsg_t;//电调解码器发送的数据 用户可以直接读出数据进行处理。
该结构体存储的是解码器返回的数值,用户可以直接调用。
1.2 结构体成员详解
1、angle 解码器获得的角度值,通过一定的映射关系可以求得真实的角度realAngle。该参数通常用于NormalMotor(在下文中将会讲解)这类电机PID 运算中计算反馈值(Fdb),或者是底盘跟随(该功能将在chassisTask说明文档中解释)。
2、rotateSpeed 通常用于ChassisMotor这类电机(下文同样会进行讲解)的PID运算,见下面的代码:
void ChassisMotor::Handle() {
speedPid.PIDInfo.ref = targetAngle;
speedPid.PIDInfo.fdb = RxMsgC6x0.rotateSpeed;//此处用到了该参数
speedPid.Calc();
intensity = speedPid.PIDInfo.output;
}
/*以上代码摘自MotorTask.cpp*/
3、moment 即扭矩。实时反馈电机的扭矩值。可用于配合实现机械限位,调零点等工作。
以工程车为例,其爪子在使用前或者使用后必须进行位置的调零,以保证每次工作时都能转动正确的角度。为了辅助调零,通常会有一个机械限位,即阻止机构向某个方向运动。
当机械爪转动到零点位置的时候,机械爪被限位卡住,而随着电机的继续转动,其扭矩,即moment将会持续增大。不妨设置一个合适的阈值,当moment
超过该阈值的时候将电机的targetAngle置零,使得电机停转,此时机械爪成功完成了调零工作。
此外,由于moment是矢量,因而具有符号。请在使用的时候注意方向。
在选取阈值的时候,对于M3508而言,moment = 6000是一个比较适宜的值,对于M2006而言,moment = 3000是一个比较适宜的值。
切记:上面的阈值只是一个参考值,具体实际使用时请开启debug模式查看电机的实时moment值,借以判断应如何选取阈值。请勿将阈值选择的过大,否则
对于M2006这种“娇弱”的电机而言可能会触发保护机制,可能产生危险。
具体的调试方法此处不再赘述。
二、Motor 类
1.1 概述
Motor类是所有电机类的基类。其派生关系满足下面的示意图:
____________ ChassisMotor
/____________ NormalMotor
Motor|____________ GMYawMotor
|____________ GMPitchMotor
\____________ .....
Motor类具有丰富的接口,可用于辅助用户实现对电机的多种操作。
1.2 Protected成员
Motor类具有以下Protected成员,以注释解释各成员的作用以及含义。
PID speedPid; //速度环PID,所有类型的电机都有。
PID anglePid; //角度环PID,只有用双环PID的电机才有,例如GMYawMotor,NormalMotor等。
uint16_t TxID; //can通讯相关参数,按照Can通讯标准设置
uint16_t RxID; //can通讯相关参数,和电调ID(设其为i)之间满足以下映射关系:
//RxID = 0x200 + i;
int16_t intensity;//通过can通讯发送给电机的电流强度。也就是所谓PID输出的控制量。
ESCC6x0RxMsg_t RxMsgC6x0;//前文提过,不再赘述。
uint8_t firstEnter;//是否第一次进入?电机是否做初始化工作的判据。
uint8_t s_count;//调节电机控制频率。
uint8_t reseted;//用于判断云台电机是否回归零点。
double reductionRate;//电机减速比
double lastRead;//辅助计算realAngle,具体请看相关代码,此处不赘述。
double realAngle;//真实角度
1.3 接口
1、targetAngle:可供用户设置的目标角度(对ChassisMotor而言是目标速度)。
2、Reset函数:用于分配电机的can类型,RxID,减速比,PID(双环PID)等参数。
can类型:CAN_TYPE_1 即can1
CAN_TYPE_2 即can2
3、Handle函数:一个虚函数,即电机的控制函数。
在CarTask.cpp中,有以下代码:
void MainControlLoop(void) {
Car::car.WorkStateFSM();
if (Car::car.GetWorkState() > 0) {
#ifdef _CHASSIS
Chassis::chassis.Handle();
#endif
#ifdef _GIMBAL
Gimbal::gimbal.Handle();
#endif
#ifdef _FRIC
Shoot::shoot.Handle();
#endif
Gate::gate.Handle();
}
CAN::can1.TxHandle();
CAN::can2.TxHandle();
#ifdef _IMU
IMU::BSP_IMU.Handle();
#endif
#ifdef _AUTOAIM
AutoAim::autoAim.Handle();
#endif
}
在主循环中会不断调用Handle函数,实现对各个电机的控制。
4、其余的Getter和Setter由于比较简单易懂,此处不再赘述。
1.3 派生类简介
Motor的派生情况如下所示:
____________ ChassisMotor
/____________ NormalMotor
Motor|____________ GMYawMotor
|____________ GMPitchMotor
\____________ .....
1、ChassisMotor 即底盘电机。具体请关注其Reset和Handle函数。
该电机运转逻辑为,用户给定一个目标速度targetAngle,将通过Handle函数进行PID运算得出控制量,从而控制电机转动。
简而言之,即以给定的转速转动。
2、NormalMotor 普通电机。转动到给定角度targetAngle位置即停止转动。使用的是双环PID控制。
3、GMYawMotor 云台Yaw轴电机,双环PID控制,转到给定角度targetAngle停止。
4、GMPitchMotor 云台Pitch轴电机,双环PID控制,转到给定角度targetAngle停止。
5、用户可以自定义新的电机类型。请注意Reset和Handle函数的实现。建议根据不同的功能建立一个代表功能或者控制部分的类,将电机封装进去,写一些
相关成员函数实现对电机的操作。可类比ChassisTask等。
1.4 派生类Handle函数的简略说明
派生类Handle函数主要就是使用传统PID或者双环PID控制,把控制量以intensity的方式传给电机。
若了解PID相关原理,理解起来不难,此处不赘述。