环境:ros-kinetic ubuntu16.04 vscode C++
这里记录一下如何编写一个自定义node来服务一些功能上面需求.这是个人一些经验记录,仅仅供参考.
举个简单例子(方便自己以后也能一看就明白,哈哈哈),编写一个node来记录车子的运动和实际距离偏差.
写node的话,有三个主要地方要注意.:aaa.cpp / CMakeList.txt /package.xml
首先,CMakeList.txt 要添加相应的 编写需要的相关库文件,以及要编译的文件等等,常见的标签有:
cs_add_executable(aaa xx/aaa.cpp)
target_link_libraries(aaa xxx)
其次,需要在package.xml文件添加一些编译该文件需要的依赖和运行的依赖:如
<build_depend>nav_msgs</build_depend>
<run_depend>nav_msgs</run_depend>
上面两个是个人也只是一个大致了解,具体专业的解析还是参考那些大神级别的吧.下面记录一下这个node和topic写法:
#include <ros/ros.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
#include <tf2_ros/transform_broadcaster.h>
#include <tf2_ros/transform_listener.h>
#include<iostream>
#include<string>
#include<fstream>
#include<regex>
#include <csignal>
#include <std_msgs/Int8.h>
#include<nav_msgs/Odometry.h>
#include <std_msgs/Float64.h>
using namespace std;
using namespace tf2_ros;
double theory_dic=0.0;
double a=0.0;
double b=0.0;
double error_value=0.0;
bool read_odom=false;
double real_distance=0.0;
//程序:发送一个start topic,,然后内部不断计算机器人的理论运动距离值,然后,给一个real_distance topic ,程序会不断打印真实和理论值的距离误差.注释部分是根据个人的经验来写的,并不严谨,可能有误.
void odom_value_(const nav_msgs::Odometry::ConstPtr& msg)//回调函数一定是void型;并且一定要定义一个参数来接受topic的参数,数据类型定义根据传入数据类型来确定,要满足 ros::msg要求
{
if(read_odom){
a=msg->pose.pose.position.x;
b=msg->pose.pose.position.y;//记录机器人开始位置
read_odom=false;
}
theory_dic=sqrt(pow((msg->pose.pose.position.x-a),2)+pow((msg->pose.pose.position.y-b),2));//实时计算机器人运动距离
}
void real_distance_value_(const std_msgs::Float64 &measured_distance_value)//回调函数必须是void型;要有变量接收topic数据
{
real_distance=measured_distance_value.data;//ros-msg里面的参数是封装好的,需要 . 来访问,才能赋值给real_distance
error_value=real_distance-theory_dic;
}
void start_(const std_msgs::Float64 &a_start)//回调函数必须是void型;要有变量接收topic数据
{
if(a_start>0)
{
read_odom=true;
}
}
int main(int argc, char **argv) {
ros::init(argc, argv, "calculate");//创建的node 名字叫 calculate
ros::NodeHandle nh("~");//可以理解为 局部性质,这些在nh下面定义的topic,只能在该程序下面进行相应的操作,而对于roscore启动的一些topic发布的消息等等,无权访问
ros::NodeHandle n;//可以理解为 全局性质, 在roscore里面发布的如 odom 等等可以访问
ros::Rate looprate(100);
ros::Subscriber sub_odom_listener=n.subscribe("odom",1000, odom_value_);//全局性质的topic ,可以不断获取机器人发布在roscore上面的odom消息
ros::Subscriber sub_line=nh.subscribe("start",1, start_);//start 就是创建的topic名称;属于局部性质的topic ,可以通过rqt_gui方式发送参数到程序里面
ros::Subscriber sub_line=nh.subscribe("real_distance",1, real_distance_value_);//real_distance就是创建的topic,基本性质跟上面的start topic一样
while(ros::ok()){
ROS_INFO("error_value: [%f]", error_value);//只要roscore没有关闭以及程序没有打断,都可以不断发布消息
}
}
//简单总结一下:
//上面的程序可以获取到一个node: calculate ;多个监听类型的topic: odom/start/real_distance
//1 每个topic需要给定一个非返回类型的回调函数,并且该回调函数需要有参传入
//2 回调函数的传入的参数是接受topic的数据的,所以其类型定义根据topic数据类型来定义
//3 需要访问roscore的其他node发布的消息的topic,需要定义为 n 形式;个人定义的 可以选择定义为 nh("~") 形式
//案例里面的注释是根据个人的理解直接给出的,都不是专业的解释.哈哈哈,主要是方便自己.哈哈哈,抱歉各位.
//上面很多都有专业名称的解析,如句柄什么的,想了解的可以搜索查看一下;这个例子是个人一些总结,可能很多地方都表述不对,希望有大佬看见可以帮忙点出.
本人还是小菜级,希望有不足之处,大佬可以指出.