gimbal/User/module/chassis.c

297 lines
9.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
µ×ÅÌÄ£×é
*/
#include "cmsis_os2.h"
#include <stdlib.h>
#include "bsp/mm.h"
#include "bsp/can.h"
#include "component/ahrs.h"
#include "device/motor_rm.h"
#include "device/motor.h"
#include "module/chassis.h"
/**
* @brief µ×ÅÌСÍÓÂÝģʽÏà¹Ø²ÎÊý
*/
#define CHASSIS_ROTOR_WZ_MIN 0.6f //СÍÓÂÝ×îСËÙ¶È
#define CHASSIS_ROTOR_WZ_MAX 0.8f //СÍÓÂÝ×î´óËÙ¶È
#define M_7OVER72PI (M_2PI * 7.0f / 72.0f) //½Ç¶ÈÆ«ÒÆÁ¿£¨ÓÃÔÚ¸úËæÔÆÌ¨35¡ã£©
#define CHASSIS_ROTOR_OMEGA 0.001f //½ÇËٶȱ仯ƵÂÊ
/**
* @brief ÉèÖõ×ÅÌģʽ
* @param c µ×Å̽ṹÌåÖ¸Õë
* @param mode Ä¿±ê¿ØÖÆÄ£Ê½
* @param now µ±Ç°Ê±¼ä´Á(ms)
* @return CHASSIS_OK:³É¹¦ CHASSIS_ERR_NULL:¿Õ
*/
static int8_t Chassis_SetMode(Chassis_t *c, Chassis_Mode_t mode, uint32_t now) {
if (!c)
return CHASSIS_ERR_NULL;
if (mode == c->mode)
return CHASSIS_OK;
//Ëæ»úÖÖ×Ó£¬Ð¡ÍÓÂÝÄ£Ê½Ëæ»úÉèÖÃÐýת·½Ïò
if (mode == CHASSIS_MODE_ROTOR && c->mode != CHASSIS_MODE_ROTOR) {
srand(now);
c->wz_multi = (rand() % 2) ? -1 : 1;
}
//ÖØÖÃPIDºÍÂ˲¨
for (uint8_t i = 0; i < c->num_wheel; i++) {
PID_Reset(&c->pid.motor[i]);
LowPassFilter2p_Reset(&c->filter.in[i], 0.0f);
LowPassFilter2p_Reset(&c->filter.out[i], 0.0f);
}
c->mode = mode;
return CHASSIS_OK;
}
/**
* @brief СÍÓÂÝģʽ¶¯Ì¬½ÇËÙ¶È
* @param min ×îСËÙ¶È
* @param max ×î´óËÙ¶È
* @param now µ±Ç°Ê±¼ä´Á(ms)
* @return ½ÇËÙ¶ÈÖµ
*/
static float Chassis_CalcWz(const float min, const float max, uint32_t now) {
float wz_vary = fabsf(0.2f * sinf(CHASSIS_ROTOR_OMEGA * (float)now)) + min;
return (wz_vary > max) ? max : wz_vary;
}
/**
* @brief µ×ÅÌģʽ³õʼ»¯
* @param c µ×Å̽ṹÌåÖ¸Õë
* @param param µ×Å̲ÎÊý½á¹¹ÌåÖ¸Õë
* @param mech_zero »úеÁãµãÅ·À­½Ç
* @param target_freq ¿ØÖÆÆµÂÊ(Hz)
* @return CHASSIS_OK:³É¹¦ CHASSIS_ERR_NULL:¿Õ CHASSIS_ERR_TYPE:²»Ö§³ÖµÄģʽ
*/
int8_t Chassis_Init(Chassis_t *c, const Chassis_Params_t *param,
float target_freq) {
if (!c) return CHASSIS_ERR_NULL;
//³õʼ»¯CANͨÐÅ
BSP_CAN_Init();
c->param = param;
c->mode = CHASSIS_MODE_RELAX;
//¸ù¾Ýµ×Å̲»Í¬ÉèÖÃģʽÂÖ×ÓÓë»ìºÏÆ÷
Mixer_Mode_t mixer_mode;
switch (param->type) {
case CHASSIS_TYPE_MECANUM://ÂóÂÖ
c->num_wheel = 4;
mixer_mode = MIXER_MECANUM;
break;
case CHASSIS_TYPE_PARLFIX4:
c->num_wheel = 4;
mixer_mode = MIXER_PARLFIX4;
break;
case CHASSIS_TYPE_PARLFIX2:
c->num_wheel = 2;
mixer_mode = MIXER_PARLFIX2;
break;
case CHASSIS_TYPE_OMNI_CROSS:
c->num_wheel = 4;
mixer_mode = MIXER_OMNICROSS;
break;
case CHASSIS_TYPE_OMNI_PLUS: //È«ÏòÂÖ£¨Àϲ½±øÀàÐÍ£©
c->num_wheel = 4;
mixer_mode = MIXER_OMNIPLUS;
break;
case CHASSIS_TYPE_SINGLE:
c->num_wheel = 1;
mixer_mode = MIXER_SINGLE;
break;
default:
return CHASSIS_ERR_TYPE;
}
//³õʼ»¯Ê±¼ä´Á
c->last_wakeup = 0;
c->dt = 0.0f;
//³õʼ»¯PIDºÍÂ˲¨
for (uint8_t i = 0; i < c->num_wheel; i++) {
PID_Init(&c->pid.motor[i], KPID_MODE_NO_D, target_freq, &param->pid.motor_pid_param);
LowPassFilter2p_Init(&c->filter.in[i], target_freq, param->low_pass_cutoff_freq.in);
LowPassFilter2p_Init(&c->filter.out[i], target_freq, param->low_pass_cutoff_freq.out);
//ÇåÁãµç»ú·´À¡
c->feedback.motor[i].rotor_speed = 0;
c->feedback.motor[i].torque_current = 0;
c->feedback.motor[i].rotor_abs_angle = 0;
c->feedback.motor[i].temp = 0;
}
//³õʼ»¯PIDºÍ»ìºÏÆ÷
PID_Init(&c->pid.follow, KPID_MODE_NO_D, target_freq, &param->pid.follow_pid_param);
Mixer_Init(&c->mixer, mixer_mode);
//ÇåÁãÔ˶¯ÏòÁ¿ºÍÊä³ö
c->move_vec.vx = c->move_vec.vy = c->move_vec.wz = 0.0f;
for (uint8_t i = 0; i < c->num_wheel; i++) {
c->out.motor[i] = 0.0f;
}
//×¢²á´ó½®µç»ú
for (int i = 0; i < c->num_wheel; i++) {
MOTOR_RM_Register(&(c->param->motor_param[i]));
}
return CHASSIS_OK;
}
/**
* @brief ¸üеç»ú·´À¡(IMU+µç»ú״̬)
* @param c µ×Å̽ṹÌåÖ¸Õë
* @param feedback µ×ÅÌ·´À¡Ö¸Õë½á¹¹Ìå
* @return CHASSIS_OK:³É¹¦ CHASSIS_ERR_NULL:¿Õ
*/
int8_t Chassis_UpdateFeedback(Chassis_t *c) {
//¸üÐÂËùÓеç»ú·´À¡
for (uint8_t i = 0; i < c->num_wheel; i++) {
MOTOR_RM_Update(&(c->param->motor_param[i]));
MOTOR_RM_t *rm_motor = MOTOR_RM_GetMotor(&(c->param->motor_param[i]));
c->motors[i] = rm_motor;
MOTOR_RM_t *rm = c->motors[i];
if (rm_motor != NULL) {
c->feedback.motor[i] = rm_motor->feedback;
}else
{
return CHASSIS_ERR_NULL;
}
}
return CHASSIS_OK;
}
/**
* @brief µ×Å̵ç»ú¿ØÖÆ
* @param c µ×Å̽ṹÌåÖ¸Õë
* @param c_cmd ¿ØÖÆÃüÁî
* @param now µ±Ç°Ê±¼ä´Á(ms)
* @return CHASSIS_OK:³É¹¦ CHASSIS_ERR_NULL:¿Õ
*/
int8_t Chassis_Control(Chassis_t *c, const Chassis_CMD_t *c_cmd, uint32_t now) {
if (!c || !c_cmd) return CHASSIS_ERR_NULL;
//¼ÆËã¿ØÖÆÖÜÆÚ
c->dt = (float)(now - c->last_wakeup) / 1000.0f;
c->last_wakeup = now;
if (!isfinite(c->dt) || c->dt <= 0.0f) {
c->dt = 0.001f;
}
if (c->dt < 0.0005f) c->dt = 0.0005f;
if (c->dt > 0.050f) c->dt = 0.050f;
//ÉèÖÃģʽ
Chassis_SetMode(c, c_cmd->mode, now);
//²»Í¬Ä£Ê½Ï¶ÔÓ¦½âË㣨Ô˶¯ÏòÁ¿£©
switch (c->mode) {
case CHASSIS_MODE_BREAK:
c->move_vec.vx = c->move_vec.vy = 0.0f;
break;
case CHASSIS_MODE_INDEPENDENT:
c->move_vec.vx = c_cmd->ctrl_vec.vx;
c->move_vec.vy = c_cmd->ctrl_vec.vy;
break;
default: { //Ò£¿ØÆ÷×ø±ê->»úÌå×ø±êϵ
float beta = c->feedback.encoder_gimbalYawMotor - c->mech_zero;
float cosb = cosf(beta);
float sinb = sinf(beta);
c->move_vec.vx = cosb * c_cmd->ctrl_vec.vx - sinb * c_cmd->ctrl_vec.vy;
c->move_vec.vy = sinb * c_cmd->ctrl_vec.vx + cosb * c_cmd->ctrl_vec.vy;
break;
}
}
//¸ù¾Ýģʽ¼ÆËãµ×Å̽ÇËÙ¶È
switch (c->mode) {
case CHASSIS_MODE_RELAX:
case CHASSIS_MODE_BREAK:
case CHASSIS_MODE_INDEPENDENT:
c->move_vec.wz = 0.0f;
break;
case CHASSIS_MODE_OPEN:
c->move_vec.wz = c_cmd->ctrl_vec.wz;
break;
//ÔÆÌ¨¸úËæ
case CHASSIS_MODE_FOLLOW_GIMBAL:
c->move_vec.wz = PID_Calc(&c->pid.follow, c->mech_zero, c->feedback.encoder_gimbalYawMotor, 0.0f, c->dt);
break;
//ÔÆÌ¨¸úËæ£¨Æ«ÒÆ£©
case CHASSIS_MODE_FOLLOW_GIMBAL_35:
c->move_vec.wz = PID_Calc(&c->pid.follow,c->mech_zero +M_7OVER72PI, c->feedback.encoder_gimbalYawMotor, 0.0f, c->dt);
break;
//СÍÓÂÝ
case CHASSIS_MODE_ROTOR:
c->move_vec.wz = c->wz_multi * Chassis_CalcWz(CHASSIS_ROTOR_WZ_MIN,CHASSIS_ROTOR_WZ_MAX, now);
break;
}
//Ô˶¯Ñ§Äæ½âË㣬Ô˶¯ÏòÁ¿·Ö½âΪµç»úתËÙ
Mixer_Apply(&c->mixer, &c->move_vec, c->setpoint.motor_rpm, c->num_wheel, 500.0f);
for (uint8_t i = 0; i < c->num_wheel; i++) {
float rf = c->setpoint.motor_rpm[i];///Ä¿±êתËÙ
float fb = LowPassFilter2p_Apply(&c->filter.in[i], (float)c->feedback.motor[i].rotor_speed);
float out_current;
switch (c->mode) {
case CHASSIS_MODE_BREAK:
case CHASSIS_MODE_FOLLOW_GIMBAL:
case CHASSIS_MODE_FOLLOW_GIMBAL_35:
case CHASSIS_MODE_ROTOR:
case CHASSIS_MODE_INDEPENDENT:
out_current = PID_Calc(&c->pid.motor[i], c->setpoint.motor_rpm[i], fb, 0.0f, c->dt);
break;
case CHASSIS_MODE_OPEN:
out_current = c->setpoint.motor_rpm[i] / 7000.0f;
break;
case CHASSIS_MODE_RELAX:
out_current = 0.0f;
break;
}
//µÍͨÂ˲¨ºÍÏÞ·ù
c->out.motor[i] = LowPassFilter2p_Apply(&c->filter.out[i], out_current);
Clip(&c->out.motor[i], -c->param->limit.max_current, c->param->limit.max_current);
}
return CHASSIS_OK;
}
/**
* @brief µç»úÊä³ö
* @param c µ×Å̽ṹÌåÖ¸Õë
*/
void Chassis_Output(Chassis_t *c) {
if (!c)
return;
//ÿ¸öµç»úÄ¿±êÊä³ö
for (uint8_t i = 0; i < c->num_wheel; i++) {
MOTOR_RM_t *rm = c->motors[i];
if (!rm) continue;
MOTOR_RM_SetOutput(&rm->param, c->out.motor[i]);
}
//µ÷ÓÃctrl
for (uint8_t i = 0; i < c->num_wheel; i++) {
MOTOR_RM_t *rm = c->motors[i];
if (rm) {
MOTOR_RM_Ctrl(&rm->param);
}
}
}
/**
* @brief ÖØÖõ×ÅÌÊä³ö
* @param c µ×Å̽ṹÌåÖ¸Õë
*/
void Chassis_ResetOutput(Chassis_t *c) {
if (!c) return;
for (uint8_t i = 0; i < c->num_wheel; i++) {
MOTOR_RM_t *m = c->motors[i];
if (m) {
MOTOR_RM_Relax(&(m->param));
}
}
}