多旋翼无人机仿真 rotors_simulator:基于PID控制器的位置控制---高度控制

news2024/11/16 1:19:42

多旋翼无人机仿真 rotors_simulator:基于PID控制器的位置控制---高度控制

  • 前言
  • 构建软件框架
    • 编译 cpp
    • 构建代码
      • main函数构建
      • 构建类的定义
  • 订阅无人机里程计信息
  • 垂直位置控制
    • 串级P控制
      • 收敛结果
      • 收敛过程
    • 串级PID控制

在这里插入图片描述

前言

无人机(Unmanned Aerial Vehicle),指的是一种由动力驱动的、无线遥控或自主飞行、机上无人驾驶并可重复使用的飞行器,飞机通过机载的计算机系统自动对飞行的平衡进行有效的控制,并通过预先设定或飞机自动生成的复杂航线进行飞行,并在飞行过程中自动执行相关任务和异常处理。

在前面的博客中,分析了 rotors_simulator 一个开源的无人机gazebo的仿真系统的一个控制接口(roll、pitch、yawrate、thrust),并通过键盘发布控制指令,使飞机飞了起来,但是真正实验过的人则知道,起控制会飞常难,需要一直调整键盘,稍微一不注意,无人机就飞走了。
其原因就是这个接口在无人机内部并没有位置控制的闭环。

在这篇文章中,分析了自动控制原理;并在这篇文章中分析了无人机各种模式的控制框图。

本篇博客主要就是基于无人机的控制原理与控制框图,基于PID控制器,利用rotors_simulator 的控制接口,实现无人机的位置控制。

构建软件框架

编译 cpp

在cmakelists.txt中加入如下

add_executable(pid_position_controller_node
  src/nodes/pid_position_controller_node.cpp)
add_dependencies(pid_position_controller_node ${catkin_EXPORTED_TARGETS})
target_link_libraries(pid_position_controller_node
  roll_pitch_yawrate_thrust_controller ${catkin_LIBRARIES})

生成 pid_position_controller_node 可执行文件

构建代码

main函数构建

int main(int argc, char** argv) {
    // 初始化节点
    ros::init(argc, argv, "pid_position_controller_node");
    // 终端输出开始信息
    std::cout<< "pid position controll start" <<std::endl;
    // 实例化 类
    rotors_control::PidPositionControllerNode pid_position_controller_node;
    ros::spin();
    return 0;
}

main函数构建

  • 初始化节点
  • 终端输出开始信息
  • 实例化 类

构建类的定义

新建pid_position_controller_node.h文件 并声明类

class PidPositionControllerNode{

 public:
    PidPositionControllerNode();
    ~PidPositionControllerNode();

 private:
    // 无人机控制用的里程计
    EigenOdometry odometry_ ;

    // 订阅里程计
    ros::Subscriber odometry_sub_;
    
    // 发布控制指令
    ros::Publisher Control_RollPitchYawrateThrust_pub_;

    // 里程计回调函数
    void OdometryCallback(const nav_msgs::OdometryConstPtr& odometry_msg);

};

先完成一些 必要的变量和函数 定义 ,后续需要的内容再向里添加。

之后便可以做功能的设计开发了

订阅无人机里程计信息

       // 订阅里程计 信息
        odometry_sub_ = nh.subscribe("firefly/odometry_sensor1/odometry", 1,
                               &PidPositionControllerNode::OdometryCallback, this);
    // 里程计信息 回调函数
    void PidPositionControllerNode::OdometryCallback(const nav_msgs::OdometryConstPtr& odometry_msg) {

        // 转成eigen 的里程计信息格式
        EigenOdometry odometry;
        eigenOdometryFromMsg(odometry_msg, &odometry);

        double pos_x =  odometry.position.x();
        double pos_y =  odometry.position.y();
        double pos_z =  odometry.position.z();

        std::cout<< "pos x : "<<pos_x <<std::endl;
        std::cout<< "pos y : "<<pos_y <<std::endl;
        std::cout<< "pos z : "<<pos_z <<std::endl;

    }

无人机位置如下:
在这里插入图片描述
大约在 gazebo 坐标系下 (0,0,1)位置

终端打印信息:
在这里插入图片描述

其中 EigenOdometry 里程计信息包括:

struct EigenOdometry {
  EigenOdometry()
      : position(0.0, 0.0, 0.0),
        orientation(Eigen::Quaterniond::Identity()),
        velocity(0.0, 0.0, 0.0),
        angular_velocity(0.0, 0.0, 0.0) {};

  EigenOdometry(const Eigen::Vector3d& _position,
                const Eigen::Quaterniond& _orientation,
                const Eigen::Vector3d& _velocity,
                const Eigen::Vector3d& _angular_velocity) {
    position = _position;
    orientation = _orientation;
    velocity = _velocity;
    angular_velocity = _angular_velocity;
  };

  Eigen::Vector3d position;
  Eigen::Quaterniond orientation;
  Eigen::Vector3d velocity; // Velocity is expressed in the Body frame!
  Eigen::Vector3d angular_velocity;
};
  • 无人机位置 —gazebo 坐标系
  • 无人机姿态四元数— 机体坐标系
  • 无人机速度— 机体坐标系
  • 无人机角速度— 机体坐标系

这部分相当于控制框图中的航姿参考系统,为控制器,提供无人机的实际位姿及各种信息。
在这里插入图片描述

垂直位置控制

无人机的垂直位置控制的控制框图如下:
在这里插入图片描述
其框图的逻辑和原因,以在前文描述,这里不再赘述。

在框图中的遥控器输入期望速度,这可以放到后面再做,首先实现整体的控制回环。

串级P控制

首先实现一个简单的串级P控制
代码如下:

   // 垂直方向位置控制
    void PidPositionControllerNode::PosZControl(){

        // 无人机期望 高度 先固定为1m
        double pos_z_des = 1;

        // 无人机当前高度
        double pos_z_cur = odometry_.position.z();

        // 高度差 期望减当前值
        double pos_z_err = pos_z_des - pos_z_cur;

        // 转为期望速度
        // 垂直位置增益
        float PID_POS_Z_GAIN = 1;

        // 无人机期望速度
        double vel_z_des = pos_z_err*PID_POS_Z_GAIN;

        double vel_z_cur = odometry_.velocity.z();

        // 速度偏差
        double vel_z_err = vel_z_des - vel_z_cur;

        // 悬停时增益
        double loiter_thrust = 1.56779*9.81;

        // 转为电机油门
        // 垂直速度增益
        float PID_VEL_Z_GAIN = 1;
        double thrust_z = vel_z_err*PID_VEL_Z_GAIN+loiter_thrust;

        std::cout<< "thrust_z : "<<thrust_z <<std::endl;
        // 控制量
        mav_msgs::RollPitchYawrateThrust roll_pitch_yawrate_thrust;
        roll_pitch_yawrate_thrust.thrust.z= thrust_z;

        Control_RollPitchYawrateThrust_pub_.publish(roll_pitch_yawrate_thrust);
    }

期望位置固定为1,外环和内环的控制均为比例作用,先打通控制回环。

然后编译看下控制效果.

控制效果如下:
z轴 震荡 几次后 , 最终收敛

收敛结果

在这里插入图片描述
在这里插入图片描述

收敛过程

在这里插入图片描述
震荡约4次,存在一定稳态误差
在这里插入图片描述
最大超调量约为0.2m
到达稳态时间约30s
稳态误差0.002m

串级PID控制

通过对上面收敛过程的分析,超调量比较大,收敛时间长,改善控制效果,适宜加入积分、微分环节。

向其中加入速度环加入pid控制器

详情参考古月居

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Oracle中分割字符串的方法

Oracle中分割字符串的方法1. 使用 regexp_substr() 函数1.1 方式11.2 方式22. 自定义函数2.1 自定义类型 table2.2 自定义函数2.2.1 自定义函数2.2.2 效果如下&#xff1a;2.3 Oracle查看&#xff1c;Collection&#xff1e; 类型数据3.1. 使用 regexp_substr() 函数 1.1 方式…

日志三个时间,动静态库的建立与使用

文章目录日志时间ModifyChangeAccessmake与g库lddfile静态库动态库静态库静态的制作静态库的使用动态库动态库的制作动态库的使用日志时间 Modify 最近修改文件内容的时间在一定条件下&#xff0c;修改文件内容时&#xff0c;可能修改文件属性&#xff1a;文件大小属性改变了 …

实验2:Numpy手写多层神经网络

引言 这个作业的目的是给你们介绍建立&#xff0c;训练和测试神经系统网络模型。您不仅将接触到使用Python包构建神经系统网络从无到有&#xff0c;还有数学方面的反向传播和梯度下降。但在实际情况下&#xff0c;你不一定要实现神经网络从零开始(你们将在以后的实验和作…

【数据结构与算法】详解快排

目录一、快排的定义及思路二、快排的代码实现一、快排的定义及思路 快排就是快速排序&#xff0c;是通过不断比较和移动交换来进行排序&#xff0c;相当于冒泡排序的一种升级。 其基本思想是&#xff1a; 分而治之&#xff0c;也就是把一组数组分成两个独立数组&#xff0c;再对…

【初学者入门C语言】之结构体(十一)

个人主页&#xff1a;天寒雨落的博客_CSDN博客-C,CSDN竞赛,python领域博主 &#x1f4ac; 刷题网站&#xff1a;一款立志于C语言的题库网站蓝桥杯ACM训练系统 - C语言网 (dotcpp.com) 特别标注&#xff1a;该博主将长期更新c语言内容&#xff0c;初学c语言的友友们&#xff0c…

【树莓派不吃灰】使用中经常看到的安装命令 wget、rpm、yum、dpkg、apt-get

目录1. 前言2. Linux系统两种主流软件包2.1 rpm包2.2 deb包3. 解决软件依赖问题 —— yum、apt3.1 yum3.2 apt 和 apt-get4. wget 网络文件下载工具5. 总结❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2022-10-28 ❤️❤️ 本篇…

设计模式之备忘录模式 - 简书

备忘录模式是一种行为设计模式&#xff0c; 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。 解决方案 我们刚才遇到的所有问题都是封装 “破损” 造成的。 一些对象试图超出其职责范围的工作。 由于在执行某些行为时需要获取数据&#xff0c; 所以它们侵入了其…

ipv6学习笔记221029

IPv6是英文“Internet Protocol Version 6”&#xff08;互联网协议第6版&#xff09;的缩写 ipv6的长度有128位, ipv4的长度是32位 ipv6以冒号:分隔 , ipv4以点.分隔 8个16位等于128位 , 4个十六进制表示16位(一个16进制表示4位) ipv6的128位 由 8 个 16位 16bit 组成 每…

【LeetCode】【两个数组的交集】

力扣 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例 2&#xff1a; 输入&#xff1a;num…

基于MATLAB的指纹识别算法仿真实现

目录 一、理论基础 二、核心程序 三、测试结果 一、理论基础 在指纹图像预处理部分&#xff0c;论文对预处理的各个步骤包括规格化、图像分割、中值滤波、二值化、细化等以及各个步骤的方法进行了深入的分析和研究&#xff0c;选择了一种图像预处理方案。在指纹特征提取部分…

基于javaweb的医疗挂号管理系统(java+springboot+freemarker+layui+mysql)

基于javaweb的医疗挂号管理系统(javaspringbootfreemarkerlayuimysql) 运行环境 Java≥8、MySQL≥5.7 开发工具 eclipse/idea/myeclipse/sts等均可配置运行 适用 课程设计&#xff0c;大作业&#xff0c;毕业设计&#xff0c;项目练习&#xff0c;学习演示等 功能说明 基…

幼儿园小程序实战开发教程(终篇)

我们已经写了四篇教程&#xff0c;涵盖了需求分析及各个页面&#xff0c;本篇是我们的最终篇。 咨询信息 我们小程序需要收集家长和孩子的信息&#xff0c;为此我们也规划了数据源。如果按照传统开发思路&#xff0c;那我们是要依次实现信息采集的每个字段&#xff0c;然后再…

<Linux系统复习>文件描述符

一、本章重点 1、进程和打开文件的关系 2、简单复习c语言文件操作 3、介绍系统调用&#xff1a;open、clos、write、read 4、理解文件描述符 5、文件描述符分配规则 6、理解stdin、stdout、stderr与fd的关系 7、理解linux下一切皆文件 8、理解重定向的本质 9、理解stdin和stdou…

《吉师作业》(1)之我是web手为啥让我学C

前言 &#x1f340;作者简介&#xff1a;吉师散养学生&#xff0c;为挣钱努力拼搏的一名小学生。 &#x1f341;个人主页&#xff1a;吉师职业混子的博客_CSDN博客-python学习,HTML学习,清览题库--C语言程序设计第五版编程题解析领域博主 &#x1fad2;文章目的&#xff1a;我不…

freeRTOS学习(二)

堆内存管理 先决条件 FreeRTOS是作为一组C源文件提供的&#xff0c;因此成为一个合格的C程序员是使用FreeRTOS的先决条件。 动态内存分配及其与FreeRTOS的相关性 内核对象&#xff1a;如任务、队列、信号量和事件组。为了使FreeRTOS尽可能易于使用&#xff0c;这些内核对象不…

科普一下MTU是什么,如何设置MTU

欢迎来到东用知识小课堂&#xff0c;下面我们就来科普一下一下MTU是什么&#xff0c;如何设置MTUMTU是最大传输单元的意思&#xff0c;代指一类通讯协议某一层上所能通过的最大数据包大小(以byte为单位)。最大传输单元这一主要参数一般与串行通讯接口相关(网络接口卡、串口等)。…

【Vue实用功能】彻底搞懂Vue中的Mixin混入

前言 有些小伙伴接手别人的Vue项目时&#xff0c;看到里面有个Mixin文件夹&#xff0c;可能会云里雾里的状态&#xff0c;今天我们来好好聊聊Mixin&#xff0c;争取以后不再云里雾里。 一、什么是Mixins&#xff1f; Mixins(混入)&#xff1a;当我们存在多个组件中的逻辑或者…

MySQL总结

文章目录一.SQL语句简介1.什么是SQL&#xff1f;2.SQL分类二.MySql常用数据类型三.数据库操作1.创建数据库2.查询和删除数据库3.备份/恢复数据库四.表操作1.创建表2.修改/查看表五.CRUD语句1.Insert语句2.Delete语句3.Update语句4.Select语句五.函数1.统计函数count2.字符串相关…

for in和for of

文章目录二者在什么情况下可以使用for ... in什么是可枚举的属性&#xff1f;for...of什么是可迭代的数据&#xff1f;总结二者在什么情况下可以使用 for … in 可以用在可枚举的数据&#xff0c;如&#xff1a; 对象数组&#xff08;循环的是索引&#xff09;字符串 什么是…

ESP8266-Arduino网络编程实例-发送邮件(基于SMTP)

发送邮件(基于SMTP) 本文将演示如何使用ESP8266发送邮件。实例中将使用SMTP(Simple Mail Transfer Protocol)协议通QQ邮箱向指定邮箱发送邮件。 1、设置QQ邮箱第三方服务 1)第一步:注册一个QQ邮箱 2)第二步:开启QQ邮箱的第三方服务 1、硬件准备 ESP8266 NodeMCU开发…