您现在的位置是:首页 > 正文

ROS:解决 无法打开源文件、VScode开发话题(msg)、服务(srv)、动作(action)、TF

2024-04-01 05:01:45阅读 2

一.解决 无法打开源文件

出错原因:系统没有找到.h文件对应的路径。

在编写完msg、srv、action文件后,要进行编译(catkin_make) .

编译之后,msg、srv、action会生成相应的.h文件

其对应的.h文件目录在devel/include/功能包下,如下:

 解决方法:将.h文件目录加入json文件中即可。

"${workspaceFolder}/devel/include",

 然后保存json文件,就好了。

二.话题

1.案例一

talker.cpp

#include "ros/ros.h"
#include <sstream>
#include "std_msgs/String.h"

int main(int argc, char** argv){
    //ROS结点初始化
    ros::init(argc, argv, "talker");
    //创建节点句柄
    ros::NodeHandle nh;
    //创建一个publisher,发布名为chatter的topic,消息类型为std_msgs,队列长度为1000
    ros::Publisher chatter_pub=nh.advertise<std_msgs::String>("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();
        //按照循环频率延时
        loop_Rate.sleep();
        ++count;
    }
    return 0;
}

listener.cpp

#include "ros/ros.h"
#include "std_msgs/String.h"

//接收到topic后,会进入回调函数
void chatterCallback(const std_msgs::String::ConstPtr& msg){
    //打印topic信息
    ROS_INFO("I heard [%s]",msg->data.c_str());
}

int main(int argc,char **argv){
    //初始化ros节点
    ros::init(argc,argv,"listener");
    //创建节点句柄
    ros::NodeHandle nh;
    //创建一个subscribler,订阅topic为“chatter”,注册回调函数chatterCallback
    ros::Subscriber sub=nh.subscribe("chatter",1000,chatterCallback);
    //循环等待执行回调函数
    ros::spin();
    return 0;
}

CMakeList.txt

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})

2.案例二:自定义msg文件

创建名为msg的文件夹

定义msg文件,name、sex、age是变量,unknow、male、female是常量:

Person.msg

# 变量
string name
uint8 sex
uint8 age
#常量
uint8 unknow=0
uint8 male=1
uint8 female=2

package.xml 添加功能包依赖:

  <!--添加功能包依赖:msg、srv-->
  <build_depend>std_msgs</build_depend>
  <exec_depend>std_msgs</exec_depend>
  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

其中:部分ROS版本中 exec_depend需要改为run_depend

CMakeLists.txt添加编译选项:

find_package(catkin REQUIRED COMPONENTS
  message_generation
)
add_message_files(
  FILES
  Person.msg
)
generate_messages(
  DEPENDENCIES
  std_msgs
)
catkin_package(
 CATKIN_DEPENDS geometry_msgs roscpp std_msgs message_runtime
)

 之后catkin_make

查看自己定义的msg

rosmsg show Person

三.服务

创建名为srv的文件夹

定义srv文件,a、b是请求数据,sum是服务数据,也就是a、b传给服务器,服务器相加sum传给客户端:

AddTwoInts.srv

#客户端
int64 a
int64 b
---
#服务器
int64 sum

package.xml 添加功能包依赖:

  <!--添加功能包依赖:msg、srv-->
  <build_depend>std_msgs</build_depend>
  <exec_depend>std_msgs</exec_depend>
  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

其中:部分ROS版本中 exec_depend需要改为run_depend

CMakeLists.txt添加编译选项:

find_package(catkin REQUIRED COMPONENTS
  message_generation
)
add_service_files(
  FILES
  AddTwoInts.srv
)
catkin_package(
 CATKIN_DEPENDS geometry_msgs roscpp std_msgs message_runtime
)

查看自己定义的srv文件:

rossrv show AddTwoInts.srv 

client.cpp

#include <cstdlib>
#include "ros/ros.h"
#include "robot_setup_tf/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 nh;
    //创建一个client,请求add_two_service
    //service消息类型是robot_setup_tf::AddTwoInts
    ros::ServiceClient client=nh.serviceClient<robot_setup_tf::AddTwoInts>("add_two_ints");
    //创建robot_setup_tf::AddTwoInts类型的消息对象
    robot_setup_tf::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_INFO("Failed to call service add_two_ints");
        return 1;
    }
    return 0;
}

server.cpp 

#include "ros/ros.h"
#include "robot_setup_tf/AddTwoInts.h"

//回调函数,client传进a、b,完成加法后返回给sum
bool add(robot_setup_tf::AddTwoInts::Request  &req, robot_setup_tf::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("response: sum=%ld",(long int)res.sum);
    return true;
}
int main(int argc,char** argv){
    //ROS节点初始化
    ros::init(argc,argv,"add_two_ints_server");
    //创建节点句柄
    ros::NodeHandle nh;
    //创建一个名为"add_two_ints"的server,注册回调函数为add()
    ros::ServiceServer service=nh.advertiseService("add_two_ints",add);
    //循环等待回调函数
    ROS_INFO("Ready to add two ints");
    ros::spin();
    return 0;
}

CMakeList.txt

add_executable(server src/server.cpp)
target_link_libraries(server ${catkin_LIBRARIES})
add_dependencies(server ${PROJECT_NAME}_gencpp)

add_executable(client src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client ${PROJECT_NAME}_gencpp)

运行:

roscore
rosrun robot_setup_tf server
rosrun robot_setup_tf client 4 5

四.动作

创建名为action文件夹

创建action文件

DoDishes.action

#goal,定义目标信息,客户端
uint8 dishwasher_id
#Specify which dishwasher we want to use
---
#result,定义结果信息,服务器
uint8 total_dishes_cleaned
---
#feedback,定义周期反馈的消息
float32 percent_complete

package.xml添加功能包依赖

  <!--添加功能包依赖:action-->
  <build_depend>actionlib</build_depend>
  <build_depend>actionlib_msgs</build_depend>
  <exec_depend>actionlib</exec_depend>
  <exec_depend>actionlib_msgs</exec_depend>

CMakeLists.txt添加编译选项:

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

DoDishes_Client.cpp

#include <actionlib/client/simple_action_client.h>
#include "robot_setup_tf/DoDishesAction.h"

typedef actionlib::SimpleActionClient<robot_setup_tf::DoDishesAction> Client;
//当action完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,const robot_setup_tf::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 robot_setup_tf::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
    robot_setup_tf::DoDishesGoal goal;
    goal.dishwasher_id=1;
    //发送action的goal给服务器端,并且设置回调函数
    client.sendGoal(goal,&doneCb,&activeCb,&feedbackCb);
    ros::spin();
    return 0;
}

DoDishes_Server.cpp

#include "ros/ros.h"
#include <actionlib/server/simple_action_server.h>
#include "robot_setup_tf/DoDishesAction.h"

typedef actionlib::SimpleActionServer<robot_setup_tf::DoDishesAction> Server;

//收到action的goal后调用该回调函数
void execute(const robot_setup_tf::DoDishesGoalConstPtr& goal,Server* as){
    ros::Rate r(1);
    robot_setup_tf::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;
}

CMakeList.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})

五.TF编程:小乌龟跟随

turtle_tf_broadcaster.cpp

 /*
  该例程产生tf数据,并计算、发布turtle2的速度指令
 */

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>

std::string turtle_name;

void poseCallback(const turtlesim::PoseConstPtr& msg)
{
        // 创建tf的广播器
        static tf::TransformBroadcaster br;

        // 根据乌龟当前的位姿,设置相对于世界坐标系的坐标变换
        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);

        // 发布坐标变换
        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;
};

turtle_tf_listener.cpp

/**
 * 该例程监听tf数据,并计算、发布turtle2的速度指令
 */

#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <geometry_msgs/Twist.h>
#include <turtlesim/Spawn.h>

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<turtlesim::Spawn>("/spawn");
        turtlesim::Spawn srv;
        add_turtle.call(srv);

        // 创建发布turtle2速度控制指令的发布者
        ros::Publisher turtle_vel = node.advertise<geometry_msgs::Twist>("/turtle2/cmd_vel", 10);

        // 创建tf的监听器
        tf::TransformListener listener;

        ros::Rate rate(10.0);
        while (node.ok())
        {
                // 获取turtle1与turtle2坐标系之间的tf数据
                tf::StampedTransform transform;
                try
                {
                        //在tf树中查找等待"/turtle2", "/turtle1"是否存在对应变换,超时时间ros::Duration(3.0),如果不设置超时时间,可能会一直卡死
                        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的速度控制指令
                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;
};

tf_demo.launch

<launch>
    <!--海龟仿真器-->
    <node pkg="turtlesim" type="turtlesim_node" name="sim"/>

    <!--键盘控制-->
    <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>

    <!--两只海龟的tf广播-->
    <node pkg="my_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster"/>
    <node pkg="my_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster"/>

    <!--监听tf广播,并且控制turtle2移动--> 
    <node pkg="my_tf" type="turtle_tf_listener" name="listener"/>
</launch>

CMakeLists.txt

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  tf
  turtlesim
)

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})

运行:

roslaunch my_tf tf_demo.launch

网站文章

  • 基于流量双发平台的高效回归方案

    基于流量双发平台的高效回归方案

    随着易盾反垃圾业务的发展迅速,业务集群的规模也在急剧的增长,传统的通过物理机来部署的方式在灵活上越来越达不到要求。业务集群容器化迁移,如何做好质量保障,本文将基于网易易盾的实践经验,分享网易易盾的基于流量双发平台的高效回归方案。

    2024-04-01 05:01:37
  • 概率/期望dp

    概率/期望dp

    概率/期望dp都是分析从当前状态能否去到其他情况,然后进行期望/概率公式的运算,最后消元推导出一般式。

    2024-04-01 05:01:28
  • MyBatis与Spring整合

    MyBatis与Spring整合

    MyBatis与Spring整合相关文档配置文件Mybatis全局配置文件映射文件SpringMVCweb.xmlSpring配置Spring MVC 配置spring-servlet.xmlcont...

    2024-04-01 05:00:48
  • hibernate查询方式

    1、OID(主键)查询 使用get方法 Customer customer=session.get(Customer.class,1l); 使用load方法 Customer customer=session.load(Customer.class,1l);2、对象导航检索: hibernate根据一个已经查到的对象,获得其关...

    2024-04-01 05:00:40
  • 【第四章】

    笔记记录

    2024-04-01 05:00:32
  • 解决git每次拉取/提交代码时都需要输入用户名和密码的方法

    解决git每次拉取/提交代码时都需要输入用户名和密码的方法

    2024-04-01 05:00:22
  • 如何在移动端测试Vue项目?

    如何在移动端测试Vue项目?

    第一步,打开cmd,输入ipconfig 我们获取到方框内的端口号,比如 xx.xx.x.xxx 我们打开项目中的config/index.js ,将这个替换其中的host 比如我们之前需要的是localhost:8888/news.html 那么我们将服务运行起来之后,就变成了 xx.xx.x.xxx:8888/news.html 如果你觉得在手机浏览器上手动输入很麻烦,那么...

    2024-04-01 04:59:42
  • APP为什么用JSON协议与服务端交互:序列化相关知识

    APP为什么用JSON协议与服务端交互:序列化相关知识

    Avro支持的数据类型非常丰富,包括C++语言里面的union类型。SOAP具有安全、可扩展、跨语言、跨平台、支持多种传输协议,有广泛的群众基础,基于HTTP的传输协议使得SOAP在穿越防火墙时具有良...

    2024-04-01 04:59:34
  • 练习7-1 编写一个程序 实现大写字母转换成小写字母,小写字母转换成大写字母 热门推荐

    #include&lt;stdlib.h&gt; #include&lt;ctype.h&gt; #include&lt;stdio.h&gt; char to_lower(char c); int main() { int c; while((c = getchar()) != EOF) putchar(to_lower(c)); return 0; } ...

    2024-04-01 04:59:26
  • 设置PPT版式

    设置PPT版式

    1.点击视图,幻灯片母版2.选中某个PPT母版,可进行编辑转载于:https://www.cnblogs.com/RogerLu/p/11495353.html

    2024-04-01 04:58:49