25_R1_chassis/User/device/navi.c

350 lines
12 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 "navi.h"
//导航初始化一系列参数
int8_t Navi_init(ops_t *o,const ops_param_t *param,Action_POS_t *pos){
if(o ==NULL) return DEVICE_ERR;
if(param == NULL) return DEVICE_ERR;
o->param = param;
//底盘路径速度pid初始化
PID_init(&o->path_speed_pid,PID_POSITION,(&o->param->ops_pid.path_speed_pid_param));
/*全场定位pid初始化*/
//全场定位跑路径的xy方向速度环pid
PID_init(&o->pid_PosSpeed_xy, PID_POSITION,(&o->param->ops_pid.pid_PosSpeed_xy_param));
/* 初始化角度纠正PID */
PID_init(&o->pid_OutAngle,PID_POSITION,(&o->param->ops_pid.pid_OutAngle_param));//外环
PID_init(&o->pid_InnerAngle,PID_POSITION,(&o->param->ops_pid.pid_InnerAngle_param));//内环
PID_init(&o->pid_OutAngle_hold,PID_POSITION,(&o->param->ops_pid.pid_OutAngle_hold_param));//外环
PID_init(&o->pid_InnerAngle_hold,PID_POSITION,(&o->param->ops_pid.pid_InnerAngle_hold_param));//内环
//底盘xy方向位置环pid初始化
PID_init(&o->pid_pos_xy_inner,PID_POSITION,(&o->param->ops_pid.pid_pos_xy_inner_param));
PID_init(&o->pid_pos_xy_outer,PID_POSITION,(&o->param->ops_pid.pid_pos_xy_outer_param));
//sick
PID_init(&o->pid_sick_inner,PID_POSITION,(&o->param->ops_pid.pid_sick_inner_param));
PID_init(&o->pid_sick_outer,PID_POSITION,(&o->param->ops_pid.pid_sick_out_param));
//全场定位底盘坐标初始化
o->chassis_pos->pos_x=0;
o->chassis_pos->pos_y=0;
o->chassis_pos->pos_lastX=0;
o->chassis_pos->pos_lastY=0;
//码盘反馈的坐标
o->chassis_pos = pos;
//经过sick调整后码盘反馈的坐标
o->chassis_pos_offest->pos_x = pos->pos_x + o->sick_offest.x;
o->chassis_pos_offest->pos_y = pos->pos_y + o->sick_offest.y;
//底盘获取地图
o->chassis_map = get_map_pointer();
//设置全场定位允许的误差范围
o->chassis_map->pos_mistake = 30;
//小量程sick1分米大概变30大量程sick1分米大概变60
o->chassis_map->sick_mistake = 15;
//o->state.points_num = param->path_num;
//标志位初始化
o->chassis_map->points_flag = 0;
o->navi_flag = 0;
o->sick_flag = 0;
//初始化sick微分数据
for(int i=0 ;i<4 ; i++){
o->sick_d.sick_distance[i] = 0;
o->sick_d.sick_distance_last[i] = 0;
o->sick_d.sick_derivative[i] = 0;
o->sick_d.status[i] = normal;
}
return DEVICE_OK;
}
/*判断是否寻迹完成函数(全场定位)*/
bool isArrive_path(point_t p,ops_t *o)
{
uint16_t xArrive = 0, yArrive = 0;
xArrive = abs_float_double(p.x,o->chassis_pos->pos_x) < o->chassis_map->pos_mistake ? 1:0;
yArrive = abs_float_double(p.y,o->chassis_pos->pos_y) < o->chassis_map->pos_mistake ? 1:0;
if(xArrive && yArrive ) return true;
else return false;
}
//利用C板imu纠正角度
fp32 ops9_AngleCorr(ops_t *o,fp32 hope_angle,pid_type_def *outer_yaw_pid_set,pid_type_def *inner_yaw_pid_set){
fp32 delta_angle,delta_wz;
if(hope_angle - o->chassis_pos->pos_yaw >180){
hope_angle -= 360;
}
else if(hope_angle - o->chassis_pos->pos_yaw <-180){
hope_angle += 360;
}
//外环角度纠正
delta_angle = PID_calc(outer_yaw_pid_set,o->chassis_pos->pos_yaw,hope_angle);
//内环速度纠正
delta_wz = PID_calc(inner_yaw_pid_set,o->ops_gyro.z,delta_angle);
return delta_wz;
}
//底盘xy速度计算(全场定位)
void POS_chassis_set(ops_t *o,fp32 vx_set, fp32 vy_set, fp32 yaw_angle_set){
o->final_out.action.vx = PID_calc(&o->pid_PosSpeed_xy, o->chassis_pos->pos_Vx,vx_set);
o->final_out.action.vy = PID_calc(&o->pid_PosSpeed_xy, o->chassis_pos->pos_Vy,vy_set);
o->final_out.action.vz = ops9_AngleCorr(o,yaw_angle_set,&o->pid_OutAngle,&o->pid_InnerAngle);
}
//定点控制
void hold_point(ops_t *o,point_t p,fp32 yaw_angle_set){
fp32 delta_x,delta_y;
fp32 delta_vx,delta_vy;
fp32 hold_vx,hold_vy;
//x
delta_x = PID_calc(&o->pid_pos_xy_outer,o->chassis_pos->pos_x,p.x);
delta_vx = PID_calc(&o->pid_pos_xy_inner,o->chassis_pos->pos_Vx,delta_x);
//y
delta_y = PID_calc(&o->pid_pos_xy_outer,o->chassis_pos->pos_y,p.y);
delta_vy = PID_calc(&o->pid_pos_xy_inner,o->chassis_pos->pos_Vy,delta_y);
//目标速度
hold_vx = delta_vy*cos((o->chassis_pos->pos_yaw)*PI/180.0f) - delta_vx*sin((o->chassis_pos->pos_yaw)*PI/180.0f);
hold_vy = delta_vy*sin((o->chassis_pos->pos_yaw)*PI/180.0f) + delta_vx*cos((o->chassis_pos->pos_yaw)*PI/180.0f);
//底盘速度
o->final_out.action.vx = hold_vx;
o->final_out.action.vy = hold_vy;
o->final_out.action.vz = ops9_AngleCorr(o,yaw_angle_set,&o->pid_OutAngle_hold,&o->pid_InnerAngle_hold);
}
//sick卡点
void sick_point(ops_t *o){
//x是x轴的sick,y是y轴的sick每个轴各两个
fp32 delta_x,delta_y;
fp32 delta_vx,delta_vy;
//x轴
if(o->sick_d.status[0] == normal) {
delta_x = -PID_calc(&o->pid_sick_outer,o->sick_distance[0],o->chassis_map->sick->sick_qian);
delta_vx = PID_calc(&o->pid_sick_inner,o->chassis_pos->pos_Vx,delta_x);
}
else if(o->sick_d.status[2] == normal){
delta_x = -PID_calc(&o->pid_sick_outer,o->sick_distance[2],o->chassis_map->sick->sick_hou);
delta_vx = PID_calc(&o->pid_sick_inner,o->chassis_pos->pos_Vx,delta_x);
}
else{
delta_vx = 0;
}
//y轴
if(o->sick_d.status[1] == normal){
delta_y = -PID_calc(&o->pid_sick_outer,o->sick_distance[1],o->chassis_map->sick->sick_you);
delta_vy = PID_calc(&o->pid_sick_inner,o->chassis_pos->pos_Vy,delta_y);
}
else if(o->sick_d.status[3] == normal){
delta_y = -PID_calc(&o->pid_sick_outer,o->sick_distance[3],o->chassis_map->sick->sick_zuo);
delta_vy = PID_calc(&o->pid_sick_inner,o->chassis_pos->pos_Vy,delta_y);
}
else{
delta_vy = 0;
}
//底盘速度
o->final_out.sick.vx = delta_vx;
o->final_out.sick.vy = delta_vy;
o->final_out.sick.vz = 0;//启用sick时不需要底盘旋转
}
// 计算sick微分函数
void sick_calculate_d(ops_t *o){
static uint32_t last_calc_time =0;
uint32_t current_time = HAL_GetTick();
// 计算实际时间差(ms)
uint32_t time_diff = current_time - last_calc_time;
// 至少400ms才计算一次
//采样频率不能太高!!
if (time_diff < 400) {
return;
}
// 转换为秒
float dt = time_diff / 1000.0f;
last_calc_time = current_time;
for(int i=0; i<4; i++){
o->sick_d.sick_distance[i] = o->sick_distance[i];
o->sick_d.sick_distance_diff[i] = o->sick_d.sick_distance[i] - o->sick_d.sick_distance_last[i];
o->sick_d.sick_derivative[i] = (float)o->sick_d.sick_distance_diff[i] / dt;
o->sick_d.sick_distance_last[i] = o->sick_distance[i];
switch(o->sick_d.status[i]){
/*目前这套switch能用但是没有考虑到一种情况即有车挡住了sick使标志位变成了block
但它缓慢后退然后平移离开导致标志位不能变回normal后期可以加一个如果底盘没有动微分值改变
说明被阻挡*/
case normal:
// 检查是否达到最大测量值 小量程sick测量最大值3238大量程sick测量最大值6487
if(o->sick_d.sick_derivative[i] == 0 &&
((o->sick_d.sick_distance[i] > 3200 && o->sick_d.sick_distance[i] < 3300) ||
(o->sick_d.sick_distance[i] > 6400 && o->sick_d.sick_distance[i] < 6500))){
o->sick_d.status[i] = max_reached;
}
// 检查是否被阻挡
else if(o->sick_d.sick_derivative[i] < -1500){
o->sick_d.status[i] = blocked;
}
break;
case blocked:
// 阻挡解除
if(o->sick_d.sick_derivative[i] > 1500){
o->sick_d.status[i] = normal;
}
break;
case max_reached:
// 从最大测量值恢复的条件
if(o->sick_d.sick_derivative[i] != 0 ){
if(o->sick_d.sick_derivative[i] < -1500){
o->sick_d.status[i] = blocked;
}
else{
o->sick_d.status[i] = normal;
}
}
break;
}
}
}
//寻迹函数
void go_path(ops_t *o,CMD_ACTION_t *ops_out){
//检查码盘是否正常
if(o->chassis_pos->Action_ready == 1){
//路径未完成
if(o->chassis_map->points_flag == 0){
//计算距离
float delta_x = o->chassis_map->target->x - o->chassis_pos->pos_x;
float delta_y = o->chassis_map->target->y - o->chassis_pos->pos_y;
float distance = sqrtf(delta_x * delta_x + delta_y * delta_y);
//计算速度
//o->chassis_speed_set = o->chassis_map->target->v;//此处设定为固定的期望速度
o->chassis_speed_set = PID_calc(&o->path_speed_pid,-distance,0);
//速度分解
float chassis_vx,chassis_vy;//底盘xy分速度
if (distance > 1e-6f) { // 避免除零
chassis_vx = o->chassis_speed_set * (delta_x / distance);
chassis_vy = o->chassis_speed_set * (delta_y / distance);
}
else{
chassis_vx = 0;
chassis_vy = 0;
}
o->navi_flag = 0;
//未到达导航点附近
if(!isArrive_path(*(o->chassis_map->target),o)){
POS_chassis_set(o,chassis_vx,chassis_vy,o->chassis_map->target->angle);
o->navi_flag = 1;
}
else{
//已到达目标点附近,进行微调
hold_point(o,*(o->chassis_map->target),o->chassis_map->target->angle);
o->navi_flag = 2;
}
ops_out->out.Vx = o->final_out.action.vx;
ops_out->out.Vy = o->final_out.action.vy;
ops_out->out.Vw = o->final_out.action.vz;
//路径完成,具体的判断值根据之后导航速度提上来之后再定
if (fabsf(o->final_out.action.vx) < 1000.0f &&
fabsf(o->final_out.action.vy) < 1000.0f &&
fabsf(o->final_out.action.vz) < 1000.0f){
// o->chassis_map->points_flag = 1;
o->sick_flag = 0;
}
}
// else if(o->chassis_map->points_flag == 1 &&o->chassis_map->sick->sick_flag == 1){
// if(o->sick_flag != 1){
//
// o->navi_flag = 3;
//
// bool x_has_valid_sick = false; // X 轴是否有可用的 Sick
// bool y_has_valid_sick = false; // Y 轴是否有可用的 Sick
// bool x_adjusted = false; // X 轴是否达标
// bool y_adjusted = false; // Y 轴是否达标
// // X 轴检查
// if (o->sick_d.status[0] == normal) { // 前 Sick 可用
// x_adjusted = (abs_float_double(o->sick_distance[0], o->chassis_map->sick->sick_qian) < o->chassis_map->sick_mistake);
// x_has_valid_sick = true;
// }
// else if (o->sick_d.status[2] == normal) { // 后 Sick 可用
// x_adjusted = (abs_float_double(o->sick_distance[2], o->chassis_map->sick->sick_hou) < o->chassis_map->sick_mistake);
// x_has_valid_sick = true;
// }
// // 如果 X 轴两个 Sick 都不可用x_has_valid_sick 保持 false
// // Y 轴检查
// if (o->sick_d.status[1] == normal) { // 右 Sick 可用
// y_adjusted = (abs_float_double(o->sick_distance[1], o->chassis_map->sick->sick_you) < o->chassis_map->sick_mistake);
// y_has_valid_sick = true;
// }
// else if (o->sick_d.status[3] == normal) { // 左 Sick 可用
// y_adjusted = (abs_float_double(o->sick_distance[3], o->chassis_map->sick->sick_zuo) < o->chassis_map->sick_mistake);
// y_has_valid_sick = true;
// }
// // 如果 Y 轴两个 Sick 都不可用y_has_valid_sick 保持 false
// // 只有 X 轴和 Y 轴各至少有一个 Sick 可用,且所有可用 Sick 都达标时,才标记完成
// if (x_has_valid_sick && y_has_valid_sick && x_adjusted && y_adjusted) {
//
// o->sick_flag = 1;
// o->sick_offest.x = o->chassis_map->target->x - o->chassis_pos->pos_x;
// o->sick_offest.y = o->chassis_map->target->y - o->chassis_pos->pos_y;
// o->navi_flag = 4;
// }
//
// sick_point(o);
//
//// ops_out->out.Vx = o->final_out.sick.vx;
//// ops_out->out.Vy = o->final_out.sick.vy;
//// ops_out->out.Vw = o->final_out.sick.vz;
// }
// else{
// ops_out->out.Vx = 0;
// ops_out->out.Vy = 0;
// ops_out->out.Vw = 0;
// }
// }
}else{
ops_out->out.Vx = 0;
ops_out->out.Vy = 0;
ops_out->out.Vw = 0;
}
}