• ROS学习ROS基础


    ROS学习(一)

    ROS基础

    一、工作空间基本操作

    创建工作空间

    mkdir -p ~/yyj_ws/src
    //到src下
    cd yyj_ws/src
    
    • 1
    • 2
    • 3

    在src文件夹下初始化工作空间,将其变成ROS工作空间的属性

    catkin_init_workspace
    
    • 1

    在src中创建功能包指令

    catkin_create_pkg[depend1][depend2][depend3][...]
    
    • 1

    例如:

    catkin_create_pkg learning_communication std_msgs rospy roscpp
    
    • 1

    此时功能包中src放的是核心代码,include放的是头文件,CMakelists.txt和package.xml是所有功能包都必须具备的文件。前者是放置编译功能包的编译选项和规则,使用cmake接口;后者是描述功能包的具体信息,比如名字、版本号、维护者、声明的依赖等后期加依赖需在此文件修改。
    接着在工作空间层级编译,再设置环境变量。

    cd ..
    catkin_make
    source ~/yyj_ws/devel/setup.bash
    
    • 1
    • 2
    • 3

    (同一个工作空间下,不允许存在同名功能包。不同工作空间下,允许存在同名功能包)
    查看ros的环境变量,关注ROS_PACKAGE_PATH即ros编译运行的查找功能包和节点的顺序

    env | grep ros
    //或者
    echo $ROS_PACKAGE_PATH
    
    • 1
    • 2
    • 3

    当不同工作空间下,存在同名功能包会先查找后生成的路径
    例:(实验完记得删除这个包)

    //安装ros功能包例程
    sudo apt-get install ros-kinetic-roscpp-tutorials
    //查找功能包会在opt/ros/kinetic/share/roscpp_tutotials
    rospack find roscpp_tutorials
    //复制功能包到工作空间src下
    //再次设置环境变量
    source ~/yyj_ws/devel/setup.bash
    //再次查找即发现查找路径指向工作空间里的功能包了
    rospack find roscpp_tutorials
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    二、ROS通信编程——话题编程

    "hello world " 例程

    1、创建发布者(talker)

    a、进入/home/frany/yyj_ws/src/learning_communication/src创建talker.cpp
    b、编写talker.cpp
    编程逻辑:
    (1)初始化ROS节点
    (2)向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型;
    (3)按照一定频率循环发布消息;

    /*
    该例程将发布chatter话题,消息类型String
    */
    
    #include 
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    
    int main(int argc,char **argv)
    {
      //ROS节点初始化,“talker“为节点名称,后期可更改
      ros::init(argc,argv,"talker");
      
      //创建节点句柄
      ros::NodeHandle n;
      //创建一个Publisher,发布名为chatter的topic,消息类型为std::msgs::String,1000是发布队列的长度,它的作用是缓冲数据,当队列满了会删除时间戳最早的数据,如发布消息过快可能会导致断帧
      ros::Publisher chatter_pub = n.advertise("chatter", 1000);
    
      //设置循环的频率
      ros::Rate loop_rate(10); 
    
      int count = 0;
      while (ros::ok())
      {
        //初始化std::msgs::String类型的消息
        std_msgs::String msg;
        std::stringstream ss;
        ss << "hello world " << count;
        msg.data = ss.str();
    
        //发布消息
        ROS_INFO("%s", msg.data.c_str()); 
        chatter_pub.publish(msg);
        
        //循环等待回调函数
        ros::spinOnce();
    
        //按照循环频率延时按循环频率(10hz)休眠即100ms,避免cpu占用过高
        loop_rate.sleep();
        ++count;
      }
    
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    2、创建订阅者(listener)

    a、进入/home/frany/yyj_ws/src/learning_communication/src创建listener.cpp
    b、编写listener.cpp
    编程逻辑:
    (1)初始化ROS节点;
    (2)订阅需要的话题;
    (3)循环等待话题消息,接收到消息后进入回调函数;
    (4)在回调函数中完成消息处理;

    /*
    该例程将订阅chatter话题,消息类型String
    */
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    
    //接收到订阅的消息后,会进入消息回调函数
    void chatterCallback(const std_msgs::String::ConstPtr& msg)
    {
      //将接收到的消息打印出来
      ROS_INFO("I heard: [%s]", msg->data.c_str());
    }
    
    int main(int argc, char **argv)
    {
      //初始化ROS节点
      ros::init(argc, argv, "listener");
    
      //创建节点句柄
      ros::NodeHandle n;
    
      //创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
      ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
    
      //循环等待回调函数
      ros::spin(); 
    
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    3、添加编译选项

    c++需要编译,python不需要,因为其本身就是一种可执行文件。
    在 CMakeLists.txt 文件中进行编译代码:
    a、流程:
    (1)设置需要编译的代码和生成的可执行文件
    (2)设置链接库
    (3)设置依赖
    add_executable生成可执行文件,依赖于talker.cpp生成talker,可以有多个源码文件依次加在后面;
    target_link_libraries为链接到第三方库,此处只链接了默认库。

    add_executable(talker src/talker.cpp) 
    target_link_libraries(talker ${catkin_LIBRARIES})
    
    add_executable(listener src/listener.cpp)
    target_link_libraries(listener ${catkin_LIBRARIES})
    
    • 1
    • 2
    • 3
    • 4
    • 5

    b、编译:
    在yyj_ws 工作空间层级下生成可执行文件:

    catkin_make
    
    • 1
    4、运行可执行文件

    a、启动ROS Master
    终端1:

    roscore
    
    • 1

    b、启动talker
    终端2:

    rosrun learning_communication talker
    
    • 1

    c、启动listener
    终端3:

    rosrun learning_communication listener
    
    • 1

    如没把环境变量直接写进.bashrc,则每次打开新终端都需添加环境变量

    source ~/yyj_ws/devel/setup.bash
    
    • 1

    自定义话题消息

    1、定义msg文件

    在learning_communication下创建msg目录,在msg目录下创建Person.msg文件

    string name
    uint8 sex
    uint8 age
    
    uint8 unknown = 0
    uint8 male    = 1
    uint8 female  = 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2、在package.xml中添加功能包依赖
      message_generation
      message_runtime
    
    • 1
    • 2
    3、在CMakeLists.txt中添加编译选项
    find_package(catkin REQUIRED COMPONENTS
      roscpp
      rospy
      std_msgs
      message_generation
      )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    catkin_package(
    #  INCLUDE_DIRS include
    #  LIBRARIES learning_communication
      CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
    #  DEPENDS system_lib
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    add_message_files(FILES Person.msg)
    generate_messages(DEPENDENCIES std_msgs)
    
    • 1
    • 2

    最后编译

    catkin_make
    
    • 1
    4、查看自定义的消息

    如没把环境变量直接写进.bashrc,则需添加环境变量

    source ~/yyj_ws/devel/setup.bash
    
    • 1
    rosmsg show Person
    
    • 1

    ROS学习(二)

    ROS基础

    三、ROS通信编程——服务编程

    例:实现加法listener发布两个数给talker,talker相加后给listener

    1、自定义服务文件srv

    a、在learning_communication下创建srv目录,在srv目录下创建AddTwoInts.srv文件

    int64 a
    int64 b
    ---
    int64 sum
    
    • 1
    • 2
    • 3
    • 4

    b、在package.xml中添加功能包依赖

      message_generation
      message_runtime
    
    • 1
    • 2

    c、在CMakeLists.txt中添加编译选项

    find_package(catkin REQUIRED COMPONENTS
      roscpp
      rospy
      std_msgs
      message_generation
      )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    catkin_package(
    #  INCLUDE_DIRS include
    #  LIBRARIES learning_communication
      CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
    #  DEPENDS system_lib
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    add_service_files(FILES AddTwoInts.srv)
    generate_messages(DEPENDENCIES std_msgs)
    
    • 1
    • 2

    d、编译
    在yyj_ws 工作空间层级下生成可执行文件:

    catkin_make
    
    • 1

    2、创建服务器

    在learning_communicatio的src下创建server.cpp文件
    编程逻辑:
    (1)初始化ROS节点
    (2)创建Server实例
    (3)循环等待服务请求,进入回调函数
    (4)在回调函数中完成服务功能的处理,并反馈应答数据

    /*
    AddTwoInts Server
    */
    
    #include "ros/ros.h"
    #include "learning_communication/AddTwoInts.h"
    
    //service回调函数,输入参数req,输出参数res
    bool add(learning_communication::AddTwoInts::Request  &req,
             learning_communication::AddTwoInts::Response &res)
    {
      //将输入参数中的请求数据相加,结果放到应答变量中
      res.sum = req.a + req.b;
      ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
      ROS_INFO("sending back response: [%ld]", (long int)res.sum);
    
      return true;
    }
    
    int main(int argc, char **argv)
    {
      //ROS节点初始化
      ros::init(argc, argv, "add_two_ints_server");
      
      //创建节点句柄
      ros::NodeHandle n;
    
      //创建一个名为add_two_ints的server,注册回调函数add()
      ros::ServiceServer service = n.advertiseService("add_two_ints", add);
    
      //循环等待回调函数
      ROS_INFO("Ready to add two ints.");
      ros::spin();
    
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    3、创建客户端

    在learning_communicatio的src下创建client.cpp文件
    编程逻辑:
    (1)初始化ROS节点
    (2)创建Client实例
    (3)发布服务请求数据
    (4)等待Server处理后的应答结果

    /*
    AddTwoInts Client
    */
    
    #include 
    #include "ros/ros.h"
    #include "learning_communication/AddTwoInts.h"
    
    
    int main(int argc, char **argv)
    {
      //Ros节点初始化
      ros::init(argc, argv, "add_two_ints_client");
      
      //从终端命令行获取两个加数
      if (argc != 3)
      {
        ROS_INFO("usage: add_two_ints_client X Y");
        return 1;
      }
    
      //创建节点句柄
      ros::NodeHandle n;
    
      //创建一个client,请求add_two_int service,service消息类型是learning_communication::AddTwoInts
      ros::ServiceClient client = n.serviceClient("add_two_ints");
    
      //创建learning_communication::AddTwoInts类型的service消息
      learning_communication::AddTwoInts srv;
      srv.request.a = atoll(argv[1]);
      srv.request.b = atoll(argv[2]);
    
      //发布service请求,等待加法运算的应答结果
      if (client.call(srv))
      {
        ROS_INFO("Sum: %ld", (long int)srv.response.sum);
      }
      else
      {
        ROS_ERROR("Failed to call service add_two_ints");
        return 1;
      }
    
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    4、添加编译选项

    在 CMakeLists.txt 文件中设置编译代码
    a、流程:
    (1)设置需要编译的代码和生成的可执行文件
    (2)设置链接库
    (3)设置依赖
    打开learning_communication功能包中的 CMakeLists.txt 文件,添加如下代码:

    add_executable(server src/server.cpp)
    target_link_libraries(server ${catkin_LIBRARIES})
    add_dependencies(server ${PROJRCT_NAME}_gencpp)
    
    add_executable(client src/client.cpp)
    target_link_libraries(client ${catkin_LIBRARIES})
    add_dependencies(client ${PROJRCT_NAME}_gencpp)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    b、编译:
    在yyj_ws 工作空间层级下生成可执行文件:

    catkin_make
    
    • 1

    5、运行可执行文件

    a、启动ROS Master
    终端1:

    roscore
    
    • 1

    b、启动server
    终端2:

    rosrun learning_communication server
    
    • 1

    c、启动client
    终端3:

    rosrun learning_communication client 80 99
    
    • 1

    如没把环境变量直接写进.bashrc,则每次打开新终端都需添加环境变量

    source ~/yyj_ws/devel/setup.bash
    
    • 1

    ROS学习(三)

    ROS基础

    四、ROS通信编程——动作编程

    例:实现机器人洗盘子的动作,并实时反馈洗盘子的动作,盘子洗完后回复給客户端成功的命令。

    1、自定义动作消息action文件

    a、在learning_communication下创建action目录,在action目录下创建DoDishes.action文件

    #定义目标信息
    uint32 dishwasher_id #Specify which dishwasher we want to use
    ---
    #定义结果信息
    uint32 total_dishes_cleaned
    ---
    #定义周期反馈的消息  洗盘子进度
    float32 percent_complete
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    b、在package.xml中添加功能包依赖

      actionlib
      actionlib_msgs
      actionlib
      actionlib_msgs
    
    • 1
    • 2
    • 3
    • 4

    c、在CMakeLists.txt中添加编译选项

    find_package(catkin REQUIRED COMPONENTS
    ...
      actionlib_msgs
      actionlib
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    add_action_files(DIRECTORY action FILES DoDishes.action)
    
    • 1
    generate_messages(DEPENDENCIES std_msgs actionlib_msgs)
    
    • 1

    d、编译
    在yyj_ws 工作空间层级下生成可执行文件:

    catkin_make
    
    • 1

    2、创建动作服务器

    在learning_communicatio的src下创建DoDishes_server.cpp文件
    编程逻辑:
    (1)初始化ROS节点
    (2)创建动作服务器实例
    (3)启动服务器,等待动作请求
    (4)在回调函数中完成动作服务功能的处理,并反馈进度信息
    (5)动作完成,发送结束信息

    #include 
    #include 
    #include "learning_communication/DoDishesAction.h"
    
    typedef actionlib::SimpleActionServer Server;
    
    // 收到action的goal后调用该回调函数
    void execute(const learning_communication::DoDishesGoalConstPtr& goal, Server* as)
    {
       ros::Rate r(1);
       learning_communication::DoDishesFeedback feedback;
    
       ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id);
    
       // 假设洗盘子的进度,并且按照1hz的频率发布进度feedback
       for(int i=1; i<=10; i++)
       {
           feedback.percent_complete = i * 10;
           as->publishFeedback(feedback);
           r.sleep();
       }
    
       // 当action完成后,向客户端返回结果
       ROS_INFO("Dishwasher %d finish working.", goal->dishwasher_id);
       as->setSucceeded();
    }
    
    int main(int argc, char** argv)
    {
       ros::init(argc, argv, "do_dishes_server");
       ros::NodeHandle n;
    
       // 定义一个服务器
       Server server(n, "do_dishes", boost::bind(&execute, _1, &server), false);
       
       // 服务器开始运行
       server.start();
    
       ros::spin();
    
       return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    3、创建动作客户端

    在learning_communicatio的src下创建DoDishes_client.cpp文件
    编程逻辑:
    (1)初始化ROS节点
    (2)创建动作客户端实例
    (3)连接动作服务器
    (4)发送动作目标
    (5)根据不同类型的服务端反馈处理回调函数

    #include 
    #include "learning_communication/DoDishesAction.h"
    
    typedef actionlib::SimpleActionClient Client;
    
    // 当action完成后会调用该回调函数一次
    void doneCb(const actionlib::SimpleClientGoalState& state,
           const learning_communication::DoDishesResultConstPtr& result)
    {
       ROS_INFO("Yay! The dishes are now clean");
       ros::shutdown();
    }
    
    // 当action激活后会调用该回调函数一次
    void activeCb()
    {
       ROS_INFO("Goal just went active");
    }
    
    // 收到feedback后调用该回调函数
    void feedbackCb(const learning_communication::DoDishesFeedbackConstPtr& feedback)
    {
       ROS_INFO(" percent_complete : %f ", feedback->percent_complete);
    }
    
    int main(int argc, char** argv)
    {
       ros::init(argc, argv, "do_dishes_client");
    
       // 定义一个客户端
       Client client("do_dishes", true);
    
       // 等待服务器端
       ROS_INFO("Waiting for action server to start.");
       client.waitForServer();
       ROS_INFO("Action server started, sending goal.");
    
       // 创建一个action的goal
       learning_communication::DoDishesGoal goal;
       goal.dishwasher_id = 1;
    
       // 发送action的goal给服务器端,并且设置回调函数
       client.sendGoal(goal,  &doneCb, &activeCb, &feedbackCb);
    
       ros::spin();
    
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    4、添加编译选项

    在 CMakeLists.txt 文件中设置编译代码
    a、流程:
    (1)设置需要编译的代码和生成的可执行文件
    (2)设置链接库
    (3)设置依赖
    打开learning_communication功能包中的 CMakeLists.txt 文件,添加如下代码:

    add_executable(DoDishes_client src/DoDishes_client.cpp)
    target_link_libraries(DoDishes_client ${catkin_LIBRARIES})
    add_dependencies(DoDishes_client ${${PROJECT_NAME}_EXPORTED_TARGETS})
    
    add_executable(DoDishes_server src/DoDishes_server.cpp)
    target_link_libraries(DoDishes_server ${catkin_LIBRARIES})
    add_dependencies(DoDishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    b、编译:
    在yyj_ws 工作空间层级下生成可执行文件:

    catkin_make
    
    • 1

    5、运行可执行文件

    a、启动ROS Master
    终端1:

    roscore
    
    • 1

    b、启动client
    终端2:

    rosrun learning_communication DoDishes_client
    
    • 1

    c、启动server
    终端3:

    rosrun learning_communication DoDishes_server
    
    • 1

    如没把环境变量直接写进.bashrc,则每次打开新终端都需添加环境变量

    source ~/yyj_ws/devel/setup.bash
    
    • 1

    ROS学习(四)

    ROS基础

    五、分布式通信

    ROS是一种分布式软件框架,节点之间通过松耦合的方式进行组合。

    1、配置IP与环境

    两台机子连接同一网络,利用指令查看各自的ip,wlan0 的inet addr 后就是 IP 地址。

    ifconfig
    
    • 1

    再查看各自的计算机名称

    hostname
    
    • 1

    打开/etc/hosts文件分别输入对方的IP与计算机名

    sudo gedit /etc/hosts
    
    • 1

    本人的配置:
    (注意两台机子交叉输入对方的信息)

    192.168.52.47   frany-PF4WN2F 
    192.168.52.83   ltstl308-desktop
    
    • 1
    • 2

    配置完毕后分别在两台机子上ping测试底层网络通信是否成功

    ping frany-PF4WN2F 
    ping  ltstl308-desktop
    
    • 1
    • 2

    如网络畅通,则底层网络通信无误。
    在从机中打开.bashrc文件设置对方的ROS_MASTER_URI

    sudo gedit ~/.bashrc
    export ROS_MASTER_URI=http://ltstl308-desktop:11311
    
    • 1
    • 2

    其中ROS Master的默认端口号为11311。

    2、小乌龟测试

    在主机中运行小乌龟仿真器

    roscore
    rosrun turtlesim turtlesim_node
    
    • 1
    • 2

    在从机中查看话题列表

    rostopic list
    
    • 1

    会看见:

    /rosout
    /rosout_agg
    /turtle1/cmd_vel
    /turtle1/color_sensor
    /turtle1/pose
    
    • 1
    • 2
    • 3
    • 4
    • 5

    然后发布小乌龟运动控制消息:

    rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
    
    • 1

    就可看见主机的小乌龟圆周运动。

    ROS学习(五)

    ROS基础

    五、ROS的关键组件

    (1)launch文件

    通过XML文件实现多节点的配置和启动(可自动启动ROS master)
    根元素采用该标签定义
    启动节点

    pkg: 节点所在的功能包名称
    type:节点的可执行文件名称
    name:节点运行时的名称
    output:打印输出信息到终端
    respawn:节点失效或者失败则重新启动
    required:节点必须有,否则launch失败
    ns:命名空间
    args:参数
    param:ros 全局变量
    arg:launch中局部变量
    在这里插入图片描述
    在这里插入图片描述

    (2)TF变换

    TF管理一些位置坐标变换
    是通过广播TF变换,监听TF变换关系实现
    小海龟跟随例程

    #安装功能包
    sudo apt-get install ros-kinetic-turtle-tf
    #启动launch文件
    roslaunch turtle_tf turtle_tf_demo.launch
    #启动控制节点
    rosrun turtlesim turtle_teleop_key
    #能够监听当前时刻所有通过ROS广播的tf坐标系,并绘制出树状图表示坐标系之间的连接关系保存到离线文件中,监听5秒后,保存5秒内坐标系之间的关系,会生成一个pdf文件。
    rosrun tf view_frames
    #使用tf_echo工具可以查看两个广播参考系之间的关系
    rosrun tf tf_echo turtle1 turtle2
    #通过rvize可视化工具更加形象的看到这三者之间的关系
    rosrun rviz rviz -d 'rospack find turtle_tf' /rviz/turtle.rviz
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    用代码实现

    #创建功能包
    catkin_create_pkg learning_tf roscpp rospy tf turtlesim
    #再learning_tf/src中创建cpp文件
    touch turtle_tf_broadcaster.cpp
    touch turtle_tf_listener.cpp
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在turtle_tf_broadcaster.cpp中写入

    #include 
    #include 
    #include 
    
    std::string turtle_name;
    
    void poseCallback(const turtlesim::PoseConstPtr& msg)
    {
    // 创建tf的广播器
    static tf::TransformBroadcaster br;
    
    // 初始化tf数据
    tf::Transform transform;
    transform.setOrigin( tf::Vector3(msg->x, msg->y, 0.0) );
    tf::Quaternion q;
    q.setRPY(0, 0, msg->theta);
    transform.setRotation(q);
    
    // 广播world与海龟坐标系之间的tf数据
    br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
    }
    
    int main(int argc, char** argv)
    {
        // 初始化ROS节点
    ros::init(argc, argv, "my_tf_broadcaster");
    
    // 输入参数作为海龟的名字
    if (argc != 2)
    {
    ROS_ERROR("need turtle name as argument"); 
    return -1;
    }
    
    turtle_name = argv[1];
    
    // 订阅海龟的位姿话题
    ros::NodeHandle node;
    ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);
    
        // 循环等待回调函数
    ros::spin();
    
    return 0;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在turtle_tf_listener.cpp中写入

    #include 
    #include 
    #include 
    #include 
    
    int main(int argc, char** argv)
    {
    // 初始化ROS节点
    ros::init(argc, argv, "my_tf_listener");
    
        // 创建节点句柄
    ros::NodeHandle node;
    
    // 请求产生turtle2
    ros::service::waitForService("/spawn");
    ros::ServiceClient add_turtle = node.serviceClient("/spawn");
    turtlesim::Spawn srv;
    add_turtle.call(srv);
    
    // 创建发布turtle2速度控制指令的发布者
    ros::Publisher turtle_vel = node.advertise("/turtle2/cmd_vel", 10);
    
    // 创建tf的监听器
    tf::TransformListener listener;
    
    ros::Rate rate(10.0);
    while (node.ok())
    {
    // 获取turtle1与turtle2坐标系之间的tf数据
    tf::StampedTransform transform;
    try
    {
    listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(3.0));
    listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);
    }
    catch (tf::TransformException &ex) 
    {
    ROS_ERROR("%s",ex.what());
    ros::Duration(1.0).sleep();
    continue;
    }
    
    // 根据turtle1与turtle2坐标系之间的位置关系,计算turtle2需要运动的线速度和角速度
    // 并发布速度控制指令,使turtle2向turtle1移动
    geometry_msgs::Twist vel_msg;
    vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),
                            transform.getOrigin().x());
    vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +
                          pow(transform.getOrigin().y(), 2));
    turtle_vel.publish(vel_msg);
    
    rate.sleep();
    }
    return 0;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    在CMakeLists.txt中添加以下代码:

    add_executable(turtle_tf_broadcaster src/turtle_tf_broadcaster.cpp)
    target_link_libraries(turtle_tf_broadcaster ${catkin_LIBRARIES})
    
    add_executable(turtle_tf_listener src/turtle_tf_listener.cpp)
    target_link_libraries(turtle_tf_listener ${catkin_LIBRARIES})
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在工作空间根目录编译

    catkin_make
    
    • 1

    source以下工作空间

    source devel/setup.bash
    
    • 1

    启动ROS Master

    roscore
    
    • 1

    启动小海龟仿真器

    rosrun turtlesim turtlesim_node
    
    • 1

    发布/turtle1海龟坐标系关系

    rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1
    
    • 1

    注:turtle_tf_broadcaster __name:=turtle1_tf_broadcaster 重新命名

    发布/turtle2海龟坐标系关系

    rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2
    
    • 1

    启动自定义的节点

    rosrun learning_tf turtle_tf_listener
    
    • 1

    启动海龟控制节点

    rosrun turtlesim turtle_teleop_key
    
    • 1

    或者创建launch文件

    #在/learning_tf创建launch文件夹
    mkdir launch
    #进入launch文件夹创建launch文件
    touch start_demo_with_listener.launch
    
    • 1
    • 2
    • 3
    • 4

    在launch文件中写入

    
    
       
       
       
       
       
       
       
       
       
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    启动launch文件即可用键盘控制海龟

    roslaunch learning_tf start_demo_with_listener.launch
    
    • 1

    (3)QT工具箱

    日志消息

    rqt_console
    
    • 1

    计算图可视化工具

    rqt_graph
    
    • 1

    数据绘图工具

    rqt_plot
    
    • 1

    参数动态配置工具

    rosrun rqt_reconfigure rqt_reconfigure
    
    • 1

    rqt_按tab键就可看见相关工具

    (4)rviz可视化平台

    数据可视化
    插件机制

    (5)gazebo物理仿真环境

    机器人仿真、功能/算法验证
    带有物理熟悉的仿真环境,云端+本地
    安装

    sudo apt-get install ros-kinetic-gazebo-ros-pkgs ros-kinetic-gazebo-ros-control
    
    • 1
    roslaunch gazebo_ros empty_world.launch
    
    • 1

    gazebo_ros -用于gazebo接口封装、gazebo服务端和客户端的启动、URDF模型生成等。
    gazebo_msgs-gazebo的Msg和Srv数据结构
    gazebo_plugins-用于gazebo的通用传感器插件
    gazebo_ros_api_plugins 和 gazebo_ros_path_plugin 这俩个gazebo的插件实现接口封装
    gazebo仿真步骤
    创建仿真环境
    配置机器人模型
    开始仿真

    ROS学习(六)

    机器人系统设计

    查看指针中的具体成员变量

    show turtlesim/Pose
    
    • 1

    机器人的定义与组成

    执行机构
    驱动系统
    传感系统
    控制系统

    机器人系统构建

    1、执行机构
    底盘、电机、舵机
    2、驱动系统
    电源子系统
    电机驱动子系统
    传感器接口:超声波、里程计
    3、传感系统
    机器人里程计
    惯性测量单元

    连接摄像头:

    cd catkin_ws/src
    git clone https://github.com/bosch-ros-pkg/usb_cam.git
    cd ~/catkin_ws
    catkin_make
    roslaunch usb_cam usb_cam-test.launch
    rqt_image_view
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    连接kinect:

    sudo apt-get install ros-kinect-freenect-*
    git clone http://github.com/avin2/SensorKinect.git
    cd SensorKinect/Bin
    tar xvf SensorKinect093-Bin-Linux-x86-v5.1.2.1.tar.bz2
    cd Sensor-Bin-Linux-x86-v5.1.2.1/
    sudo ./install.sh
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在src下建立一个freenect.launch文件并写入

    
    
    
        
        
            
            
            
            
            
            
            
            
            
    
        
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在此层目录下运行freenect.launch

    roslaunch freenect.launch 
    rosrun rviz rviz
    
    • 1
    • 2

    将Global options下的fixed frame改成camera_rgb_optical_frame
    添加pointcloud2和image并分别订阅话题即可
    连接rplidar:

    #在工作空间的src下安装雷达的ros包
    git clone https://github.com/Slamtec/rplidar_ros.git
    #编译工作空间
    catkin_make
    #查看雷达串口权限
    ls -l /dev |grep ttyUSB
    #修改权限
    sudo chmod 666 /dev/ttyUSB0
    #查看雷达扫描点云图
    roscore
    roslaunch rplidar_ros view_rplidar.launch
    #运行雷达
    rosrun rplidar_ros rplidarNode
    #在终端查看雷达数据
    rosrun rplidar_ros rplidarNodeClient
    #或者
    echo /scanl
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    URDF机器人建模

    URDF是Unified Robot Description Format,统一机器人描述格式
    可以解析URDF文件中使用XML格式描述的机器人模型
    ROS同时也提供URDF文件的C++解析器

    描述机器人某个刚体部分的外观和物理属性;尺寸、颜色、形状、惯性矩阵、碰撞参数等 描述机器人link部分的外观参数 描述link的惯性参数 描述link的碰撞属性 描述机器人关节的运动学属性和动力学属性,包括关节运动的位置和速度限制,根据关节形式,可以将其分为六种类型。 实践: urdf:存放机器人模型的URDF或xacro文件 meshes:放置URDF中引用的模型渲染文件 launch:保存相关启动文件 config:保存rviz的配置文件

    catkin_create_pkg mbot_description urdf xacro
    
    • 1

    joint_state_publisher:发布每个joint(除fixed类型)的状态,而且可以通过UI界面对joint进行控制
    robot_state_publisher:将机器人各个links、joints之间的关系,通过TF的形式,整理成三维姿态信息发布
    在launch文件中创建display_mbot_base_urdf.launch文件写入

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15


    在URDF文件夹下检查机器人URDF模型的整体架构

    #先将 xacro 文件解析成 urdf 文件
    rosrun xacro xacro xxx.xacro > xxx.urdf
    urdf_to_graphiz xxxxx.urdf
    
    • 1
    • 2
    • 3
  • 相关阅读:
    客户机操作系统已禁用 CPU。请关闭或重置虚拟机(解决)
    【模型训练】YOLOv7训练visdrone数据集
    1064 Complete Binary Search Tree
    猿创征文|从JAVAER到GISER的进击之路
    8.吴恩达机器学习-异常检测
    Web Development with Python Step1
    如何实现延迟任务,这11种方式才算优雅!
    ESP32C3基于Arduino框架下的 ESP32 RainMaker开发示例教程
    华秋电子余宁荣获2022年PCB行业先进科技工作者奖项
    提升用户体验,给你的模态弹窗加个小细节
  • 原文地址:https://blog.csdn.net/feichangyanse/article/details/133000927