Track
_src=src; // 复制原始图像给_src
/** 处于未锁定装甲板状态 */
if(!locate_target){
// 初始化成功进入锁定装甲板状态
if(Initial(Armors)) locate_target = true;
else locate_target = false;
// 接收电控发的角度
Solve_pitch = AS.Robot_msg.Controller_pitch;
Solve_yaw = AS.Robot_msg.Controller_yaw;
return false;
}
首先就是未处于装甲板锁定状态的情况,在这里会更改状态,进入装甲板锁定模式,接收电控角度(先别管从哪里来的)
关于电控数据如何接收将在 "串口通信篇" 进行详解,这里只需要知道 AS.Robot_msg 可以拿到角度的数据
至于锁定哪个装甲板将在 Initial() 里面决定,这个函数的介绍在 Initial 小节说明
这里就需要对基本的角度进行一个简单的介绍了,我们将角度分为 pitch、yaw、roll 三轴角度
pitch():俯仰,将物体绕X轴旋转(localRotationX)

yaw():航向,将物体绕Y轴旋转(localRotationY)

roll():横滚,将物体绕Z轴旋转(localRotationZ)

相信这三张图足够你对这三个角度信息有一个初步的认识,在机器人上,我们需要掌控的便是云台信息
如果你看过我们的机器人,那么你便会发现云台是一个两轴位移(pithch、yaw)的结构,至于为什么不接收 roll 的数据
是因为我们的机器人一般情况下不具备 roll 方向,但是请注意,在坡上或者轮腿机器人,是具备roll信息的,一般我们默认为0°

不要在意画技
/** 锁定装甲板状态 */
else{
if(track_start){
t = time;
track_start = false;
return false;
}
dt = seconds_duration (time - t).count(); // 计算时间间隔
t = time; // 更新时间
/** 锁定装甲板 */
if(!Lock_Armor(Armors,dt)) return false;
/** 已锁定装甲板,进行枪管角度计算 */
Eigen::Vector3d rpy = AS.Barrel_Solve(enemy_armor.world_position);
Solve_pitch = rpy[1];
Solve_yaw = rpy[2];
/** 进入跟踪状态,进行陀螺检测 */
if(tracker_state == TRACKING){
Spin_detect(); // 陀螺状态检测
}
}
关于 if(track_strat) 部分与跟踪关系不大,这里不详细展开
dt = seconds_duration (time - t).count(); // 计算时间间隔
t = time; // 更新时间
这里计算时间间隔,会后续的预测做准备
这里需要说明的就是关于时间t的结构了 chrono_time t 下面是 chrono_time 原始定义,在robot_status.h里面
* 重命名模块名
* std::chrono::duration<intmax_t N, intmax_t D = 1> N表示分子,D表示分母
*
* 使用示例:
* auto start = std::chrono::high_resolution_clock::now();
* for (int i = 0; i < 1000000000; ++i) {}
* auto end = std::chrono::high_resolution_clock::now();
* auto duration = milliseconds_duration(end-start).count();
* std::cout << duration;
using seconds_duration = std::chrono::duration<double>; //秒
using milliseconds_duration = std::chrono::duration<double,std::milli>; //毫秒
using microseconds_duration = std::chrono::duration<double,std::micro>; //微秒
using chrono_time = decltype(std::chrono::high_resolution_clock::now()); //当前时间 decltype()获取返回变量类型
这里的using相信你并不陌生,"using namespace std" 这两者的用法是不一样的,using主要有三种用法
导入命名空间
// 导入整个命名空间到当前作用域 using namespace std;指定别名
typedef int T; // 用 T 代替 int using T = int; // 用 T 代替 int在派生类中引用基类成员(类似声明)
class Base{ public: void ShowName(); int Value; } class Derived : private Base{ public: using Base::Value; using Base::ShowName; }
/** 锁定装甲板 */
if(!Lock_Armor(Armors,dt)) return false;
/** 已锁定装甲板,进行枪管角度计算 */
Eigen::Vector3d rpy = AS.Barrel_Solve(enemy_armor.world_position);
Solve_pitch = rpy[1];
Solve_yaw = rpy[2];
通过在前面的 Initial() 决定好的锁定装甲板,在 Lock_Armor() 里面持续锁定对应装甲板
然后通过锁定的装甲板,使用 AS.Barrel_Solve() 计算pitch和yaw的角度值
关于枪管角度如何计算和对应的模型,将在 "空间位姿解算篇" 的弹道闭环里面进行讲解
/** 进入跟踪状态,进行陀螺检测 */
if(tracker_state == TRACKING){
Spin_detect(); // 陀螺状态检测
}
陀螺部分将在 "整车观测篇" 的陀螺状态里面进行讲解