ROS基础内容(AI优化版)
本文最后更新于44 天前,其中的信息可能已经过时,如有错误请发送邮件到suzhech@gmail.com

ROS 学习指南:从 Ubuntu 基础到机器人控制

Ubuntu 系统基础

要想学习 ROS,需要先安装 Ubuntu 系统。下面是 Ubuntu 系统(Linux 系统)的一些基本命令。

Linux 基础命令参考手册

1. 目录操作命令

# pwd = Print Work Directory (显示当前工作目录)
pwd

# cd = Change Directory (切换目录)
cd /path/to/directory    # 切换到指定目录
cd ..                    # 返回上一级目录
cd ~                     # 返回 home 目录
cd -                     # 返回上一次访问的目录

# ls = list (列出目录内容)
ls          # 列出当前目录内容
ls -a       # 显示所有文件(包括隐藏文件)
ls -l       # 详细列表显示(权限、大小、时间)
ls -la      # 显示所有文件的详细信息

# mkdir = make directory (创建目录)
mkdir dirname            # 创建目录
mkdir -p parent/child    # 创建多级目录

2. 文件操作命令

# rm = remove (删除文件或目录)
rm filename              # 删除文件
rm -r dirname            # 删除文件夹(递归删除)
rm -rf dirname           # 强制删除(不询问)

# mv = move (移动或重命名文件)
mv filename folder/filename    # 移动文件
mv oldname newname             # 重命名文件

# cp = copy (复制文件或目录)
cp file1 file2           # 复制文件
cp -r dir1 dir2          # 复制目录

3. 文件查看命令

# cat = catenate (连续输出文件内容)
cat filename             # 显示整个文件内容

# less = "比 more 更强" (分页查看文件)
less filename            # 分页查看文件内容

# tail = 取文件"尾巴" (查看文件末尾内容)
tail filename            # 查看文件末尾10行
tail -f filename         # 实时跟踪文件变化
tail -n 20 filename      # 查看文件末尾20行

4. 文本编辑器

# vi = visual interface (命令行文本编辑器)
# vim = vi improved (改进版 vi)
# gedit = GNOME 的图形化文本编辑器

# 编辑器使用示例:
gedit hello.cpp          # 打开图形化编辑器(推荐新手用)
vim hello.cpp            # 打开命令行编辑器
vi hello.cpp             # 打开 vi 编辑器

使用说明:

  1. 在终端中直接输入命令即可执行
  2. 注意命令和参数之间的空格
  3. 谨慎使用 rm -rf 命令

ROS 基础概念

ROS 重要概念介绍

ROS 基础工作空间(Workspace):存放工程开发相关文件的文件夹。类似一个 IDE(例如 Pycharm)新建一个工程,就是一个工作空间。包含 4 个文件夹:

空间名称英文名称主要用途与说明
srcSource Space放置功能包代码
buildBuild Space编译过程中产生的中间文件,不用过多关注
develDevelopment Space放置编译生成的可执行文件、库、脚本
installInstall Space存放可执行文件,与上面 devel 有一定重复

工作流程

  1. 先创建一个工作空间
  2. 再创建一个功能包:catkin_create_pkg 包名 依赖包
  3. 编辑源文件
  4. 编辑配置文件
  5. 编译并执行
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws
catkin_make
source devel/setup.bash
cd src
catkin_create_pkg robot_control roscpp std_msgs geometry_msgs

ROS 代码编写

基础代码结构

#include "ros/ros.h"   // 写入ROS头文件
#include "geometry_msgs/Twist.h"  // 写入速度消息处理头文件

// linear.x / linear.y / linear.z(线速度)
// angular.x / angular.y / angular.z(角速度)

// arguement count/arguement vector 用于传参
int main(int argc, char** argv){
    ros::init(argc, argv, "move_robot_node");  // 通过初始化一个节点,相当于在ROS Master系统中注册了一个节点用于通信和管理进程
    ros::NodeHandle nh; // 定义一个节点句柄用于创建发布者和订阅者
    ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("cmd_vel", 10); // 用Publisher创建了一个叫pub的发布者,发布的消息类型为Twist,发布到的话题名称为cmd_vel,队列长度为10
}

Rate 函数和 Sleep 函数

ros::Rate define_rate_name(20); // 会定义一个"节拍器", 以一秒二十次的频率工作

为了保证系统在运行过程中的稳定性,通常会使用 sleep 函数,这个函数是为了保证 ROS 系统按照某一特定频率运行。

特殊地,对于一个循环而言,例如:

for(int i = 0; i < 30; ++i){
    some command;
    rate.sleep();
}

由于循环执行了三十次,我们又知道”节拍器”一秒钟运行三十次,也就相当于在这里我们执行了三秒,通过”节拍器”这一”睡眠特性”我们能够让整个 ROS 中所出现的代码以我们预想的秒数执行,达到稳定的状态。

运动控制函数

根据 sleep 的这一特性,结合最终考核任务让小车前进一段距离后逆时针旋转 60° 后做矩形运动,我们可以编写前进函数和旋转函数:

void move_forward(ros::Publisher pub, double second){
    geometry_msgs::Twist t1;
    ros::Rate rate(10); // 一秒十次,相当于0.1秒每次
    int n = second / 0.1;
    t1.linear.x = 1.0;
    for(int i = 0; i < n; i++){
        pub.publish(t1);
        rate.sleep();
    }
    ROS_INFO("前进中");
}

void turn_function(ros::Publisher pub_name, double angle){
    geometry_msgs::Twist t1;
    ros::Rate rate(10);
    t1.angular.z = 0.1; // 弧度制即0.1rad/s
    double angle_rad = angle * M_PI / 180.0; // M_PI=3.1415926.... 这一步目的是将角度转化为弧度
    int n = angle_rad / 0.1;
    for(int i = 0; i < n; i++){
        pub_name.publish(t1);
        rate.sleep();
        ROS_INFO("旋转中");
    }
    t1.angular.z = 0;
    pub_name.publish(t1);
    ROS_INFO("旋转完成");
}

改进的运动控制(带停止指令)

void move_forward(ros::Publisher pub_name, double second){
    geometry_msgs::Twist t1;
    ros::Rate rate(10); // 一秒十次,相当于0.1秒每次
    int n = second / 0.1;
    t1.linear.x = 0.1;
    for(int i = 0; i < n; i++){
        pub_name.publish(t1);
        rate.sleep();
        ROS_INFO("前进中");
    }

    // 用pub_name作参数名的原因是和pub区分,实际查阅过程中发现可以用指针来代替,避免直接传参。
    for(int i = 0; i < 3; i++){
        t1.linear.x = 0.0;
        pub_name.publish(t1);
        ROS_INFO("前进完成");
    }
}

基于偏转角的精确控制

#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
#include "tf/tf.h"
#include "nav_msgs/Odometry.h"
#include <cmath>

double yaw = 0;

void callback(const nav_msgs::Odometry::ConstPtr& msg){
    tf::Quaternion test(
        msg->pose.pose.orientation.x,
        msg->pose.pose.orientation.y,
        msg->pose.pose.orientation.z,
        msg->pose.pose.orientation.w
    );

    tf::Matrix3x3 m(test);
    double roll, pitch;
    m.getRPY(roll, pitch, yaw);
}

void turn_function(ros::Publisher pub_name, double target_angle){
    geometry_msgs::Twist t1;
    ros::Rate rate(10);  // 依然0.1秒每次
    t1.angular.z = 0.3; // 弧度制即0.3rad/s
    ros::spinOnce();
    ros::Duration(0.1).sleep();
    double start_rad = yaw; // 只会赋值一次
    double target_rad = target_angle * M_PI / 180.0;

    while(ros::ok()){
        double delta = yaw - start_rad;
        if (delta > M_PI) delta -= 2 * M_PI;
        if (delta < -M_PI) delta += 2 * M_PI;
        if(fabs(delta) >= target_rad){
            break;
        }
        else {
            pub_name.publish(t1);
            ros::spinOnce();
            rate.sleep();
        }
    }

    t1.angular.z = 0;
    pub_name.publish(t1);
    ros::Duration(0.2).sleep();
    ROS_INFO("旋转完成");
}

完整的主程序

int main(int argc, char** argv){
    setlocale(LC_ALL, "");
    ros::init(argc, argv, "Robot_Control");
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("/cmd_vel", 10);
    ros::Subscriber sub = nh.subscribe("/odom", 10, callback);

    move_forward(pub, 10);
    turn_function(pub, 60);
    move_forward(pub, 10);
    turn_function(pub, 90);
    move_forward(pub, 6);
    turn_function(pub, 90);
    move_forward(pub, 10);
    turn_function(pub, 90);
    move_forward(pub, 6);
    return 0;
}

环境配置

# 启动 Gazebo 仿真环境
roslaunch turtlebot3_gazebo turtlebot3_world.launch

# 设置机器人模型
echo "export TURTLEBOT3_MODEL=burger" >> ~/.bashrc
source ~/.bashrc

# 机器人型号说明:
# burger(最小型)
# waffle(带摄像头、激光雷达)
# waffle_pi(带树莓派摄像头)

# 启动 Gazebo 和 Rviz
roslaunch turtlebot3_gazebo turtlebot3_gazebo_rviz.launch

进阶任务:导航目标点

单点导航

#include <ros/ros.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <actionlib/client/simple_action_client.h>
#include <tf/tf.h>
#include <cmath>

int main(int argc, char** argv){
    ros::init(argc, argv, "nav_goal");
    actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;

    MoveBaseClient client("move_base", true);
    ROS_INFO("等待启动成功");
    client.waitForServer(ros::Duration(5.0));
    ROS_INFO("连接成功!");

    move_base_msgs::MoveBaseGoal goal;

    goal.target_pose.header.frame_id = "map";
    goal.target_pose.header.stamp = ros::Time::now();

    goal.target_pose.pose.position.x = 3.0;
    goal.target_pose.pose.position.y = 2.0;

    double yaw = M_PI;
    tf::Quaternion q = tf::createQuaternionFromYaw(yaw);
    goal.target_pose.pose.orientation.x = q.x();
    goal.target_pose.pose.orientation.y = q.y();
    goal.target_pose.pose.orientation.z = q.z();
    goal.target_pose.pose.orientation.w = q.w();

    ROS_INFO("发送导航目标...");
    client.sendGoal(goal);
    client.waitForResult();

    if(client.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
        ROS_INFO("到达目标点!");
    else
        ROS_WARN("未能到达目标点!");

    return 0;
}

多点导航

#include <ros/ros.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <actionlib/client/simple_action_client.h>
#include <tf/tf.h>
#include <cmath>

int main(int argc, char** argv){
    setlocale(LC_ALL, "");
    ros::init(argc, argv, "nav_goal");
    typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;

    MoveBaseClient client("move_base", true);
    ROS_INFO("等待启动成功");
    client.waitForServer(ros::Duration(5.0));
    ROS_INFO("连接成功!");

    double goals[][3] = {
        {-1.5, 0.5, 0},
        {2.05, 0.3, 0},
        {3, 2, M_PI},
        {1.06, 2.48, 0},
        {-6.04, 5.04, 0},
        {-6.5, -3.42, 0},
    };

    for(int i = 0; i < 6; ++i){
        move_base_msgs::MoveBaseGoal goal;
        goal.target_pose.header.frame_id = "map";
        goal.target_pose.header.stamp = ros::Time::now();

        goal.target_pose.pose.position.x = goals[i][0];
        goal.target_pose.pose.position.y = goals[i][1];

        double yaw = goals[i][2];
        tf::Quaternion q = tf::createQuaternionFromYaw(yaw);
        goal.target_pose.pose.orientation.x = q.x();
        goal.target_pose.pose.orientation.y = q.y();
        goal.target_pose.pose.orientation.z = q.z();
        goal.target_pose.pose.orientation.w = q.w();

        ROS_INFO("发送导航目标...");
        client.sendGoal(goal);
        client.waitForResult();

        if(client.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
            ROS_INFO("到达目标点!");
        else
            ROS_WARN("未能到达目标点!");

        ros::Duration(1.0).sleep();
    }

    ROS_INFO("至此,终于完成了所有考核任务");
    return 0;
}

这份指南涵盖了从 Ubuntu 基础命令到 ROS 机器人控制的完整流程,包括基础运动控制和高级导航功能。通过逐步学习和实践这些内容,您将能够掌握 ROS 机器人编程的核心概念和技能。

ROS基础内容(AI优化版) by Suzhech
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇