ROS学习笔记(一)补充篇 参考创客制造

我将ROS的CPP部分分成7个部分:
1、基础的node param
2、动态调节参数
3、关于TF变换
4、actionlib
5、插件技术
6、movebase
7、nodelet技术

前言

相比于ros学习笔记一,ros学习笔记一补充篇将会更加注重代码的讲解。ros学习笔记一只是像大观园一样,看看ROS这个领域的山山水水。而ros学习笔记一补充篇将会深入的补充这些山山水水的来源

节点node

rosrun 使用格式:
rosrun 包名 节点名
rosnode list 将会显示出正在运行的节点,其实我们平时都是直接用rosrun rqt_graph rqt_graph来吧正在运行的节点和话题之间的信息给显示出来

话题

节点node1和节点node2是通过话题来通信,节点node1发布topic1,而节点node2订阅topic1
我们可以输入 rostopic echo 话题1来显示出话题的信息
如何查看一个node到底能够发布多少个话题,用
rostopic list
在这个下面列出来的topic都是可以被订阅的
这里写图片描述
当然也 可以用

rostopic echo /

然后 不停的按tab回车来显示出来
这里写图片描述

发布publish

使用rostopic pub可以吧数据发布到某个正在广播的话题上面
1、我们可以用rostopic type 话题名
来查看这个话题的数据类型
2、然后rosmsg show 话题的数据类型名
3、有了1,2,这两个参数我们就可以发布话题了
示例:

rostopic pub -1 话题名称 话题的数据类型 需要改变的参数
rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]' 

编写简单的消息发布器和订阅器 (C++) catkin方式

前提准备:
talker.cpp

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  ros::Rate loop_rate(10);
  int count = 0;
  while (ros::ok())
  {
    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"

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  ros::spin();

  return 0;
}

我下面将两种编译方式,看情况而定,反正我都会哈哈~
当然,个人比较倾向于用IDE,但是用终端编译是最准确的
先讲用终端命令行进行编译吧。
这个是个很经典的框架,很值得记忆!!!!

cd Desktop/
mkdir -p dao/src 这里建立一个stack叫做dao
cd huazi/src/
catkin_init_workspace
cd ..
catkin_make
cd src
catkin_create_pkg daodao roscpp rospy std_msgs genmsg 这里建立一个package叫做daodao

然后把talk.cpp文件放到里面
然后在CMakeLists.txt中修改,这里说的是修改,就是把几个分号给去掉,或者说直接把语句添加上

 add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker dao_generate_messages_cpp)当然这句话不加也是可以的

这里写图片描述
要说明的一点就是,这里dao_generate_messages_cpp当中的dao就是我的这个stack的名字
然后做完这一切工作之后,就是stack的目录下进行catkin_make

cd ..
catkin_make

这里写图片描述
然后运行一些这个节点

roscore
source ~/Desktop/dao/devel/setup.bash
rosrun daodao talker

这里写图片描述


第二种编译方式
打开Roboware
在桌面上创建一个叫dao111的stack
然后新建一个daodao的包,如果你不知道如何新建一个包的话,就请到我的Roboware学习笔记那篇里面有如何新建一个包的过程
然后新建一个talker.cpp的文件,然后输入代码

值得注意的一点就是,这里的find_package 就要自己写了

这里写图片描述

这里写图片描述
另外,很重要很重要的框架
就是按照这个样子来建立文件
这里写图片描述
然后你就可以在这里看到package 和 node 的名字
这里写图片描述
然后运行
这里写图片描述

好到这里两种调试方法结束啦~
在这里我想做个总结,就是packagename自己在创建文件夹的时候时候自己定义的,node的名字值在写cpp文件当中自己的定义的,其中cpp的文件名字就是node的名字


代码解析:
框架:

#include"ros/ros.h"
#include"std_msgs/String.h"
int main(int argc,char **argv)
{
    ros::init(argc,argv,"节点名")
    ros::NodeHandle n;
}

一个很经典的语句:

ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

就像是int a=1;在这句话中返回值数据类型是int
因此在上一条语句中返回值的数据类型是ros::Publisher,调用句柄n的一个advertise的函数,这个函数的返回值的数据类型是<std_msgs/String>
(引用一句很经典的话:告诉master,我们要在chatter上发布一个<std_msgs/String>的数据类型) 这里chatter就是topic的话题的名称,1000就是按照我的理解是,在1000字符以内吧

ros::Rate loop_rate(10);
loop_rate.sleep();

这里的10表示的是10hz,如果是1的话,就是1Hz,也即是没1s更新一次

ROS_INFO("%s", msg.data.c_str());
ros::spinOnce();这个地方应该是回调机制
chatter_pub.publish(msg);这里向所有订阅chatter(话题)的节点发布消息我觉的可以记住这个框架,实例化两个对象,
   std_msgs::String msg;
    std::stringstream ss;
    ss<<count;
    msg.data=ss.str();
    ROS_INFO("%s",msg.data.c_str());

小例子1、

我用上面的框架,写了一个自己的小例子,每隔1秒,向终端ros发布1,2,3…
程序:

#include<sstream>
#include"ros/ros.h"
#include"std_msgs/String.h"
int main(int argc, char **argv)
{
    ros::init(argc,argv,"Num");
    ros::NodeHandle n;
    ros::Publisher chatter_pub=n.advertise<std_msgs::String>("getNum",1000);//使用这条语句发布信息
    ros::Rate loop_rate(1);
    int count=0;
    while(ros::ok())
    {
        std_msgs::String msg;
        std::stringstream ss;
        ss<<count;
        msg.data=ss.str();
        ROS_INFO("%s", msg.data.c_str());
        chatter_pub.publish(msg);
        ros::spinOnce();
        loop_rate.sleep();
        ++count;
    }
}

这里写图片描述
另外一定要注意大小写。


小例子2

然后下面我想讲的就是吧这个节点发布的消息给了另外一个节点,然后这这个节点打印出来
这是我的目标
这里写图片描述
效果:
这里写图片描述
Num.cpp

#include<sstream>
#include"ros/ros.h"
#include"std_msgs/String.h"
int main(int argc, char **argv)
{
    ros::init(argc,argv,"Num");
    ros::NodeHandle n;
    ros::Publisher chatter_pub=n.advertise<std_msgs::String>("getNum",1000);//使用这条语句发布信息
    ros::Rate loop_rate(1);
    int count=0;
    while(ros::ok())
    {
        std_msgs::String msg;
        std::stringstream ss;
        ss<<count;
        msg.data=ss.str();
        chatter_pub.publish(msg);
        ros::spinOnce();
        loop_rate.sleep();
        ++count;
    }
}

get.cpp

#include"ros/ros.h"
#include"std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("%s", msg->data.c_str());
}
int main(int argc, char **argv)
{
    ros::init(argc,argv,"get");
    ros::NodeHandle n;
    ros::Subscriber sub=n.subscribe("getNum",1000, chatterCallback);
    ros::spin();
}

代码解析和总结:

这两句命令在在一起记忆:

ros::spinOnce();
ros::spin();

在publish的cpp文件当中

ros::spinOnce();如果没有这个函数的话,就没有回调信息

在subscribe的cpp文件当中

ros::spin();产生回调信息

然后这个框架我真的觉得应该记住

        std_msgs::String msg;实例化类型
        std::stringstream ss;
        ss<<count;将输出数值给了ss
        msg.data=ss.str();将ss和msg相互关联,这样的话后面的输出做准备
        chatter_pub.publish(msg);向刚刚的msg的话题进行发布
        ros::spinOnce();产生对应的回调函数,在getcpp当中哟对应的
        loop_rate.sleep();
        ++count;

这个输出的回调函数应该是要记住的

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("%s", msg->data.c_str());
}

这个在主函数的当中调用机制也是应该熟悉的!

ros::Subscriber sub=n.subscribe("getNum",1000, chatterCallback);

最后别忘记在CMakeLists.txt当中添加2条语句哈。


python的实现

1、发布一个话题

第一种方式,使用终端实现
在工作区间下

cd catkin_ws/src
catkin_create_pkg daodao roscpp rospy std_msgs genmsg
cd daodao
mkdir scripts
cd scripts
vim talker.py
chmod +x talker.py

talker表示的是发布一个话题
往talker.py中写这些

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass

然后

cd ~/catkin_ws
catkin_make
source ~/catkin_ws/devel/setup.bash
rosrun daodao talker.py

这里写图片描述
直接就运行成功了

第二种编译方式:
使用roboware

同样使用roboware的时候,还是需要安装一些软件的
为了支持python的调试功能,需要安装pylint

sudo apt-get install python-pip
sudo python -m pip install pylint

同时为了获取更好的代码补齐体验,需要安装clang

sudo apt-get install clang

然后把代码写进去,就可以运行了,在这次调试的过程中,我发现直接在调试窗口,更好一些,能够犯得错误更少
意外情况1:
这里写图片描述
这是因为roscore没开
另外,指的注意的一点是仍要写cmakelists文件,
这里写图片描述
意外情况2:
这里写图片描述
这是因为python没有加#!/usr/bin/python
意外情况3:
这里写图片描述
这是因为每天添加可执行文件chmod +x talker.py
成功运行:
这里写图片描述
建议吧python的代码放到scripts这个文件夹中 src中放Cpp文件
这里写图片描述

代码解析:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass
#!/usr/bin/python
# -*- coding: UTF-8 -*-

让编译器找到python

import rospy
from std_msgs.msg import String

导入rospy客户端,和std_msg/String 这个数据类型
queue_size表示的对应的大小

pub = rospy.Publisher('chatter', String, queue_size=10)

这个是话题的名称chatter

rospy.init_node('talker')

初始化节点,节点的名字要唯一,并且不能

rate=rospy.Rate(10)

创建rate对象,与sleep()函数结合使用,控制话题消息发布的频率

while not rospy.is_shutdown():
    hello_str = "hello world %s" % rospy.get_time()
    rospy.loginfo(hello_str)
    pub.publish(hello_str)
    rate.sleep()

rospy.is_shutdown()函数是什么意思,目前还不知道。
rate.sleep()用于控制发布的频率
rospy.loginfor(str) 函数在屏幕输出信息,我们把这个信息存储在hello_str当中


2、订阅一个话题

#!/usr/bin/python
import rospy
from std_msgs.msg import String

def callback(data):
    rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)

def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("chatter", String, callback)
    rospy.spin()
if __name__ == '__main__':
    listener()

最后别忘记给listener.py添加可执行权限chmod +x listener.py
这里写图片描述
测试可以通过
这里写图片描述
代码分析

def callback(data):
    rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)

这里是定义一个回调函数

def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("chatter", String, callback)
    rospy.spin()

定义listener函数,
第一行,初始化一个节点,后面anony=False ,默认参数是不匿名的,但是现在你也可以选择匿名。匿名之后就不会被重复了
第二行是订阅话题的名称,使用回调函数来输出话题的名称
第三行rospy.spin()是保持你的节点一直运行,直到程序关闭。


接下来这篇博客当中,我希望写的是ros cpp剩下的内容,和python的所有的东西。
编写服务器和客户端
到自己的依赖项里面然后

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)

添加message_generation

 add_message_files(
   FILES
   Num.msg
#   Message2.msg
)
 add_service_files(
   FILES
#   Service1.srv
AddTwoInts.srv
 )
 generate_messages(
   DEPENDENCIES
   std_msgs
 )
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES mypackage
  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

在package.xml里面添加

  <build_depend>message_generation</build_depend>
  <run_depend>message_runtime</run_depend>

这个地方的文件名就是你当时创建的srv文件的名称
beginner_tutorials/AddTwoInts.h是由编译系统自动根据我们先前创建的srv文件生成的对应该srv文件的头文件。
里面一般就是有一个输入的参数和一个输出的参数,然后

bool add(mypackage::AddTwoInts::Request &req,mypackage::AddTwoInts::Response &res)
{
    res.sum=req.a+req.b;
    ROS_INFO_STREAM("res.sum="<<res.sum);
    return true;
}

在srv当中,我们使用—将request和respon进行分开。

int64 a
int64 b
---
int64 sum

重要的就是这一句,其实就是这个service的名称和回调函数。

 ros::ServiceServer service=nh.advertiseService("add_two_ints",add);

这个头文件姑且可以理解为stdio.h

#include <cstdlib>

利用这个头文件,能够让我们输出参数

    mypackage::AddTwoInts srv;
    srv.request.a=atoll(argv[1]);
    srv.request.b=atoll(argv[
  • 11
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值