新增因克斯EC电机(哨兵大yaw轴)驱动支持 目前支持速度伺服控制模式 解析反馈报文类型1

This commit is contained in:
宋家齐 2023-12-11 21:08:08 +08:00
parent 4f8100efbc
commit 9e51196992
12 changed files with 508 additions and 50 deletions

View File

@ -54,7 +54,7 @@ include_directories(Inc Drivers/STM32F4xx_HAL_Driver/Inc Drivers/STM32F4xx_HAL_D
modules modules/alarm modules/algorithm modules/BMI088 modules/can_comm modules/daemon modules/encoder modules/imu modules/ist8310
modules/led modules/master_machine modules/message_center modules/motor modules/oled modules/referee modules/remote modules/standard_cmd
modules/super_cap modules/TFminiPlus modules/unicomm modules/vofa
modules/motor/DJImotor modules/motor/HTmotor modules/motor/LKmotor modules/motor/servo_motor modules/motor/step_motor
modules/motor/DJImotor modules/motor/HTmotor modules/motor/LKmotor modules/motor/servo_motor modules/motor/step_motor modules/motor/ECmotor
application application/chassis application/cmd application/gimbal application/shoot
Middlewares/Third_Party/SEGGER/RTT Middlewares/Third_Party/SEGGER/Config)

View File

@ -1,6 +1,7 @@
#include "gimbal.h"
#include "robot_def.h"
#include "dji_motor.h"
#include "ECmotor/ECA8210.h"
#include "ins_task.h"
#include "message_center.h"
#include "general_def.h"
@ -11,11 +12,15 @@
static attitude_t *gimba_IMU_data; // 云台IMU数据
static DJIMotorInstance *yaw_motor, *pitch_motor;
static ECMotorInstance *big_yaw_motor;
static Publisher_t *gimbal_pub; // 云台应用消息发布者(云台反馈给cmd)
static Subscriber_t *gimbal_sub; // cmd控制消息订阅者
static Gimbal_Upload_Data_s gimbal_feedback_data; // 回传给cmd的云台状态信息
static Gimbal_Ctrl_Cmd_s gimbal_cmd_recv; // 来自cmd的控制信息
sin_input_generate_t sinInputGenerate;
void GimbalInit()
{
gimba_IMU_data = INS_Init(); // IMU先初始化,获取姿态数据指针赋给yaw电机的其他数据来源
@ -73,40 +78,51 @@ void GimbalInit()
// .IntegralLimit = 100,
// .MaxOut = 500,
// },
// .speed_PID = {
// .Kp = 50, // 50
// .Ki = 350, // 350
// .Kd = 0, // 0
// .Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement,
// .IntegralLimit = 2500,
// .MaxOut = 20000,
// },
.speed_PID = {
.Kp = 5.13, // 50
.Ki = 88.26, // 350
.Kd = 0, // 0
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement,
.IntegralLimit = 2500,
.MaxOut = 30000,
},
// .other_angle_feedback_ptr = &gimba_IMU_data->Pitch,
// // 还需要增加角速度额外反馈指针,注意方向,ins_task.md中有c板的bodyframe坐标系说明
// .other_speed_feedback_ptr = (&gimba_IMU_data->Gyro[0]),
.current_PID = {
.Kp = 1, // 10
.Ki = 0,
.Kd = 0,
.Improve = PID_Trapezoid_Intergral | PID_Integral_Limit | PID_Derivative_On_Measurement,
.IntegralLimit = 3000,
.MaxOut = 30000,
}
},
.controller_setting_init_config = {
.outer_loop_type = OPEN_LOOP,
.close_loop_type = OPEN_LOOP,
.outer_loop_type = SPEED_LOOP,
.close_loop_type = SPEED_LOOP|CURRENT_LOOP,
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
},
.motor_type = GM6020,
.motor_control_type = CURRENT_CONTROL
};
Motor_Init_Config_s big_yaw_config = {
.can_init_config = {
.can_handle = &hcan1,
.tx_id = 1,
},
.controller_setting_init_config = {
.outer_loop_type = OPEN_LOOP,
.close_loop_type = OPEN_LOOP,
.motor_reverse_flag = MOTOR_DIRECTION_NORMAL,
},
.motor_type = ECA8210
};
// 电机对total_angle闭环,上电时为零,会保持静止,收到遥控器数据再动
yaw_motor = DJIMotorInit(&yaw_config);
pitch_motor = DJIMotorInit(&pitch_config);
// yaw_motor = DJIMotorInit(&yaw_config);
// pitch_motor = DJIMotorInit(&pitch_config);
big_yaw_motor = ECMotorInit(&big_yaw_config);
gimbal_pub = PubRegister("gimbal_feed", sizeof(Gimbal_Upload_Data_s));
gimbal_sub = SubRegister("gimbal_cmd", sizeof(Gimbal_Ctrl_Cmd_s));
sin_input_frequency_init(&sinInputGenerate);
}
/* 机器人云台控制核心任务,后续考虑只保留IMU控制,不再需要电机的反馈 */
@ -154,21 +170,30 @@ void GimbalTask()
// 在合适的地方添加pitch重力补偿前馈力矩
// 根据IMU姿态/pitch电机角度反馈计算出当前配重下的重力矩
// ...
static uint32_t cnt;
static float time;
DJIMotorEnable(pitch_motor);
float deltaT=DWT_GetDeltaT(&cnt);
time += deltaT;
//DJIMotorEnable(pitch_motor);
ECMotorEnable(big_yaw_motor);
float input = step_input_generate(&sinInputGenerate);
//DJIMotorSetRef(pitch_motor,input);
ECMotorSetRef(big_yaw_motor,30);
//ANODT_SendF1(input*1000,pitch_motor->measure.speed_aps*1000,0,0);
float theta = pitch_motor->measure.angle_single_round - 6200 * ECD_ANGLE_COEF_DJI;
//float input = arm_sin_f32(2*PI*10*time);
float gravity_feed = 3800*arm_cos_f32(theta/180*PI);
DJIMotorSetRef(pitch_motor,gravity_feed);
//DJIMotorSetRef(pitch_motor,gravity_feed);
float vofa_send_data[4];
// vofa_send_data[0]=yaw_motor->motor_controller.speed_PID.Ref;
// vofa_send_data[1]=yaw_motor->motor_controller.speed_PID.Measure;
// vofa_send_data[2]=yaw_motor->motor_controller.angle_PID.Ref;
vofa_send_data[0]=big_yaw_motor->measure.speed_rads;
vofa_send_data[1]=big_yaw_motor->measure.angle_single_round;
vofa_send_data[2]=big_yaw_motor->measure.real_current;
vofa_send_data[3]=big_yaw_motor->measure.temperature;
// vofa_send_data[3]=yaw_motor->motor_controller.angle_PID.Measure;
// vofa_justfloat_output(vofa_send_data,16,&huart1);
vofa_justfloat_output(vofa_send_data,16,&huart1);
vofa_send_data[0] = pitch_motor->motor_controller.pid_ref;
@ -185,16 +210,71 @@ void GimbalTask()
}
void sin_input_generate(float frequency, int count)
{
static uint32_t cnt;
static float time;
while(time>=count*(1/frequency))
{
float deltaT=DWT_GetDeltaT(&cnt);
time += deltaT;
//void sin_input_generate(float frequency, int count)
//{
// static uint32_t cnt;
// static float time;
// while(time>=count*(1/frequency))
// {
// float deltaT=DWT_GetDeltaT(&cnt);
// time += deltaT;
//
// float input = arm_sin_f32(2*PI*frequency*time);
// DJIMotorSetRef(yaw_motor,input);
// }
//}
float input = arm_sin_f32(2*PI*frequency*time);
DJIMotorSetRef(yaw_motor,input);
void sin_input_frequency_init(sin_input_generate_t* InputGenerate)
{
for(int i=0;i<43;i++)
{
InputGenerate->frequency[i] = 1.0 + 0.5*i;
}
for(int i=0;i<9;i++)
{
InputGenerate->frequency[i+43] = 24.0 + 2.0*i;
}
for(int i=0;i<8;i++)
{
InputGenerate->frequency[i+43+9] = 50 + 10*i;
}
InputGenerate->frequency[60] = 200;
InputGenerate->frequency[61] = 250;
InputGenerate->frequency[62] = 333;
InputGenerate->frequency[63] = 500;
}
float sin_input_generate(sin_input_generate_t* InputGenerate)
{
InputGenerate->DeltaT = DWT_GetDeltaT(&InputGenerate->cnt);
InputGenerate->time += InputGenerate->DeltaT;
if(InputGenerate->time >= 20*(1/InputGenerate->frequency[InputGenerate->frequency_index]))
{
InputGenerate->time = 0;
InputGenerate->frequency_index += 1;
}
if(InputGenerate->frequency_index >= 64)
{
InputGenerate->input = 0;
}
else
InputGenerate->input = arm_sin_f32(2*PI*InputGenerate->frequency[InputGenerate->frequency_index]*InputGenerate->time);
//float input = arm_sin_f32(2*PI*frequency*time);
return InputGenerate->input;
}
float step_input_generate(sin_input_generate_t* InputGenerate)
{
static int8_t forward_flag = 1;
InputGenerate->DeltaT = DWT_GetDeltaT(&InputGenerate->cnt);
InputGenerate->time += InputGenerate->DeltaT;
if(InputGenerate->time >= 3)
{
if(forward_flag ==1) forward_flag = -1;
else if (forward_flag == -1) forward_flag = 1;
InputGenerate->time = 0;
}
return 60*forward_flag;
}

View File

@ -1,6 +1,6 @@
#ifndef GIMBAL_H
#define GIMBAL_H
#include "robot_def.h"
/**
* @brief ,RobotInit()
*
@ -13,4 +13,18 @@ void GimbalInit();
*/
void GimbalTask();
typedef struct
{
uint32_t cnt;//计时用
uint8_t frequency_index;//运行到哪个频率
float time;
float frequency[64];
float DeltaT;
float input;
} sin_input_generate_t;
void sin_input_frequency_init(sin_input_generate_t* InputGenerate);
float sin_input_generate(sin_input_generate_t* InputGenerate);
float step_input_generate(sin_input_generate_t* InputGenerate);
#endif // GIMBAL_H

View File

@ -37,7 +37,7 @@ void RobotInit()
#endif
#if defined(ONE_BOARD) || defined(CHASSIS_BOARD)
ChassisInit();
//ChassisInit();
#endif
OSTaskInit(); // 创建基础任务
@ -56,7 +56,7 @@ void RobotTask()
#endif
#if defined(ONE_BOARD) || defined(CHASSIS_BOARD)
ChassisTask();
//ChassisTask();
#endif
}

View File

@ -119,9 +119,9 @@ __attribute__((noreturn)) void StartROBOTTASK(void const *argument)
robot_start = DWT_GetTimeline_ms();
RobotTask();
robot_dt = DWT_GetTimeline_ms() - robot_start;
if (robot_dt > 5)
if (robot_dt > 1)
LOGERROR("[freeRTOS] ROBOT core Task is being DELAY! dt = [%f]", &robot_dt);
osDelay(5);
osDelay(1);
}
}

View File

@ -306,7 +306,9 @@ void DJIMotorControl()
pid_ref += *motor_controller->current_feedforward_ptr;
if (motor_setting->close_loop_type & CURRENT_LOOP)
{
pid_ref = PIDCalculate(&motor_controller->current_PID, measure->real_current, pid_ref);
//现在3508和6020电调都内置电流闭环 无需PID计算
//pid_ref = PIDCalculate(&motor_controller->current_PID, measure->real_current, pid_ref);
pid_ref = pid_ref;
}

View File

@ -0,0 +1,179 @@
//
// Created by SJQ on 2023/12/11.
//
#include "ECA8210.h"
ECMotor_Report_t ECMotor_Report;
ECMotor_SpdCMD_t ECMotor_SpdCMD;
ECMotor_PosCMD_t ECMotor_PosCMD;
static uint8_t idx;
static ECMotorInstance *ecmotor_instance[EC_MOTOR_MX_CNT] = {NULL};
static void swap ( uint8_t *a ,uint8_t *b )
{
uint8_t temp = *a;
*a = *b;
*b = temp;
}
/**
* @brief
*
* @param _instance caninstance
*/
static void ECMotorDecode(CANInstance *_instance)
{
ECMotorInstance *motor = (ECMotorInstance *)_instance->id; // 通过caninstance保存的father id获取对应的motorinstance
ECMotor_Measure_t *measure = &motor->measure;
uint8_t *rx_buff = _instance->rx_buff;
swap(rx_buff+1,rx_buff+2);// 输出端位置 高位在前
memcpy(&ECMotor_Report,rx_buff,sizeof(ECMotor_Report));
//高位在前 这两个12位数据需要做特殊处理
ECMotor_Report.speed_raw = (uint16_t)(rx_buff[3]<<4|(rx_buff[4]>>4));
ECMotor_Report.current_raw = (uint16_t)(rx_buff[4]<<8|(rx_buff[5]));
DaemonReload(motor->daemon); // 喂狗
measure->feed_dt = DWT_GetDeltaT(&measure->feed_dwt_cnt);
measure->angle_single_round = (float)(ECMotor_Report.angle_raw-32768) * 0.0003814697;
measure->speed_rads = (float)(ECMotor_Report.speed_raw-2048) * 0.008789;
measure->real_current = (float)(ECMotor_Report.current_raw-2048) * 0.014648;
measure->temperature = (ECMotor_Report.temperature_raw - 50) /2;
}
static void ECMotorLostCallback(void *motor_ptr)
{
ECMotorInstance *motor = (ECMotorInstance *)motor_ptr;
LOGWARNING("[ECMotor] motor lost, id: %d", motor->motor_can_ins->tx_id);
}
ECMotorInstance *ECMotorInit(Motor_Init_Config_s *config)
{
ECMotorInstance *motor = (ECMotorInstance *)malloc(sizeof(ECMotorInstance));
motor = (ECMotorInstance *)malloc(sizeof(ECMotorInstance));
memset(motor, 0, sizeof(ECMotorInstance));
motor->motor_settings = config->controller_setting_init_config;
PIDInit(&motor->current_PID, &config->controller_param_init_config.current_PID);
PIDInit(&motor->speed_PID, &config->controller_param_init_config.speed_PID);
PIDInit(&motor->angle_PID, &config->controller_param_init_config.angle_PID);
motor->other_angle_feedback_ptr = config->controller_param_init_config.other_angle_feedback_ptr;
motor->other_speed_feedback_ptr = config->controller_param_init_config.other_speed_feedback_ptr;
config->can_init_config.id = motor;
config->can_init_config.can_module_callback = ECMotorDecode;
config->can_init_config.rx_id = config->can_init_config.tx_id;
config->can_init_config.tx_id = config->can_init_config.tx_id;
motor->motor_can_ins = CANRegister(&config->can_init_config);
ECMotorEnable(motor);
DWT_GetDeltaT(&motor->measure.feed_dwt_cnt);
ecmotor_instance[idx++] = motor;
Daemon_Init_Config_s daemon_config = {
.callback = ECMotorLostCallback,
.owner_id = motor,
.reload_count = 5, // 50ms
};
motor->daemon = DaemonRegister(&daemon_config);
return motor;
}
void ECMotorControl()
{
float pid_measure, pid_ref;
int16_t set;
ECMotorInstance *motor;
ECMotor_Measure_t *measure;
Motor_Control_Setting_s *setting;
for (size_t i = 0; i < idx; ++i)
{
motor = ecmotor_instance[i];
measure = &motor->measure;
setting = &motor->motor_settings;
pid_ref = motor->pid_ref;
if ((setting->close_loop_type & ANGLE_LOOP) && setting->outer_loop_type == ANGLE_LOOP)
{
if (setting->angle_feedback_source == OTHER_FEED)
pid_measure = *motor->other_angle_feedback_ptr;
else
pid_measure = measure->real_current;
pid_ref = PIDCalculate(&motor->angle_PID, pid_measure, pid_ref);
if (setting->feedforward_flag & SPEED_FEEDFORWARD)
pid_ref += *motor->speed_feedforward_ptr;
}
if ((setting->close_loop_type & SPEED_LOOP) && setting->outer_loop_type & (ANGLE_LOOP | SPEED_LOOP))
{
if (setting->angle_feedback_source == OTHER_FEED)
pid_measure = *motor->other_speed_feedback_ptr;
else
pid_measure = measure->speed_rads;
pid_ref = PIDCalculate(&motor->angle_PID, pid_measure, pid_ref);
if (setting->feedforward_flag & CURRENT_FEEDFORWARD)
pid_ref += *motor->current_feedforward_ptr;
}
if (setting->close_loop_type & CURRENT_LOOP)
{
pid_ref = PIDCalculate(&motor->current_PID, measure->real_current, pid_ref);
}
set = pid_ref;
if (setting->motor_reverse_flag == MOTOR_DIRECTION_REVERSE)
set *= -1;
ECMotor_SpdCMD.mode = 0b010;
ECMotor_SpdCMD.reserve = 0b000;
ECMotor_SpdCMD.ack_type = 0b01;
ECMotor_SpdCMD.spd_target = set;
ECMotor_SpdCMD.max_current = 10;
// 这里随便写的,为了兼容多电机命令.后续应该将tx_id以更好的方式表达电机id,单独使用一个CANInstance,而不是用第一个电机的CANInstance
//memcpy(sender_instance->tx_buff + (motor->motor_can_ins->tx_id - 0x280) * 2, &set, sizeof(uint16_t));
CANSetDLC(motor->motor_can_ins,7);
memcpy(motor->motor_can_ins->tx_buff,&ECMotor_SpdCMD,sizeof(ECMotor_SpdCMD));
//发送数据高位在前!! 交换一下顺序
swap(motor->motor_can_ins->tx_buff+1,motor->motor_can_ins->tx_buff+4);
swap(motor->motor_can_ins->tx_buff+2,motor->motor_can_ins->tx_buff+3);
swap(motor->motor_can_ins->tx_buff+5,motor->motor_can_ins->tx_buff+6);
//memcpy(motor->motor_can_ins->tx_buff+1,&ECMotor_SpdCMD.spd_target,sizeof(float32_t));
if (motor->stop_flag == MOTOR_STOP)
{ // 若该电机处于停止状态,直接将发送buff置零
memcpy(motor->motor_can_ins->tx_buff,0,sizeof(ECMotor_SpdCMD));
}
CANTransmit(motor->motor_can_ins,0.2);
}
}
void ECMotorStop(ECMotorInstance *motor)
{
motor->stop_flag = MOTOR_STOP;
}
void ECMotorEnable(ECMotorInstance *motor)
{
motor->stop_flag = MOTOR_ENALBED;
}
void ECMotorSetRef(ECMotorInstance *motor, float ref)
{
motor->pid_ref = ref;
}
uint8_t ECMotorIsOnline(ECMotorInstance *motor)
{
return DaemonIsOnline(motor->daemon);
}

View File

@ -0,0 +1,130 @@
//
// Created by SJQ on 2023/12/11.
//
#ifndef BASIC_FRAMEWORK_ECA8210_H
#define BASIC_FRAMEWORK_ECA8210_H
#include "stdint.h"
#include "bsp_can.h"
#include "controller.h"
#include "motor_def.h"
#include "daemon.h"
#define EC_MOTOR_MX_CNT 4
#pragma pack(1)
typedef struct
{
uint8_t bug_info:5; //错误信息
uint8_t report_type:3; //报文类别
uint16_t angle_raw:16; //输出端位置数值范围0~65536 对应-12.5f~12.5f,单位 rad
uint16_t speed_raw:12; //输出端转速数值范围0~4095 对应-18.0f~18.0f,单位 rad/s
uint16_t current_raw:12; //实际电流0~4095 对应-30~30A
uint8_t temperature_raw:8;//电机温度:反馈的数值数据类型为无符号 8 位,数值等于实际温度*2+50
}ECMotor_Report_t;
#pragma pack()
typedef struct
{
uint8_t mode:3; //控制模式
float32_t pos_target; //错误信息
uint16_t spd_target:15; //输出端位置数值范围0~65536 对应-12.5f~12.5f,单位 rad
uint16_t max_current:12; //输出端转速数值范围0~4095 对应-18.0f~18.0f,单位 rad/s
uint8_t ack_type:2; //实际电流0~4095 对应-30~30A
}ECMotor_PosCMD_t;
#pragma pack(1)
typedef struct
{
uint8_t ack_type:2;
uint8_t reserve:3;
uint8_t mode:3; //控制模式
float32_t spd_target; //输出端速度指令 单位RPM
uint16_t max_current; //电流限幅 电机电流阈值数值解释0~65536 对应 0~6553.6A比例为10
}ECMotor_SpdCMD_t;
#pragma pack()
typedef struct // EC-A8120
{
uint16_t last_ecd; // 上一次读取的编码器值
uint16_t ecd; // 当前编码器值
float angle_single_round; // 单圈角度
float speed_rads; // speed rad/s
float real_current; // 实际电流
uint8_t temperature; // 温度,C°
float total_angle; // 总角度
int32_t total_round; // 总圈数
float feed_dt;
uint32_t feed_dwt_cnt;
} ECMotor_Measure_t;
typedef struct
{
ECMotor_Measure_t measure;
Motor_Control_Setting_s motor_settings;
float *other_angle_feedback_ptr; // 其他反馈来源的反馈数据指针
float *other_speed_feedback_ptr;
float *speed_feedforward_ptr; // 速度前馈数据指针,可以通过此指针设置速度前馈值,或LQR等时作为速度状态变量的输入
float *current_feedforward_ptr; // 电流前馈指针
PIDInstance current_PID;
PIDInstance speed_PID;
PIDInstance angle_PID;
float pid_ref;
Motor_Working_Type_e stop_flag; // 启停标志
CANInstance *motor_can_ins;
DaemonInstance *daemon;
} ECMotorInstance;
/**
* @brief LK电机
*
* @param config
* @return LKMotorInstance*
*/
ECMotorInstance *ECMotorInit(Motor_Init_Config_s *config);
/**
* @brief
* @attention ref是最外层闭环的输入,
*
* @param motor
* @param ref
*/
void ECMotorSetRef(ECMotorInstance *motor, float ref);
/**
* @brief EC电机计算pid//,bspcan发送电流值(CAN报文)
*
*/
void ECMotorControl();
/**
* @brief EC电机,
*
* @param motor
*/
void ECMotorStop(ECMotorInstance *motor);
/**
* @brief EC电机
*
* @param motor
*/
void ECMotorEnable(ECMotorInstance *motor);
uint8_t ECMotorIsOnline(ECMotorInstance *motor);
#endif //BASIC_FRAMEWORK_ECA8210_H

View File

@ -106,6 +106,7 @@ typedef enum
M2006,
LK9025,
HT04,
ECA8210,
} Motor_Type_e;
/* 电机控制方式枚举 */

View File

@ -1,5 +1,6 @@
#include "motor_task.h"
#include "LK9025.h"
#include "ECA8210.h"
#include "HT04.h"
#include "dji_motor.h"
#include "step_motor.h"
@ -14,7 +15,7 @@ void MotorControlTask()
/* 如果有对应的电机则取消注释,可以加入条件编译或者register对应的idx判断是否注册了电机 */
LKMotorControl();
ECMotorControl();
// legacy support
// 由于ht04电机的反馈方式为接收到一帧消息后立刻回传,以此方式连续发送可能导致总线拥塞
// 为了保证高频率控制,HTMotor中提供了以任务方式启动控制的接口,可通过宏定义切换

View File

@ -33,3 +33,54 @@ void vofa_justfloat_output(float *data, uint8_t num , UART_HandleTypeDef *huart
//HAL_UART_Transmit(huart, (uint8_t *)send_data, 4 * num + 4, 100);
CDC_Transmit_FS((uint8_t *)send_data,4 * num + 4);
}
#define BYTE0(dwTemp) (*(char*)(&dwTemp))
#define BYTE1(dwTemp) (*((char*)(&dwTemp)+1))
#define BYTE2(dwTemp) (*((char*)(&dwTemp)+2))
#define BYTE3(dwTemp) (*((char*)(&dwTemp)+3))
uint8_t DataSendBuf[100];
//匿名上位机
void ANODT_SendF1(int32_t Angle,int32_t speed_rpm,int32_t Angle_target,int32_t speed_target)//F1灵活格式帧
{
uint8_t cnt=0;
DataSendBuf[cnt++]=0xAA; //帧头
DataSendBuf[cnt++]=0xFF; //目标地址
DataSendBuf[cnt++]=0xF1; //功能码
DataSendBuf[cnt++]=16; //数据长度
DataSendBuf[cnt++]=BYTE0(Angle);
DataSendBuf[cnt++]=BYTE1(Angle);
DataSendBuf[cnt++]=BYTE2(Angle);
DataSendBuf[cnt++]=BYTE3(Angle);
DataSendBuf[cnt++]=BYTE0(speed_rpm);
DataSendBuf[cnt++]=BYTE1(speed_rpm);
DataSendBuf[cnt++]=BYTE2(speed_rpm);
DataSendBuf[cnt++]=BYTE3(speed_rpm);
DataSendBuf[cnt++]=BYTE0(Angle_target);
DataSendBuf[cnt++]=BYTE1(Angle_target);
DataSendBuf[cnt++]=BYTE2(Angle_target);
DataSendBuf[cnt++]=BYTE3(Angle_target);
DataSendBuf[cnt++]=BYTE0(speed_target);
DataSendBuf[cnt++]=BYTE1(speed_target);
DataSendBuf[cnt++]=BYTE2(speed_target);
DataSendBuf[cnt++]=BYTE3(speed_target);
uint8_t sc=0; //和校验
uint8_t ac=0; //附加校验
for(uint8_t i=0;i<DataSendBuf[3]+4;i++)
{
sc+=DataSendBuf[i];
ac+=sc;
}
DataSendBuf[cnt++]=sc;
DataSendBuf[cnt++]=ac;
// for(uint8_t i=0;i<cnt;i++)
// HAL_UART_Transmit(&huart6,&DataSendBuf[i],1,100);
CDC_Transmit_FS(DataSendBuf, cnt);
}

View File

@ -17,5 +17,5 @@ typedef union
uint8_t uint8_t[4];
} send_float;
void vofa_justfloat_output(float *data, uint8_t num , UART_HandleTypeDef *huart);
void ANODT_SendF1(int32_t Angle,int32_t speed_rpm,int32_t Angle_target,int32_t speed_target);
#endif // !1#define