17 Commits
master ... dev

Author SHA1 Message Date
Zorua
0b0b62f6f9 4310pitch driver bug solved 2026-03-21 15:34:10 +08:00
guoxy06
3ebb57d86b 修改RectifyRCjoystick()改了左摇杆限幅 2026-03-15 16:41:00 +08:00
Zorua
4ac9cba1d7 damiao motor driver init_1.1 2026-03-15 13:15:49 +08:00
Zorua
3afa755680 damiao motor driver init_1 2026-03-15 12:52:05 +08:00
Zorua
fbc83771a8 damiao motor driver init 2026-03-14 18:55:54 +08:00
fcl
52e8018b2c changed pid param for steer motor 2026-03-14 14:20:38 +08:00
guoxy06
fa85ac8e2a 4310能转,但不受遥控控制 2026-03-13 18:37:58 +08:00
fcl
4d20b137da reast 2026-03-11 20:37:35 +08:00
fcl
8a96476007 Revert "supercap can1"
This reverts commit 69e97cbefa.
2026-03-11 20:30:36 +08:00
fcl
91588795c2 待测版本(ID修改完成) 2026-03-11 19:45:12 +08:00
fcl
0e711f1fe8 待测版本(ID修改完成) 2026-03-11 19:44:53 +08:00
fcl
09802b3daa 待测版本(ID修改完成) 2026-03-10 19:10:47 +08:00
69e97cbefa supercap can1 2026-03-10 15:21:42 +08:00
5d32411da6 supercap can1 2026-03-10 03:09:35 +08:00
6d1de50957 supercap can1 2026-03-10 03:07:45 +08:00
93d26b601d Merge remote-tracking branch 'origin/dev' into dev 2026-03-10 03:06:07 +08:00
d6872ad1e8 supercap 2026-03-10 03:05:49 +08:00
13 changed files with 232 additions and 98 deletions

View File

@@ -113,14 +113,14 @@ void ChassisInit()
.can_init_config.can_handle = &hcan1, .can_init_config.can_handle = &hcan1,
.controller_param_init_config = { .controller_param_init_config = {
.angle_PID = { .angle_PID = {
.Kp = 12, .Kp = 35,
.Ki = 0.2, .Ki = 0.25,
.Kd = 0, .Kd = 0,
.CoefA = 3, .CoefA = 3,
.CoefB = 0.1, .CoefB = 0.1,
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement | PID_DerivativeFilter | PID_ChangingIntegrationRate, .Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement | PID_DerivativeFilter | PID_ChangingIntegrationRate,
.IntegralLimit = 1000, .IntegralLimit = 1500,
.MaxOut = 5000, .MaxOut = 6000,
.Derivative_LPF_RC = 0.001, .Derivative_LPF_RC = 0.001,
.DeadBand = 0.5, .DeadBand = 0.5,
}, },
@@ -151,7 +151,7 @@ void ChassisInit()
motor_steering_lb = DJIMotorInit(&chassis_motor_steering_config); motor_steering_lb = DJIMotorInit(&chassis_motor_steering_config);
PID_Init_Config_s chassis_follow_pid_conf = { PID_Init_Config_s chassis_follow_pid_conf = {
.Kp = 1.05, // 6 .Kp = 0.95, // 6
.Ki = 0, .Ki = 0,
.Kd = 0.1, // 0.495 .Kd = 0.1, // 0.495
.DeadBand = 0.5f,// 启用死区,值为0.5度 .DeadBand = 0.5f,// 启用死区,值为0.5度
@@ -170,11 +170,14 @@ void ChassisInit()
SuperCap_Init_Config_s cap_conf = { SuperCap_Init_Config_s cap_conf = {
.can_config = { .can_config = {
.can_handle = &hcan2, .can_handle = &hcan1, // 保持你原有的硬件CAN接口不变
.tx_id = 0x302, // 超级电容默认接收id .tx_id = 0x001, // C板发给超级电容的ID
.rx_id = 0x301, // 超级电容默认发送id,注意tx和rx在其他人看来是反的 .rx_id = 0x100, // 超级电容发给C板的ID
}}; }};
cap = SuperCapInit(&cap_conf); // 超级电容初始化 cap = SuperCapInit(&cap_conf); // 超级电容初始化 todo 控制
// (新增)设置超级电容功率补偿,例如补偿5W,可根据实际需求调整 todo 控制
SuperCapSetPowerOffset(cap, 5);
// 发布订阅初始化,如果为双板,则需要can comm来传递消息 // 发布订阅初始化,如果为双板,则需要can comm来传递消息
#ifdef CHASSIS_BOARD #ifdef CHASSIS_BOARD

View File

@@ -203,14 +203,13 @@ static void RemoteControlSet()
// 左侧开关状态为[下],或视觉未识别到目标,纯遥控器拨杆控制 // 左侧开关状态为[下],或视觉未识别到目标,纯遥控器拨杆控制
if (switch_is_down(rc_data[TEMP].rc.switch_left) ) if (switch_is_down(rc_data[TEMP].rc.switch_left) )
{ // 按照摇杆的输出大小进行角度增量,增益系数需调整 { // 按照摇杆的输出大小进行角度增量,增益系数需调整
gimbal_cmd_send.yaw += 0.005f * (float)rc_data[TEMP].rc.rocker_l_; gimbal_cmd_send.yaw += 0.005f * (float)rc_data[TEMP].rc.rocker_r_;
gimbal_cmd_send.pitch += 0.001f * (float)rc_data[TEMP].rc.rocker_l1; gimbal_cmd_send.pitch += 0.001f * (float)rc_data[TEMP].rc.rocker_r1;
} }
// 云台软件限位 // 云台软件限位
// 底盘参数,目前没有加入小陀螺(调试似乎暂时没有必要),系数需要调整 // 底盘参数,目前没有加入小陀螺(调试似乎暂时没有必要),系数需要调整
chassis_cmd_send.vx = 0.15f * (float)rc_data[TEMP].rc.rocker_r_; // _水平方向 chassis_cmd_send.vx = 0.15f * (float)rc_data[TEMP].rc.rocker_l_; // _水平方向
chassis_cmd_send.vy = 0.15f * (float)rc_data[TEMP].rc.rocker_r1; // 1数值方向 chassis_cmd_send.vy = 0.15f * (float)rc_data[TEMP].rc.rocker_l1; // 1数值方向
// // 发射参数 // // 发射参数
// if (switch_is_up(rc_data[TEMP].rc.switch_right)) // 右侧开关状态[上],弹舱打开 // if (switch_is_up(rc_data[TEMP].rc.switch_right)) // 右侧开关状态[上],弹舱打开

View File

@@ -26,12 +26,12 @@ void GimbalInit()
}, },
.controller_param_init_config = { .controller_param_init_config = {
.angle_PID = { .angle_PID = {
//.Kp = 0.685, // 8 //.Kp = 0.785, // 8
.Kp = 0.685, // 8 .Kp = 3, // 8
//.Ki = 0.315, //.Ki = 0.315,
.Ki = 0.25, .Ki = 0.45,
.Kd = 0.022, .Kd = 0.03,
//.DeadBand = 0.1, //.DeadBand = 0.1
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement | PID_DerivativeFilter | PID_ChangingIntegrationRate, .Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement | PID_DerivativeFilter | PID_ChangingIntegrationRate,
.IntegralLimit = 1060, .IntegralLimit = 1060,
.CoefA = 20, .CoefA = 20,
@@ -40,9 +40,9 @@ void GimbalInit()
.Derivative_LPF_RC = 0.001 .Derivative_LPF_RC = 0.001
}, },
.speed_PID = { .speed_PID = {
.Kp = 8000, // 50 .Kp = 500, // 50
//.Kp = 5000, // 50 //.Kp = 5000, // 50
.Ki = 5000, // 200 .Ki = 2000, // 200
.Kd = 0, .Kd = 0,
.CoefB = 1, .CoefB = 1,
.CoefA = 10, .CoefA = 10,
@@ -66,7 +66,7 @@ void GimbalInit()
Motor_Init_Config_s pitch_config = { Motor_Init_Config_s pitch_config = {
.can_init_config = { .can_init_config = {
.can_handle = &hcan2, .can_handle = &hcan2,
.tx_id = 4, .tx_id = 4,//2
}, },
.controller_param_init_config = { .controller_param_init_config = {
.angle_PID = { .angle_PID = {
@@ -83,7 +83,7 @@ void GimbalInit()
.Kd = 0, // 0 .Kd = 0, // 0
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement, .Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement,
.IntegralLimit = 2500, .IntegralLimit = 2500,
.MaxOut = 20000, .MaxOut = 8000,//20000
}, },
.other_angle_feedback_ptr = &gimba_IMU_data->Pitch, .other_angle_feedback_ptr = &gimba_IMU_data->Pitch,
// 还需要增加角速度额外反馈指针,注意方向,ins_task.md中有c板的bodyframe坐标系说明 // 还需要增加角速度额外反馈指针,注意方向,ins_task.md中有c板的bodyframe坐标系说明
@@ -96,7 +96,7 @@ void GimbalInit()
.close_loop_type = SPEED_LOOP | ANGLE_LOOP, .close_loop_type = SPEED_LOOP | ANGLE_LOOP,
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL, .motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
}, },
.motor_type = M3508, .motor_type = DM4310,
}; };
// 电机对total_angle闭环,上电时为零,会保持静止,收到遥控器数据再动 // 电机对total_angle闭环,上电时为零,会保持静止,收到遥控器数据再动
yaw_motor = DJIMotorInit(&yaw_config); yaw_motor = DJIMotorInit(&yaw_config);
@@ -132,6 +132,17 @@ void GimbalTask()
DJIMotorChangeFeed(pitch_motor, SPEED_LOOP, OTHER_FEED); DJIMotorChangeFeed(pitch_motor, SPEED_LOOP, OTHER_FEED);
DJIMotorSetRef(yaw_motor, gimbal_cmd_recv.yaw); // yaw和pitch会在robot_cmd中处理好多圈和单圈 DJIMotorSetRef(yaw_motor, gimbal_cmd_recv.yaw); // yaw和pitch会在robot_cmd中处理好多圈和单圈
DJIMotorSetRef(pitch_motor, gimbal_cmd_recv.pitch); DJIMotorSetRef(pitch_motor, gimbal_cmd_recv.pitch);
// // 根据底盘速度进行补偿,保持云台稳定
// // 这里简化处理,实际应用中可能需要更复杂的补偿算法
// float yaw_ref = gimbal_cmd_recv.yaw;
// float pitch_ref = gimbal_cmd_recv.pitch;
//
// // 当底盘移动时,云台需要保持相对稳定
// // 这里可以根据底盘速度调整云台的控制参考值
// // 例如,当底盘向前移动时,云台可能需要稍微向后调整以保持稳定
//
// DJIMotorSetRef(yaw_motor, yaw_ref); // yaw和pitch会在robot_cmd中处理好多圈和单圈
// DJIMotorSetRef(pitch_motor, pitch_ref);
break; break;
// 云台自由模式,使用编码器反馈,底盘和云台分离,仅云台旋转,一般用于调整云台姿态(英雄吊射等)/能量机关 // 云台自由模式,使用编码器反馈,底盘和云台分离,仅云台旋转,一般用于调整云台姿态(英雄吊射等)/能量机关
case GIMBAL_FREE_MODE: // 后续删除,或加入云台追地盘的跟随模式(响应速度更快) case GIMBAL_FREE_MODE: // 后续删除,或加入云台追地盘的跟随模式(响应速度更快)
@@ -160,3 +171,12 @@ void GimbalTask()
// 推送消息 // 推送消息
PubPushMessage(gimbal_pub, (void *)&gimbal_feedback_data); PubPushMessage(gimbal_pub, (void *)&gimbal_feedback_data);
} }
// /**
// * @brief 获取云台IMU数据指针
// *
// * @return attitude_t* 云台IMU数据指针
// */
// attitude_t *GetGimbalIMUData()
// {
// return gimba_IMU_data;
// }

View File

@@ -1,6 +1,6 @@
#ifndef GIMBAL_H #ifndef GIMBAL_H
#define GIMBAL_H #define GIMBAL_H
#include "../modules/imu/ins_task.h"
/** /**
* @brief 初始化云台,会被RobotInit()调用 * @brief 初始化云台,会被RobotInit()调用
* *
@@ -9,8 +9,8 @@ void GimbalInit();
/** /**
* @brief 云台任务 * @brief 云台任务
* * @return attitude_t* 云台IMU数据指针
*/ */
void GimbalTask(); void GimbalTask();
//attitude_t *GetGimbalIMUData();
#endif // GIMBAL_H #endif // GIMBAL_H

View File

@@ -26,7 +26,7 @@
/* 机器人重要参数定义,注意根据不同机器人进行修改,浮点数需要以.0或f结尾,无符号以u结尾 */ /* 机器人重要参数定义,注意根据不同机器人进行修改,浮点数需要以.0或f结尾,无符号以u结尾 */
// 云台参数 // 云台参数
#define YAW_CHASSIS_ALIGN_ECD 3938 // 云台和底盘对齐指向相同方向时的电机编码器值,若对云台有机械改动需要修改 #define YAW_CHASSIS_ALIGN_ECD 1190 // 云台和底盘对齐指向相同方向时的电机编码器值,若对云台有机械改动需要修改
#define YAW_ECD_GREATER_THAN_4096 0 // ALIGN_ECD值是否大于4096,是为1,否为0;用于计算云台偏转角度 #define YAW_ECD_GREATER_THAN_4096 0 // ALIGN_ECD值是否大于4096,是为1,否为0;用于计算云台偏转角度
#define PITCH_HORIZON_ECD 3412 // 云台处于水平位置时编码器值,若对云台有机械改动需要修改 #define PITCH_HORIZON_ECD 3412 // 云台处于水平位置时编码器值,若对云台有机械改动需要修改
#define PITCH_MAX_ANGLE 0 // 云台竖直方向最大角度 (注意反馈如果是陀螺仪,则填写陀螺仪的角度) #define PITCH_MAX_ANGLE 0 // 云台竖直方向最大角度 (注意反馈如果是陀螺仪,则填写陀螺仪的角度)

View File

@@ -96,7 +96,7 @@ void ShootInit()
.close_loop_type = CURRENT_LOOP | SPEED_LOOP, .close_loop_type = CURRENT_LOOP | SPEED_LOOP,
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL, // 注意方向设置为拨盘的拨出的击发方向 .motor_reverse_flag = MOTOR_DIRECTION_NORMAL, // 注意方向设置为拨盘的拨出的击发方向
}, },
.motor_type = M3508 // 英雄使用m3508 .motor_type = M2006 // 英雄使用m3508
}; };
loader = DJIMotorInit(&loader_config); loader = DJIMotorInit(&loader_config);

View File

@@ -64,7 +64,7 @@ static void f_Integral_Limit(PIDInstance *pid)
static void f_Derivative_On_Measurement(PIDInstance *pid) static void f_Derivative_On_Measurement(PIDInstance *pid)
{ {
pid->Dout = pid->Kd * (pid->Last_Measure - pid->Measure) / pid->dt; pid->Dout = pid->Kd * (pid->Last_Measure - pid->Measure) / pid->dt;
} }
// 微分滤波(采集微分时,滤除高频噪声) // 微分滤波(采集微分时,滤除高频噪声)
static void f_Derivative_Filter(PIDInstance *pid) static void f_Derivative_Filter(PIDInstance *pid)

View File

@@ -27,7 +27,9 @@ static CANInstance sender_assignment[6] = {
[4] = {.can_handle = &hcan2, .txconf.StdId = 0x200, .txconf.IDE = CAN_ID_STD, .txconf.RTR = CAN_RTR_DATA, .txconf.DLC = 0x08, .tx_buff = {0}}, [4] = {.can_handle = &hcan2, .txconf.StdId = 0x200, .txconf.IDE = CAN_ID_STD, .txconf.RTR = CAN_RTR_DATA, .txconf.DLC = 0x08, .tx_buff = {0}},
[5] = {.can_handle = &hcan2, .txconf.StdId = 0x2ff, .txconf.IDE = CAN_ID_STD, .txconf.RTR = CAN_RTR_DATA, .txconf.DLC = 0x08, .tx_buff = {0}}, [5] = {.can_handle = &hcan2, .txconf.StdId = 0x2ff, .txconf.IDE = CAN_ID_STD, .txconf.RTR = CAN_RTR_DATA, .txconf.DLC = 0x08, .tx_buff = {0}},
}; };
static CANInstance DM_sender_assignment[1] = {
[0] = {.can_handle = &hcan2, .txconf.StdId = 0x3FE, .txconf.IDE = CAN_ID_STD, .txconf.RTR = CAN_RTR_DATA, .txconf.DLC = 0x08, .tx_buff = {0}}
};
/** /**
* @brief 6个用于确认是否有电机注册到sender_assignment中的标志位,防止发送空帧,此变量将在DJIMotorControl()使用 * @brief 6个用于确认是否有电机注册到sender_assignment中的标志位,防止发送空帧,此变量将在DJIMotorControl()使用
* flag的初始化在 MotorSenderGrouping()中进行 * flag的初始化在 MotorSenderGrouping()中进行
@@ -106,7 +108,36 @@ static void MotorSenderGrouping(DJIMotorInstance *motor, CAN_Init_Config_s *conf
} }
} }
break; break;
case DM4310:
if (motor_id < 4) // 根据ID分组
{
motor_send_num = motor_id;
motor_grouping = config->can_handle == &hcan2 ? 1 : 4;
}
else
{
motor_send_num = motor_id - 4;
motor_grouping = config->can_handle == &hcan2 ? 0 : 3;
}
// 计算接收id并设置分组发送id
config->rx_id = 0x300 + motor_id + 1; // 把ID+1,进行分组设置
sender_enable_flag[motor_grouping] = 1; // 设置发送标志位,防止发送空帧
motor->message_num = motor_send_num;
motor->sender_group = motor_grouping;
// 检查是否发生id冲突
for (size_t i = 0; i < idx; ++i)
{
if (dji_motor_instance[i]->motor_can_instance->can_handle == config->can_handle && dji_motor_instance[i]->motor_can_instance->rx_id == config->rx_id)
{
LOGERROR("[dji_motor] ID crash. Check in debug mode, add dji_motor_instance to watch to get more information.");
uint16_t can_bus = config->can_handle == &hcan2 ? 1 : 2;
while (1) // 6020的id 1-4和2006/3508的id 5-8会发生冲突(若有注册,即1!5,2!6,3!7,4!8) (1!5!,LTC! (((不是)
LOGERROR("[dji_motor] id [%d], can_bus [%d]", config->rx_id, can_bus);
}
}
break;
default: // other motors should not be registered here default: // other motors should not be registered here
while (1) while (1)
LOGERROR("[dji_motor]You must not register other motors using the API of DJI motor."); // 其他电机不应该在这里注册 LOGERROR("[dji_motor]You must not register other motors using the API of DJI motor."); // 其他电机不应该在这里注册
@@ -296,8 +327,17 @@ void DJIMotorControl()
// 分组填入发送数据 // 分组填入发送数据
group = motor->sender_group; group = motor->sender_group;
num = motor->message_num; num = motor->message_num;
if (i == 1)//pitch轴电机对应i值为1,需要特殊处理,因为它的发送顺序和其他电机不同,在同一帧中与其他电机的高八位和低八位相反
{
DM_sender_assignment[0].tx_buff[6] = (uint8_t)(set & 0x00ff); // 高八位
DM_sender_assignment[0].tx_buff[7] = (uint8_t)(set >> 8); // 低八位
}
else
{
sender_assignment[group].tx_buff[2 * num] = (uint8_t)(set >> 8); // 低八位 sender_assignment[group].tx_buff[2 * num] = (uint8_t)(set >> 8); // 低八位
sender_assignment[group].tx_buff[2 * num + 1] = (uint8_t)(set & 0x00ff); // 高八位 sender_assignment[group].tx_buff[2 * num + 1] = (uint8_t)(set & 0x00ff); // 高八位
}
// 若该电机处于停止状态,直接将buff置零 // 若该电机处于停止状态,直接将buff置零
if (motor->stop_flag == MOTOR_STOP) if (motor->stop_flag == MOTOR_STOP)
@@ -310,6 +350,7 @@ void DJIMotorControl()
if (sender_enable_flag[i]) if (sender_enable_flag[i])
{ {
CANTransmit(&sender_assignment[i], 1); CANTransmit(&sender_assignment[i], 1);
CANTransmit(&DM_sender_assignment[0], 1);//达妙电机单独一帧发送
} }
} }
} }

View File

@@ -105,7 +105,6 @@ void DJIMotorChangeFeed(DJIMotorInstance *motor, Closeloop_Type_e loop, Feedback
* @brief 该函数被motor_task调用运行在rtos上,motor_stask内通过osDelay()确定控制频率 * @brief 该函数被motor_task调用运行在rtos上,motor_stask内通过osDelay()确定控制频率
*/ */
void DJIMotorControl(); void DJIMotorControl();
/** /**
* @brief 停止电机,注意不是将设定值设为零,而是直接给电机发送的电流值置零 * @brief 停止电机,注意不是将设定值设为零,而是直接给电机发送的电流值置零
* *

View File

@@ -20,13 +20,32 @@ static DaemonInstance *rc_daemon_instance;
* @brief 矫正遥控器摇杆的值,超过660或者小于-660的值都认为是无效值,置0 * @brief 矫正遥控器摇杆的值,超过660或者小于-660的值都认为是无效值,置0
* *
*/ */
static void RectifyRCjoystick() // static void RectifyRCjoystick()
// {
// for (uint8_t i = 0; i < 5; ++i)
// if (abs(*(&rc_ctrl[TEMP].rc.rocker_l_ + i)) > 660)
// *(&rc_ctrl[TEMP].rc.rocker_l_ + i) = 0;
// }
static void RectifyRCjoystick()//左遥杆水平向右限幅不够,因为下面的+3,将+3删除就用上面的
{ {
int16_t *rocker_ptr = &rc_ctrl[TEMP].rc.rocker_l_;
for (uint8_t i = 0; i < 5; ++i) for (uint8_t i = 0; i < 5; ++i)
if (abs(*(&rc_ctrl[TEMP].rc.rocker_l_ + i)) > 660) {
*(&rc_ctrl[TEMP].rc.rocker_l_ + i) = 0; if (i == 0) // 左遥杆水平方向
{
// 增加右向最大值到700,左向保持660不变
if (rocker_ptr[i] > 700)
rocker_ptr[i] = 700;
else if (rocker_ptr[i] < -660)
rocker_ptr[i] = -660;
}
else // 其他通道保持原限制
{
if (abs(rocker_ptr[i]) > 660)
rocker_ptr[i] = 0;
}
}
} }
/** /**
* @brief 遥控器数据解析 * @brief 遥控器数据解析
* *
@@ -40,7 +59,7 @@ static void sbus_to_rc(const uint8_t *sbus_buf)
rc_ctrl[TEMP].rc.rocker_l_ = (((sbus_buf[2] >> 6) | (sbus_buf[3] << 2) | (sbus_buf[4] << 10)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 2 rc_ctrl[TEMP].rc.rocker_l_ = (((sbus_buf[2] >> 6) | (sbus_buf[3] << 2) | (sbus_buf[4] << 10)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 2
rc_ctrl[TEMP].rc.rocker_l1 = (((sbus_buf[4] >> 1) | (sbus_buf[5] << 7)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 3 rc_ctrl[TEMP].rc.rocker_l1 = (((sbus_buf[4] >> 1) | (sbus_buf[5] << 7)) & 0x07ff) - RC_CH_VALUE_OFFSET; //!< Channel 3
rc_ctrl[TEMP].rc.dial = ((sbus_buf[16] | (sbus_buf[17] << 8)) & 0x07FF) - RC_CH_VALUE_OFFSET; rc_ctrl[TEMP].rc.dial = ((sbus_buf[16] | (sbus_buf[17] << 8)) & 0x07FF) - RC_CH_VALUE_OFFSET;
rc_ctrl[TEMP].rc.rocker_l_= rc_ctrl[TEMP].rc.rocker_l_; rc_ctrl[TEMP].rc.rocker_l_= rc_ctrl[TEMP].rc.rocker_l_+3;
// 左侧拨轮 // 左侧拨轮
RectifyRCjoystick(); RectifyRCjoystick();
// 开关,0左1右 // 开关,0左1右

View File

@@ -1,15 +1,12 @@
/* /*
* @Descripttion: * @Descripttion: 适配群星战队协议的超级电容模块
* @version: * @version: V2.0
* @Author: Chenfu
* @Date: 2022-12-02 21:32:47
* @LastEditTime: 2022-12-05 15:29:49
*/ */
#include "super_cap.h" #include "super_cap.h"
#include "memory.h" #include "memory.h"
#include "stdlib.h" #include "stdlib.h"
static SuperCapInstance *super_cap_instance = NULL; // 可以由app保存此指针 static SuperCapInstance *super_cap_instance = NULL;
static void SuperCapRxCallback(CANInstance *_instance) static void SuperCapRxCallback(CANInstance *_instance)
{ {
@@ -17,9 +14,14 @@ static void SuperCapRxCallback(CANInstance *_instance)
SuperCap_Msg_s *Msg; SuperCap_Msg_s *Msg;
rxbuff = _instance->rx_buff; rxbuff = _instance->rx_buff;
Msg = &super_cap_instance->cap_msg; Msg = &super_cap_instance->cap_msg;
Msg->vol = (uint16_t)(rxbuff[0] << 8 | rxbuff[1]);
Msg->current = (uint16_t)(rxbuff[2] << 8 | rxbuff[3]); // 按照新协议解析接收数据
Msg->power = (uint16_t)(rxbuff[4] << 8 | rxbuff[5]); Msg->ready = (SuperCapReadyEnum)rxbuff[0];
Msg->state = (SuperCapStateEnum)rxbuff[1];
Msg->energy = rxbuff[2];
Msg->chassis_power = (uint16_t)(rxbuff[3] << 1); // 左移一位还原量程
Msg->bat_voltage = rxbuff[4];
Msg->bat_power = rxbuff[5];
} }
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config) SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config)
@@ -32,10 +34,24 @@ SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config)
return super_cap_instance; return super_cap_instance;
} }
void SuperCapSend(SuperCapInstance *instance, uint8_t *data) void SuperCapSend(SuperCapInstance *instance, SuperCap_TxMsg_s *tx_data)
{ {
memcpy(instance->can_ins->tx_buff, data, 8); uint8_t *txbuff = instance->can_ins->tx_buff;
CANTransmit(instance->can_ins,1);
// 按照新协议装载发送数据
txbuff[0] = tx_data->Enable;
txbuff[1] = tx_data->Charge;
txbuff[2] = tx_data->Powerlimit - instance->power_offset; // 计算功率补偿
txbuff[3] = tx_data->ChargePower;
CANTransmit(instance->can_ins, 1);
}
void SuperCapSetPowerOffset(SuperCapInstance *instance, uint8_t offset)
{
if (instance != NULL) {
instance->power_offset = offset;
}
} }
SuperCap_Msg_s SuperCapGet(SuperCapInstance *instance) SuperCap_Msg_s SuperCapGet(SuperCapInstance *instance)

View File

@@ -1,29 +1,61 @@
/* /*
* @Descripttion: * @Descripttion: 适配群星战队协议的超级电容模块
* @version: * @version: V2.0
* @Author: Chenfu
* @Date: 2022-12-02 21:32:47
* @LastEditTime: 2022-12-05 15:25:46
*/ */
#ifndef SUPER_CAP_H #ifndef SUPER_CAP_H
#define SUPER_CAP_H #define SUPER_CAP_H
#include "bsp_can.h" #include "bsp_can.h"
// 超级电容状态枚举(从群星战队协议移植)
typedef enum
{
DISCHARGE = 0, // 放电状态
CHARGE = 1, // 充电状态
WAIT = 2, // 待机状态
SOFTSTART_PROTECTION = 3, // 处于软起动状态
OVER_LOAD_PROTECTION = 4, // 超电过载保护状态
BAT_OVER_VOLTAGE_PROTECTION = 5, // 过压保护状态
BAT_UNDER_VOLTAGE_PROTECTION = 6, // 电池欠压保护
CAP_UNDER_VOLTAGE_PROTECTION = 7, // 超级电容欠压保护
OVER_TEMPERATURE_PROTECTION = 8, // 过温保护
BOOM = 9, // 超电爆炸了
} SuperCapStateEnum;
// 超级电容准备状态
typedef enum
{
UNREADY = 0,
READY = 1,
} SuperCapReadyEnum;
#pragma pack(1) #pragma pack(1)
/* 接收到的超级电容信息结构体 */
typedef struct typedef struct
{ {
uint16_t vol; // 电压 SuperCapReadyEnum ready; // 可用标志:1为可用,0为不可用
uint16_t current; // 电流 SuperCapStateEnum state; // 状态标志
uint16_t power; // 功率 uint8_t energy; // 超级电容可用能量:0-100%
uint16_t chassis_power; // 底盘功率
uint8_t bat_voltage; // 电池电压*10
uint8_t bat_power; // 电池功率
} SuperCap_Msg_s; } SuperCap_Msg_s;
/* 需要发送给超级电容的控制信息结构体 */
typedef struct {
uint8_t Enable; // 超级电容使能。1使能,0失能
uint8_t Charge; // 超级电容充电。1充电,0放电
uint8_t Powerlimit; // 裁判系统功率限制
uint8_t ChargePower; // 超级电容充电功率
} SuperCap_TxMsg_s;
#pragma pack() #pragma pack()
/* 超级电容实例 */ /* 超级电容实例 */
typedef struct typedef struct
{ {
CANInstance *can_ins; // CAN实例 CANInstance *can_ins; // CAN实例
SuperCap_Msg_s cap_msg; // 超级电容信息 SuperCap_Msg_s cap_msg; // 超级电容接收信息
uint8_t power_offset; // 功率补偿值
} SuperCapInstance; } SuperCapInstance;
/* 超级电容初始化配置 */ /* 超级电容初始化配置 */
@@ -34,18 +66,22 @@ typedef struct
/** /**
* @brief 初始化超级电容 * @brief 初始化超级电容
*
* @param supercap_config 超级电容初始化配置
* @return SuperCapInstance* 超级电容实例指针
*/ */
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config); SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s *supercap_config);
/** /**
* @brief 发送超级电容控制信息 * @brief 发送超级电容控制信息
*
* @param instance 超级电容实例
* @param data 超级电容控制信息
*/ */
void SuperCapSend(SuperCapInstance *instance, uint8_t *data); void SuperCapSend(SuperCapInstance *instance, SuperCap_TxMsg_s *tx_data);
#endif // !SUPER_CAP_Hd /**
* @brief 设置超级电容功率补偿
*/
void SuperCapSetPowerOffset(SuperCapInstance *instance, uint8_t offset);
/**
* @brief 获取超级电容数据
*/
SuperCap_Msg_s SuperCapGet(SuperCapInstance *instance);
#endif // !SUPER_CAP_H

View File

@@ -1,21 +1,16 @@
<!-- # super_cap (适配版)
* @Descripttion:
* @version:
* @Author: Chenfu
* @Date: 2022-12-02 21:32:47
* @LastEditTime: 2022-12-05 15:27:57
-->
# super_can
## 代码结构 ## 代码结构
.h中放置的是数据定义和外部接口,以及协议的定义和宏,.c中包含一些私有函数。 .h中放置的是数据和协议枚举定义、控制接口,.c中包含CAN接收中断的回调解析以及发送打包逻辑。当前版本已完全适配群星战队的超级电容协议。
## 外部接口 ## 外部接口
```c ```c
SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s* supercap_config); SuperCapInstance *SuperCapInit(SuperCap_Init_Config_s* supercap_config);
void SuperCapSend(SuperCapInstance *instance, uint8_t *data); void SuperCapSend(SuperCapInstance *instance, SuperCap_TxMsg_s *tx_data);
void SuperCapSetPowerOffset(SuperCapInstance *instance, uint8_t offset);
SuperCap_Msg_s SuperCapGet(SuperCapInstance *instance);
``` ```
## 私有函数和变量 ## 私有函数和变量
@@ -25,7 +20,7 @@ static uint8_t *rxbuff;
static void SuperCapRxCallback(can_instance *_instance) static void SuperCapRxCallback(can_instance *_instance)
``` ```
`SuperCapRxCallback()`是super cap初始化can实例时的回调函数,用于can接收中断,进行协议解析。 SuperCapRxCallback()是super cap初始化can实例时的回调函数,用于CAN接收中断,进行协议解析(包含底盘功率右移量程的还原等处理)。
## 使用范例 ## 使用范例
@@ -35,20 +30,26 @@ static void SuperCapRxCallback(can_instance *_instance)
SuperCap_Init_Config_s capconfig = { SuperCap_Init_Config_s capconfig = {
.can_config = { .can_config = {
.can_handle = &hcan1, .can_handle = &hcan1,
.rx_id = 0x301, .rx_id = 0x100, // 超级电容发给C板的ID
.tx_id = 0x302 .tx_id = 0x001 // C板发给超级电容的ID
}, }
.recv_data_len = 4*sizeof(uint16_t), };
.send_data_len = sizeof(uint8_t) SuperCapInstance *ins = SuperCapInit(&capconfig);
};
SuperCapInstance *ins =SuperCapInit(&capconfig); // 如果需要设置功率补偿
SuperCapSetPowerOffset(ins, 5);
``` ```
发送通过`SuperCapSend()`,建议使用强制类型转换: 发送通过`SuperCapSend()`,建议使用强制类型转换:
发送控制指令时,使用 SuperCap_TxMsg_s 结构体:
```c ```c
uint16_t tx = 0x321; SuperCap_TxMsg_s tx_cmd = {
SuperCapSend(ins, (uint8_t*)&tx); .Enable = 1,
.Charge = 1,
.Powerlimit = 60,
.ChargePower = 40
};
SuperCapSend(ins, &tx_cmd);
``` ```