多旋翼无人机仿真 rotors_simulator:roll pitch yawrate thrust 控制器
多旋翼无人机仿真 rotors_simulator:roll pitch yawrate thrust 控制器
- 前言
- mav_with_keyboard.launch
- roll_pitch_yawrate_thrust_controller_node.cpp
- RollPitchYawrateThrustControllerNode
- 构造函数
- RollPitchYawrateThrustCallback
- OdometryCallback
- RollPitchYawrateThrustController
- 构造函数
- SetOdometry
- SetRollPitchYawrateThrust
- CalculateRotorVelocities
- ComputeDesiredAngularAcc
- 总结
前言
RotorS 是一个MAV gazebo 仿真系统。
提供了几种多旋翼仿真模型,例如
- AscTec Hummingbird
- AscTec Pelican
- AscTec Firefly
但是仿真系统不限于使用这几种模型
AscTec 是 德国Ascending Technologies公司的缩写。
是很早的无人机了,实物张下面这个样子:
仿真系统中包含很多种仿真传感器,都可以安装在无人机上,例如:
- IMU
- 里程计
- 视觉惯导相机
功能包中包含了几种控制器,包含位置控制,游戏手柄控制灯
github的地址为:https://github.com/ethz-asl/rotors_simulator
在之前的博客总分析 rotors_simulator 的位置控制器 是如何使无人机在 gazebo里面悬停的
如果无人机仅能悬停那么也没什么用啊,在同样的launch文件下,发现了mav_with_keyboard.launch 文件
通过文件的名字可以推断是通过键盘来控制无人机飞行
运行一下发现,运行不了,具体的原因会在下面给出
但是通过这个功能,发现了其中的一个控制接口 roll pitch yawrate thrust
本篇文章主要分析这个控制器是如何实现的。
了解清楚这个控制器,在之后的博客中,会通过应用更普遍的PID控制器,利用这个接口实现无人机的位置。
mav_with_keyboard.launch
这个启动文件对应的是启动 roll_pitch_yawrate_thrust_controller_node
的 节点。
但是 这个 文件有点问题
<include file="$(find rotors_gazebo)/launch/spawn_mav.launch"><arg name="mav_name" value="$(arg mav_name)" /><arg name="model" value="$(find rotors_description)/urdf/mav_generic_odometry_sensor.gazebo" /><arg name="enable_logging" value="$(arg enable_logging)" /><arg name="enable_ground_truth" value="$(arg enable_ground_truth)" /><arg name="log_file" value="$(arg log_file)"/></include>
这个启动了gazebo,加载了无人机
<node name="key_joystick" pkg="rotors_joy_interface" type="key_joystick.py" />
启动这个的时候,会提示以下几个问题,都好解决
- ModuleNotFoundError: No module named uinput ----缺少python的uinput模块 通过指令 pip指令按照就行
- No matching distribution found for python-pygame----缺少python的pygame模块 通过指令 pip指令按照就行
- /usr/bin/env: “python”: 没有那个文件或目录----ubuntu20.04是对应的python3 通过 创建一个链接符号到 python 命令:sudo ln -s /usr/bin/python3 /usr/bin/python
但是启动了,会自己闪退,这个是launch文件运行不成功的原因之一
<node name="rotors_joy_interface" pkg="rotors_joy_interface" type="rotors_joy_interface" />
这个是启动 rotors_joy_interface 功能包下面 joy.cpp 对应生成的可执行文件
<node name="joy_node" pkg="joy" type="joy_node" />
这个功能包,及对应的执行文件就没有。
这个是launch文件启动不成功的原因之二
<node name="roll_pitch_yawrate_thrust_controller_node" pkg="rotors_control" type="roll_pitch_yawrate_thrust_controller_node" output="screen"><rosparamcommand="load" file="$(find rotors_gazebo)/resource/roll_pitch_yawrate_thrust_controller_$(arg mav_name).yaml" /><rosparam command="load" file="$(find rotors_gazebo)/resource/$(arg mav_name).yaml" /><remap from="odometry" to="odometry_sensor1/odometry" /></node>
启动 rotors_control 功能包的 roll_pitch_yawrate_thrust_controller_node.cpp 对应生产的可执行文件
由于只是分析 其 控制的原理与接口,所以只需要分析其代码就ok了,launch文件的问题就不去解决了。
roll_pitch_yawrate_thrust_controller_node.cpp
是一个执行文件的代码,所以从main看起
int main(int argc, char** argv) {ros::init(argc, argv, "roll_pitch_yawrate_thrust_controller_node");
初始化节点
rotors_control::RollPitchYawrateThrustControllerNode roll_pitch_yawrate_thrust_controller_node;ros::spin();return 0;
}
实例化 类
下面来看这个类的内容
RollPitchYawrateThrustControllerNode
构造函数
RollPitchYawrateThrustControllerNode::RollPitchYawrateThrustControllerNode() {
InitializeParams();ros::NodeHandle nh;
初始化参数
声明节点
cmd_roll_pitch_yawrate_thrust_sub_ = nh.subscribe(kDefaultCommandRollPitchYawrateThrustTopic, 1,&RollPitchYawrateThrustControllerNode::RollPitchYawrateThrustCallback, this);
订阅控制指令
odometry_sub_ = nh.subscribe(kDefaultOdometryTopic, 1,&RollPitchYawrateThrustControllerNode::OdometryCallback, this);
订阅里程计
motor_velocity_reference_pub_ = nh.advertise<mav_msgs::Actuators>(kDefaultCommandMotorSpeedTopic, 1);
发布电机转速
初始化参数就不看了,就是初始化的各个方向 角度和角速度的增益
来看订阅的两个回调函数
RollPitchYawrateThrustCallback
控制指令的回调函数
void RollPitchYawrateThrustControllerNode::RollPitchYawrateThrustCallback(const mav_msgs::RollPitchYawrateThrustConstPtr& roll_pitch_yawrate_thrust_reference_msg) {
mav_msgs::EigenRollPitchYawrateThrust roll_pitch_yawrate_thrust;mav_msgs::eigenRollPitchYawrateThrustFromMsg(*roll_pitch_yawrate_thrust_reference_msg, &roll_pitch_yawrate_thrust);
转成eigen的格式
roll_pitch_yawrate_thrust_controller_.SetRollPitchYawrateThrust(roll_pitch_yawrate_thrust);
对应格式的 控制指令 送入控制器中
OdometryCallback
里程计回调函数
void RollPitchYawrateThrustControllerNode::OdometryCallback(const nav_msgs::OdometryConstPtr& odometry_msg) {
EigenOdometry odometry;eigenOdometryFromMsg(odometry_msg, &odometry);
转成eigen 的里程计信息格式
roll_pitch_yawrate_thrust_controller_.SetOdometry(odometry);
将eigen的里程计信息格式送入 控制器中
Eigen::VectorXd ref_rotor_velocities;roll_pitch_yawrate_thrust_controller_.CalculateRotorVelocities(&ref_rotor_velocities);
获得控制器 最终 计算的 电机转速
mav_msgs::ActuatorsPtr actuator_msg(new mav_msgs::Actuators);
构造 电机转速的 变量
actuator_msg->angular_velocities.clear();for (int i = 0; i < ref_rotor_velocities.size(); i++)actuator_msg->angular_velocities.push_back(ref_rotor_velocities[i]);actuator_msg->header.stamp = odometry_msg->header.stamp;
赋值电机转速
motor_velocity_reference_pub_.publish(actuator_msg);
发布电机转速
下面来看在控制器里具体执行的操作,是如何计算得到电机转速的
RollPitchYawrateThrustController
构造函数
RollPitchYawrateThrustController::RollPitchYawrateThrustController(): initialized_params_(false),controller_active_(false) {InitializeParameters();
}
构造函数 初始化参数标志位为0 控制器激活标志位为0
初始化参数
SetOdometry
void RollPitchYawrateThrustController::SetOdometry(const EigenOdometry& odometry) {odometry_ = odometry;
}
获得里程计数据
赋值给类的成员变量
SetRollPitchYawrateThrust
获得控制指令
void RollPitchYawrateThrustController::SetRollPitchYawrateThrust(const mav_msgs::EigenRollPitchYawrateThrust& roll_pitch_yawrate_thrust) {roll_pitch_yawrate_thrust_ = roll_pitch_yawrate_thrust;controller_active_ = true;
}
获得控制指令,赋值给类的成员变量
控制器激活
CalculateRotorVelocities
计算电机转速
assert(rotor_velocities);assert(initialized_params_);
判断是否有这两个参数
rotor_velocities->resize(vehicle_parameters_.rotor_configuration_.rotors.size());
电机转速清零
if (!controller_active_) {*rotor_velocities = Eigen::VectorXd::Zero(rotor_velocities->rows());return;}
如果没有控制指令,那么控制器就没有激活 所有电机的转速为0
Eigen::Vector3d angular_acceleration;ComputeDesiredAngularAcc(&angular_acceleration);
计算期望的角加速度
Eigen::Vector4d angular_acceleration_thrust;angular_acceleration_thrust.block<3, 1>(0, 0) = angular_acceleration;
将3个方向的力,加上推力方向的力
angular_acceleration_thrust(3) = roll_pitch_yawrate_thrust_.thrust.z();
最后是直接赋值了推力的大小
*rotor_velocities = angular_acc_to_rotor_velocities_ * angular_acceleration_thrust;*rotor_velocities = rotor_velocities->cwiseMax(Eigen::VectorXd::Zero(rotor_velocities->rows()));*rotor_velocities = rotor_velocities->cwiseSqrt();
根据电机混控参数 分配各电机转速
ComputeDesiredAngularAcc
计算期望角加速度
void RollPitchYawrateThrustController::ComputeDesiredAngularAcc(Eigen::Vector3d* angular_acceleration) const {
assert(angular_acceleration);
判断有这个变量
Eigen::Matrix3d R = odometry_.orientation.toRotationMatrix();
获得无人机的姿态旋转矩阵
double yaw = atan2(R(1, 0), R(0, 0));
根据旋转矩阵求得yaw角
Eigen::Matrix3d R_des;R_des = Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()) // yaw* Eigen::AngleAxisd(roll_pitch_yawrate_thrust_.roll, Eigen::Vector3d::UnitX()) // roll* Eigen::AngleAxisd(roll_pitch_yawrate_thrust_.pitch, Eigen::Vector3d::UnitY()); // pitch
计算得到期望的旋转矩阵
Eigen::Matrix3d angle_error_matrix = 0.5 * (R_des.transpose() * R - R.transpose() * R_des);Eigen::Vector3d angle_error;vectorFromSkewMatrix(angle_error_matrix, &angle_error);
通过旋转矩阵 计算角度偏差
Eigen::Vector3d angular_rate_des(Eigen::Vector3d::Zero());
声明并清零期望角速度值
angular_rate_des[2] = roll_pitch_yawrate_thrust_.yaw_rate;
把控制指令里面的期望航向角速度 赋值 到向量中
Eigen::Vector3d angular_rate_error = odometry_.angular_velocity - R_des.transpose() * R * angular_rate_des;
计算得到角速度偏差
*angular_acceleration = -1 * angle_error.cwiseProduct(normalized_attitude_gain_)- angular_rate_error.cwiseProduct(normalized_angular_rate_gain_)+ odometry_.angular_velocity.cross(odometry_.angular_velocity);
根据角度偏差、角速度偏差、实际角速度 计算得到 期望的角加速度
总结
其中的整个节点逻辑和之前的位置控制类似
在node cpp中获得控制指令和里程计数据,转成 控制器需要的数据格式
控制器中的关键部分就是 期望角角速度的计算
核心思想是:
通过旋转矩阵计算得到 角度偏差 和角速度偏差
根据 角度偏差、角速度偏差、实际角速度 计算得到 期望角加速度
多旋翼无人机仿真 rotors_simulator:roll pitch yawrate thrust 控制器相关推荐
- 多旋翼无人机仿真 rotors_simulator:用键盘控制无人机飞行
多旋翼无人机仿真 rotors_simulator:用键盘控制无人机飞行 前言 书接上文 接口测试 键盘指令发布 指令转换与发布 修改 rotors_simulator 的控制接口节点 测试 前言 R ...
- 多旋翼无人机仿真 rotors_simulator 是如何悬停的(一)
多旋翼无人机仿真 rotors_simulator 是如何悬停的(一) 前言 mav_hovering_example.launch mav_generic_odometry_sensor.gazeb ...
- 【rotors】多旋翼无人机仿真(三)——SE3控制
[rotors]多旋翼无人机仿真(一)--搭建rotors仿真环境 [rotors]多旋翼无人机仿真(二)--设置飞行轨迹 [rotors]多旋翼无人机仿真(三)--SE3控制 [rotors]多旋翼 ...
- 【rotors】多旋翼无人机仿真(四)——参数补偿和PID控制
[rotors]多旋翼无人机仿真(一)--搭建rotors仿真环境 [rotors]多旋翼无人机仿真(二)--设置飞行轨迹 [rotors]多旋翼无人机仿真(三)--SE3控制 [rotors]多旋翼 ...
- 【rotors】多旋翼无人机仿真(二)——设置飞行轨迹
[rotors]多旋翼无人机仿真(一)--搭建rotors仿真环境 [rotors]多旋翼无人机仿真(二)--设置飞行轨迹 [rotors]多旋翼无人机仿真(三)--SE3控制 [rotors]多旋翼 ...
- 【rotors】多旋翼无人机仿真(一)——搭建rotors仿真环境
[rotors]多旋翼无人机仿真(一)--搭建rotors仿真环境 [rotors]多旋翼无人机仿真(二)--设置飞行轨迹 [rotors]多旋翼无人机仿真(三)--SE3控制 [rotors]多旋翼 ...
- 【ROSGAZEBO】多旋翼无人机仿真(六)——SE(3)几何姿态控制器
[ROS&GAZEBO]多旋翼无人机仿真(一)--搭建仿真环境https://blog.csdn.net/qq_37680545/article/details/123185002 [ROS& ...
- 四旋翼无人机仿真之hector_quadrotor无人机(ROS + Gazebo)(三)传感器数据读取与复现(IMU、GPS)
系列文章目录 文章1:四旋翼无人机仿真之hector_quadrotor无人机(ROS + Gazebo) 文章2:四旋翼无人机仿真之hector_quadrotor(二)键盘teleop_twist ...
- 四旋翼无人机仿真之hector_quadrotor无人机(ROS + Gazebo)(一)
这里写自定义目录标题 应用环境 hector_quadrotor 功能包结构简介 hector_quadrotor 功能包安装 1. 安装所需依赖库 2. 下载.安装hector_quadrotor ...
最新文章
- 匿名黑客Anonymous实施的8次最强攻击
- Yii2 解决2006 MySQL server has gone away问题
- linux I/O--IO原理和几种零拷贝机制(五)
- zhcon解决Ubuntu命令行模式乱码问题
- 网关Spring Cloud Gateway科普
- Java开发趋势:2019年展望
- xampp默认mysql数据库root密码的修改
- HDU2161 Primes
- 康众平板探测器_2020-2025年数字化X线探测器行业市场深度调研及投资前景预测分析报告 数字化设备成为市场主流...
- Android-- Dialog对话框的使用方法
- 剑指offer——面试题4:替换空格
- 上传分片切片大文件 XLSX/CSV/TXT
- System.ConfigurationManager类用于对配置文件的读取
- PJAX,站点加速之翼
- 如何使用fiddler抓取APP接口
- 主流的商业智能BI工具推荐,学会数据分析没难度
- 经典兔子问题有一对兔子从出生后第3个月起每个月都生一对兔子
- Pomodoro Technique
- 计算机ppt培训心得体会,制作ppt学习心得体会
- uni-app z-index无效的解决办法(遮罩层)
热门文章
- 关于不使用firefly补丁对系统进行美化的探讨(转)
- eclipse3.6 太阳神版 中文汉化插件
- OPengl学习(二)——opengl环境搭建
- 上网行为安全之深信服用户认证技术和用户、组管理
- 无影云服务器没有网络怎么办?
- 富人越富,穷人越穷,我为什么反对PoS
- 2017寒假作业 计科1501 李俊01
- 五子棋java毕业设计论文_基于Java的五子棋游戏的设计毕业论文,课程设计,研究生文献...
- arduino笔记15:按键开关输入
- TCP穿透主流商用NAT产品的主要技术研究