zoukankan      html  css  js  c++  java
  • ROS基础

    话题编程

    实现发布者talker.cpp

     1 #include <sstream>
     2 #include "ros/ros.h"
     3 #include "std_msgs/String.h"
     4 
     5 int main(int argc, char **argv)
     6 {
     7     //ROS节点初始化
     8     ros::init(argc, argv, "talker");
     9     
    10     //创建节点句柄
    11     ros::NodeHandle n;
    12 
    13     //创建一个publisher,发布名为chatter的topic,消息类型为std_msgs::String
    14     ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
    15 
    16     //设置循环的频率
    17     ros::Rate loop_rate(10);
    18 
    19     int count = 0;
    20     while (ros::ok())
    21     {
    22         //初始化std_msgs::String类型的消息
    23         std_msgs::String msg;
    24         std::stringstream ss;
    25         ss << "hello world" << count;
    26         msg.data = ss.str();
    27 
    28         //发布消息
    29         ROS_INFO("%s", msg.data.c_str());
    30         chatter_pub.publish(msg);//发布
    31 
    32         //循环等待回调函数
    33         ros::spinOnce();
    34         
    35         //按照循环频率延时
    36         loop_rate.sleep();
    37         ++count;
    38     }
    39     return 0;
    40 }

    实现订阅者listener.cpp

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

    设置需要编译的代码和生成的可执行文件;设置链接库;设置依赖。CMakeLists.txt

     1 cmake_minimum_required(VERSION 2.8.3)
     2 project(learning_communication)
     3 
     4 find_package(catkin REQUIRED COMPONENTS
     5   roscpp
     6   rospy
     7   std_msgs
     8 )
     9 
    10 catkin_package(
    11 #  INCLUDE_DIRS include
    12 #  LIBRARIES learning_communication
    13 #  CATKIN_DEPENDS roscpp rospy std_msgs
    14 #  DEPENDS system_lib
    15 )
    16 
    17 include_directories(
    18 # include
    19   ${catkin_INCLUDE_DIRS}
    20 )
    21 
    22 add_executable(talker src/talker.cpp)
    23 
    24 add_executable(listener src/listener.cpp)
    25 
    26 target_link_libraries(talker
    27    ${catkin_LIBRARIES}
    28 )
    29 
    30 target_link_libraries(listener
    31    ${catkin_LIBRARIES}
    32 )

    listener.cpp,talker.cpp,CMakeLists.txt三部分。

    发布

    订阅

    1.在msg/Person.msg中定义msg文件

    string name
    uint8 sex
    uint8 age
    
    uint8 unknown = 0
    uint8 male = 1
    uint8 female = 2

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

    <build_depend>message_generation</build_depend>

    <exec_depend>message_runtime</exec_depend>

    将package.xml中的注释去掉即可。

    3.在CMakeLists.txt添加编译选项(与消息有关)

    find_package(...message_generation)
    catkin_package(CATKIN_DEPENDS roscpp rospy std_msgs message_runtime)
    add_message_files( FILES Person.msg)

    generate_messages(DEPENDENCIES std_msgs)

    编译后,查看自定义消息是否成功

    服务编程

    1.在srv/AddTwoInts.srv中自定义服务请求与应答

    int64 a
    int64 b
    ---
    int64 sum

    2.在package.xml中添加功能包依赖(同上)

    3.在CMakeLists.txt添加编译选项(与服务有关)

    add_service_files( FILES AddTwoInts.srv) 部分内容已在消息编程中添加。

    实现服务器server.cpp

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

    实现客户端client.cpp

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

    启动Server节点

    等待

    客户端发布服务请求

    服务端接收到请求,完成加法,将结果发给客户端。

    动作编程

    1.在action/DoDishes.action中自定义动作消息

    #定义目标信息
    uint32 dishwasher_id
    #Specify which dishwasher we want to use
    ---
    #定义结果信息
    uint32 total_dishes_cleaned
    ---
    #定义周期反馈的消息
    float32 percent_complete

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

    <build_depend>actionlib</build_depend>
    <build_depend>actionlib_msgs</build_depend>
    <exec_depend>actionlib</exec_depend>
    <exec_depend>actionlib_msgs</exec_depend>

    3.在CMakeLists.txt添加编译选项

    find_package(catkin REQUIRED actionlib_msgs actionlib)
    add_action_files(DIRECTORY action FILES DoDishes.action)
    generate_messages(DEPENDENCIES actionlib_msgs)

    在原编译选项中添加,不应完全复制进CMakeLists.txt中。

    实现动作服务器DoDishes_server.cpp

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

    实现动作客户端DoDishes_client.cpp

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

    运行过程中

    运行结束

    TF坐标变换

    roslaunch turtle_tf turtle_tf_demo.launch

    往另一个乌龟运动。

    rosrun turtlesim turtle_teleop_key

    控制一只乌龟运动,另一只乌龟追。

    rosrun tf view_frames

    监听5秒,生成PDF文件。

    实时监听输出坐标变换信息

    (可以看出只有平移变换)

    TF坐标变换编程

    先建一个功能包

    应该在catkin_learning/src/下输入命令,上图有错误。

    TF广播器turtle_tf_broadcaster.cpp

     1 #include <ros/ros.h>
     2 #include <tf/transform_broadcaster.h>
     3 #include <turtlesim/Pose.h>
     4 
     5 std::string turtle_name;
     6 
     7 void poseCallback(const turtlesim::PoseConstPtr& msg)
     8 {
     9     // tf广播器
    10     static tf::TransformBroadcaster br;
    11 
    12     // 根据乌龟当前的位姿,设置相对于世界坐标系的坐标变换
    13     tf::Transform transform;
    14     transform.setOrigin( tf::Vector3(msg->x, msg->y, 0.0) );
    15     tf::Quaternion q;
    16     q.setRPY(0, 0, msg->theta);//z轴转
    17     transform.setRotation(q);
    18 
    19     // 发布坐标变换
    20     br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
    21 }
    22 
    23 int main(int argc, char** argv)
    24 {
    25     // 初始化节点
    26     ros::init(argc, argv, "my_tf_broadcaster");
    27     if (argc != 2)
    28     {
    29         ROS_ERROR("need turtle name as argument"); 
    30         return -1;
    31     };
    32     turtle_name = argv[1];
    33 
    34     // 订阅乌龟的pose信息
    35     ros::NodeHandle node;
    36     ros::Subscriber sub = node.subscribe(turtle_name+"/pose", 10, &poseCallback);
    37 
    38     ros::spin();
    39 
    40     return 0;
    41 };

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

    修改CMakeLists.txt

    除此之外,在find_package中添加tf,turtlesim,std_msgs。

    添加start_demo_with_listener.launch

     1  <launch>
     2     <!-- 海龟仿真器 -->
     3     <node pkg="turtlesim" type="turtlesim_node" name="sim"/>
     4 
     5     <!-- 键盘控制 -->
     6     <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>
     7 
     8     <!-- 两只海龟的tf广播,发布坐标关系 -->
     9     <node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster" />
    10     <node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster" />
    11 
    12     <!-- 监听tf广播,并且控制turtle2移动 -->
    13     <node pkg="learning_tf" type="turtle_tf_listener" name="listener" />
    14 
    15  </launch>

  • 相关阅读:
    C#计算两个时间年份月份天数(根据生日计算年龄)差,求时间间隔
    C#四舍五入保留一位小数
    给Editplus去掉.bak文件
    $().each() 与 $.each()解析
    VS 2013+Qt 5.4.1
    HDU 5228 ZCC loves straight flush( BestCoder Round #41)
    产品经理的修炼:如何把梳子卖给和尚
    c++ STL unique , unique_copy函数
    linux定时备份mysql数据库文件
    Python——异常基础
  • 原文地址:https://www.cnblogs.com/112358nizhipeng/p/9398858.html
Copyright © 2011-2022 走看看