ROS学习笔记

参考资料:

1.CSDN-古月居21讲入门 学习笔记

2.赵虚左 AutoLabour 学习笔记

3.ros官网教程

4. Ubuntu系统根目录空间不足解决

以总文件夹P1为例

1.初始化工作空间

 cd  P1/src   --->>>  

catkin_init_workspace

2.编译工作空间 

cd   /P1   --->>>

catkin_make

3.在src下创建功能包:  (右键点击:Create Catkin Package)

命名并指定依赖

名字  + 依赖1  依赖2  依赖3

catkin_create_pkg helloworld rospy roscpp std_msgs

4,基于功能包进行开发

4.1  C++实现 helloworld 等.功能
//  1.  加入头文件
#include "ros/ros.h"

// 主函数main

int main(int argc, char  *argv[])
{
	
	//3.初始化节点
	ros::init(argc,argv,"hello_node");

	//4.输出日志
	ROS_INFO("hello world");
	return 0;
}

设置   包/src 下  CMakeLists.txt: 生成可执行文件和需要的动态链接库

###########
## Build ##
###########
               
add_executable(hello src/helloworld_c.cpp)          //构建生成可执行文件,名字尽量一致

arget_link_libraries(hello  ${catkin_LIBRARIES})   //设置可执行文件的动态链接库

在P1下用catkin_make进行编译并添加环境变量(或者添加到永久环境变量:

cd P1/

source ./devel/setup.bash

可以通过设置一下命令自动添加环境变量:

nano ~/.bashrc
source ./devel/setup.bash && echo "Command executed successfully" || echo "Command failed"

运行:   包名   程序名

roscore

roscore helloworld hello          


4.2 用python实现

在包下文件夹下,创建 scripts 文件夹

mkdir scripts

编辑要执行的helloworld_p.py文件,给予执行权限,并设置CMakeLists.txt文件:

#! /usr/bin/env python

import rospy



if __name__ == "__main__":
	rospy.init_node("helo_p")
	rospy.loginfo("hello world")
 catkin_install_python(PROGRAMS
   scripts/helloworld_p.py
   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
 )

后同上

roscore
source ./devel/setup.bash
rosrun helloworld helloworld_p.py

5.配置开发环境

sudo apt install terminator 使用可分布终端

ctrl+alt+t打开终端

安装VScode或者 sublime text

需要安装C/C++扩展,python,ROS,chinese simple扩展包

创建文件时可以用

code .

在终端中用vscode打开文件

用ctrl+shift_B打开 catkin_make:build生成文件

可以用touch .vscode/tasks.json 添加缺少的文件:

{
// 有关 tasks.json 格式的文档,请参见  可以用ctrl+shift+B直接进行编译
    // https://go.microsoft.com/fwlink/?LinkId=733558
    "version": "2.0.0",
    "tasks": [
        {
            "label": "catkin_make:debug", //代表提示的描述性信息
            "type": "shell",  //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
            "command": "catkin_make",//这个是我们需要运行的命令
            "args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
            "group": {"kind":"build","isDefault":true},   
            "presentation": {
                "reveal": "always"//可选always或者silence,代表是否输出信息
            },
            "problemMatcher": "$msCompile"
        }
    ]
}

6.launch文件

roslaunch 包名   节点名字

6.1  包名下创建launch文件夹和  .launch文件

【依然要添加环境变量】

执行:

roslaunch  hello_world start_turtlesim.launch 

代码规则:

<launch>

<node pkg= "turtlesim"  type= "turtlesim_node"    name = "turtlesim_GUI"/>
<node pkg= "turtlesim"  type= "turtle_teleop_key" name= "turtlesim_key"/>
<node pkg="hello_world" type= "hello_vscode_c"    name = "show hello" output="screen"/>

</launch>

目录参考为:

上图 

7.ROS架构

查看计算图                                rosrun rqt_graph rqt_graph

8.ROS通信机制

ros是进程(Nodes)的分布式框架

三种通信策略:

          *话题通信(发布订阅模式)

          *服务通信(请求响应模式)

          *参数服务器(参数共享模式)

8.1发布实现C++:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>                  //拼接字符串

int main(int  argc, char  * argv[])
{
    //初始化ros节点
    ros::init(argc,argv,"erGouZi");
    //创建节点句柄
    ros::NodeHandle nh;
    //创建发布者对象
    ros::Publisher pub= nh.advertise<std_msgs::String>("House",10);

    
     //发布消息和循环发布数据
    std_msgs::String msg;
    //设置发布频率
    ros::Rate rate(10);

    int count=0;

    while(ros::ok())
    {
        //msg.data="hello";

        count++;
        std::stringstream   ss;
        ss  <<  "hello  No."  <<  count;
        msg.data=ss.str();

        pub.publish(msg);


        ROS_INFO("Publish data is :%s",ss.str()_.c_str());
    //频率等待
        rate.sleep();

    }

    return 0;
}

可通过            rostopic 话题名字  echo           获得话题信息

8.2.订阅话题C++
#include "ros/ros.h"
#include "std_msgs/String.h"

//回调函数
void doMessage(const std_msgs::String::ConstPtr &msg)
{

    ROS_INFO("Cuihua Subscribered data is : %s",msg->data.c_str());
}


int main(int argc,char ** argv)
{

    //初始化节点名称必须不同
    //为ROS Master中唯一的,网络拓扑名称
    ros::init(argc,argv,"CuiHua");
    //实例化节点
    ros::NodeHandle nh;
   
    ros::Subscriber sub=nh.subscribe("House",10,doMessage);
    ros::spin();      //back to callback function

    





    return 0;
}

发布者也可以通过: ros::Duration(3).sleep();实现短暂延时,防止注册未完成的情况

8.3 发布实现 Python:
#!  /usr/bin/env python

import rospy
from std_msgs.msg import String



if __name__ == "__main__":
    rospy.init_node("Tom")
    pub=rospy.Publisher("Car",String,queue_size=10)
    msg=String()
    rate = rospy.Rate(1)
    count = 0
    while not rospy.is_shutdown():
        count +=1
        msg.data="hello"+str(count)
        pub.publish(msg)
        rospy.loginfo("publish by pytho is %s",msg.data)
        rate.sleep()
    pass
8.4 订阅话题 Python
#! /usr/bin/env python

import rospy
from std_msgs.msg import String


def doMessage(msg):
    rospy.loginfo("my subscribed data is %s ",msg.data)


if __name__ == "__main__":
    rospy.init_node("Jerry")
    sub = rospy.Subscriber("Car",String,doMessage,queue_size=10)
    rospy.spin()
8.5 自定义话题msgs
8.5.1 常用字段类型:

* int8   int16   int32  int64   

*float32   float64

*string

*time   duration

*other msg files

*variable_length array[]    fixed-length array[C]

8.5.2 创建流程

包下创建 msg文件以及.msg结尾的文件,定义消息类型,如Person.msg

string name
int32 age
float32 height

修改添加package.xml文件下  build_depend  和exec_depend:

<build_depend>message_generation</build_depend>

 <exec_depend>message_runtime</exec_depend>

修改CMakeLists.txt文件:

find_package下添加:  message_generation

add_message_files添加内容:

add_message_files(
  FILES
  Person.msg
 
)

以及generate_messages字段的注释释放:

以及catkin_package下放开CATKIN_DEPENDS coscpp rospy std_msgs........并添加:message_runtime

编译以后可以在  include 和lib中找到Person信息类

并设置c_cpp_properties.json设置include文件

8.5.3  C++订阅使用

#include <ros/ros.h>
#include "plumbing_pub_sub/Person.h"

int main(int argc, char ** argv)
{

    ros::init(argc,argv,"Teacher");

    ros::NodeHandle nh;

    ros::Publisher pub=nh.advertise<plumbing_pub_sub::Person>("CheckStudents",10);

    ros::Rate rate(1);

    plumbing_pub_sub::Person person;
    person.name="LZF";
    person.age=99;
    person.height=1.99;
    while(ros::ok())
    {
        pub.publish(person);
        ROS_INFO("pubed info is:%s,%d,%.02f",person.name.c_str(),person.age,person.height);

        person.age++;
        rate.sleep();
        ros::spinOnce();        //suggest

    }
    
    return 0;
}

修改CMakeLists文件需要设置:

add_dependencies(demo02_def_pub   ${PROJECT_NAME}_generate_messages_cpp)

编译依赖,使得编译有先后顺序

编译时用rostopic设置,需要添加环境路径

8.5.4.  订阅C++使用
#include <ros/ros.h>
#include "plumbing_pub_sub/Person.h"

void whatIHeard(const plumbing_pub_sub::Person::ConstPtr & msg)
{
ROS_INFO("subed news is : %s,%d,%.6f",msg->name.c_str(),msg->age,msg->height);


}

int main(int argc,char** argv)
{

ros::init(argc,argv,"StuA");

ros::NodeHandle nh;
ros::Subscriber sub=nh.subscribe("CheckStudents",10,whatIHeard);
ros::spin();
return 0;
}

配置同上

8.5.5  发布Python实现:

设置settings.json文件,添加Person信息类路径(第三行):

    "python.analysis.extraPaths": [
        "/home/lzf20u/Ros_Prj/P1/devel/lib/python3/dist-packages",
        "/opt/ros/noetic/lib/python3/dist-packages",
        "/home/lzf20u/Ros_Prj/P4_Learning_Ros_2_pub_sub/devel/lib/python3/dist-packages"
    ]
#!  /usr/bin/env python

import rospy
from plumbing_pub_sub.msg import  Person

if __name__ == "__main__":
    rospy.init_node("OldMan")
    pub=rospy.Publisher("Chat",Person,queue_size=10);
    p = Person()
    p.name="jack"
    p.age=10
    p.height=1.82
    rate=rospy.Rate(1)
    while not rospy.is_shutdown():
        pub.publish(p)
        rospy.loginfo("pub news is %s,%d,%f",p.name,p.age,p.height)
        rate.sleep()
    pass
同上
8.5.6 订阅Python实现
#!  /usr/bin/env python

import rospy
from plumbing_pub_sub.msg import Person

def doPerson(p):
    rospy.loginfo("hear info is:%s,%d,%f",p.name,p.age,p.height)

if __name__ == "__main__":
    rospy.init_node("HearA")
    sub=rospy.Subscriber("Chat",Person,doPerson)
    rospy.spin()

8.6 服务通信模型

在包下创建srv文件夹以及srv文件,如AddInts.srv,设置服务消息类型:

#客户端要请求的数据
int32 num1
int32 num2
---

#要发送的数据
int32 sum
配置package.xml文件:

 <build_depend>message_generation</build_depend>
 <exec_depend>message_runtime</exec_depend>

配置CMakeLists.txt文件:

find_package添加message_generation

以及:

add_service_files(
  FILES
  AddInts.srv
)

放开注释:

generate_messages(
  DEPENDENCIES
  std_msgs  
)

取消注释,添加messsage_runtime:

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES plumbing_server_client
  CATKIN_DEPENDS roscpp rospy std_msgs   message_runtime
#  DEPENDS system_lib
)

进行编译----

8.6.1.服务端实现:

对c_cpp_properties.json导入path  的devel下include文件:

#include  <ros/ros.h>
#include "plumbing_server_client/AddInts.h"

bool doNums(plumbing_server_client::AddInts::Request &request,
plumbing_server_client::AddInts::Response &response)
{
    // 接收数据
    int num1= request.num1;
    int num2= request.num2;
    ROS_INFO("Received request data is %d , %d ",num1,num2);

    /  设置返回数据
    int sum=num1+num2;
    response.sum=sum;

    //
    return true;
}
int main(int argc ,char ** argv)
{
//初始化节点和句柄,注册服务
    ros::init(argc,argv,"Company");
    ros::NodeHandle nh;
    ros::ServiceServer server=nh.advertiseService("addInts",doNums);
    ros::spin();
    return 0;
}

设置CMakeLists.txt:

add_dependencies(demo01_server ${PROJECT_NAME}_gencpp)

target_link_libraries(demo01_server
  ${catkin_LIBRARIES}
)

 add_executable(demo01_server  src/demo01_server.cpp)

可以通过:rosservice call addInts "num1: 9  num2: 5"       发送请求询问

8.6.2客户端实现
#include <ros/ros.h>
#include <plumbing_server_client/AddInts.h>

int  main(int argc , char ** argv)
{
    ros::init(argc, argv,"client");
    ros::NodeHandle nh;

    //订阅服务话题
    ros::ServiceClient client = nh.serviceClient<plumbing_server_client::AddInts>("addInts");

    plumbing_server_client::AddInts ai;
    ai.request.num1=10;
    ai.request.num2=99;
//发起请求并响应
     bool flag  =  client.call(ai);

    if(flag)
    {
        ROS_INFO("SUCCESS, SUM= %d",ai.response.sum);

    }


    return 0;
}

动态输入:

#include <ros/ros.h>
#include <plumbing_server_client/AddInts.h>

int  main(int argc , char ** argv)
{

    if(argc!=3)
    {
        ROS_INFO("INPUT ERROR");
        return 1;
    }


    ros::init(argc, argv,"client");
    ros::NodeHandle nh;
    ros::ServiceClient client = nh.serviceClient<plumbing_server_client::AddInts>("addInts");

    plumbing_server_client::AddInts ai;
    //ai.request.num1=10;
    //ai.request.num2=99;
    ai.request.num1=atoi(argv[1]); 
    ai.request.num2= atoi(argv[2]) ;
    //等待服务开始函数
     client.waitForExistence();
     ros::service::waitForService("addInts");
     bool flag  =  client.call(ai);

    if(flag)
    {
        ROS_INFO("SUCCESS, SUM= %d",ai.response.sum);

    }


    return 0;
}
8.6.3 Python服务端实现
#!  /usr/bin/env python

import rospy
#from plumbing_server_client.srv import AddInts,AddIntsRequest,AddIntsResponse
from plumbing_server_client.srv import *
def answer(request):
    num1=request.num1
    num2=request.num2

    sum=num1+num2
    rospy.loginfo("get data num1=%d,num2=%d,sum=%d",num1,num2,sum)
    response=AddIntsResponse()
    response.sum=sum

    return response

if __name__ == "__main__":
    rospy.init_node("Company")
    server = rospy.Service("addInts",AddInts,answer)
    rospy.loginfo("server begin work")
    rospy.spin()
    pass

可以通过:rosservice call addInts "num1: 0  num2: 5"  发起话题请求

8.6.4  Python客户端实现:
#!  /usr/bin/env python

import rospy
from plumbing_server_client.srv import *


if __name__ == "__main__":
    rospy.init_node("Client")
    client=rospy.ServiceProxy("addInts",AddInts)
    response = client.call(12,5)
    rospy.loginfo("answered data is %d ",response.sum)
    pass

 优化:

#!  /usr/bin/env python

import rospy
from plumbing_server_client.srv import *
import sys

if __name__ == "__main__":
    if(len(sys.argv) != 3:
        rospy.loginfo("input error")
        sys.exit(1)

    num1=  int(sys.argv[1])
    num2=  int(sys.argv[2])

    rospy.init_node("Client")
    client=rospy.ServiceProxy("addInts",AddInts)
    #response = client.call(12,5)
    client.wait_for_service()
    #or rospy.wait_for_service("addInts")

    response = client.call(num1,num2)
    rospy.loginfo("answered data is %d ",response.sum)
    pass

8.7  参数服务器模型

可使用数据类型:

32-bit integers

boleans 

strings

doubles

iso8601 dates

lists

base64-encoded binary data

字典

8.7.1  参数操作 C++     新增加/修改



代码

#include "ros/ros.h"
/*  ros::NodeHandle
        setParam()
    ros::param
        set()

*/

int main(int argc, char ** argv)
{

    
    ros::init(argc,argv,"set_param_c");
    ros::NodeHandle nh;
    //plan A;
    nh.setParam("type","book");
    nh.setParam("Distance",11);

    //Plan B
    ros::param::set("type_param","tom");
    ros::param::set("radius_param",0.15);
    return 0;
}

rosparam list  

和:

rosparam get /Distance可以从服务器查看相关记载数据  

运行但不调试

8.7.2  参数操作  C++ 查询:
#include "ros/ros.h"
/*
    ros::NodeHandle

        param(键,默认值) 
            存在,返回对应结果,否则返回默认值

        getParam(键,存储结果的变量)
            存在,返回 true,且将值赋值给参数2
            若果键不存在,那么返回值为 false,且不为参数2赋值

        getParamCached键,存储结果的变量)--提高变量获取效率
            存在,返回 true,且将值赋值给参数2
            若果键不存在,那么返回值为 false,且不为参数2赋值

        getParamNames(std::vector<std::string>)
            获取所有的键,并存储在参数 vector 中 

        hasParam(键)
            是否包含某个键,存在返回 true,否则返回 false

        searchParam(参数1,参数2)
            搜索键,参数1是被搜索的键,参数2存储搜索结果的变量

    ros::param ----- 与 NodeHandle 类似
*/

int main(int argc, char ** argv)
{
    ros::init(argc,argv,"get_param");
    ros::NodeHandle nh;
    //1.param   
    float Distance= nh.param("Distance",0.5); 
    ROS_INFO("Distance = %.2f ",Distance);
    //2.getParam
    double result;
    bool flag1 =nh.getParam("Distance",result);
    if(flag1)
    {
        ROS_INFO("distance equals  %f: ",result);
    }
    else
    {
        ROS_INFO("get error");
    }
    //3. getParamCached
    float result2;
    bool flag2=nh.getParamCached("Distance",result2);
    //4.getParamNames(std::vector<std::string>)
    std::vector<std::string>  names;
    nh.getParamNames(names); 
    for (auto &&name : names)
        {
            ROS_INFO("readed name is %s",name.c_str());
        }
    //5.hasParam
    bool flag3=nh.hasParam("Distance");
    bool flag4 = nh.hasParam("diss");

    //6.searchParam
        std::string keyName;
        nh.searchParam("Distance",keyName);
        

    return 0;
}

对于param可以用  ros::param::....来实现,不再赘述

8.7.3 参数操作  Python 

添加

#! /usr/bin/env python

import rospy
"""rospy.set_param()
"""


if __name__ == "__main__":
    rospy.init_node("param_set_p")
    #add
    rospy.set_param("type_p","pythonLanguage")
    rospy.set_param("Distance_p",88.8)
    #change
    rospy.set_param("Distance_p",99.9)

    pass

获取

#! /usr/bin/env python

import rospy

"""
get_paam_cached
get_param_names
has_param
search_param
"""


if __name__ == "__main__":
    rospy.init_node("get_param_p")
    Distance = rospy.get_param("Distance_p",0)

    #
    Distance2=rospy.get_param_cached("Distance",0.5)
    #
    names=rospy.get_param_names()
    for name in names:
        rospy.loginfo("names = %s",name)
    #
    flag2=rospy.has_param("Distance")
    #
    key = rospy.search_param("Distance")
    pass

删除

#! /usr/bin/env python

import rospy



if __name__ == "__name__" :
    rospy.init_node("del_param_p")

    try:
        rospy.delete_param("Distance")
    except Exception as e:
        rospy.loginfo("doesn't exist")

9.常用命令

rosnode

rostopic 

rosservice

rosmsg

rossrv

rosparam

9.1 rosnode     ping   / list/info   /machine    /kill    /cleanup
9.2 rostopic     bw/delay/echo find/hz/info/lsit/pub/type

注意与示例:rostopic pub 话题名  信息类型  信息  ------可以临时发布话题

rostopic up  -r  频率  话题  信息类型  信息

9.3 rosservice    args/info/call/list/type/uri

注意与示例:rosservice call 服务名  参数

9.4 rosmsg   show/info/list/md5/package/packages

rosmsg list |frep -i person

9.5 rossrv    show/list/info/md5/package/packages

9.6 rosparam  set/get /load/dump/delete/list

10.通信机制实操

记录:要求实现小乌龟运动,圆周的运动

姿态订阅:《添加turtlesim>包  -》xml文件

#include "ros/ros.h"
#include "turtlesim/Pose.h"


void doPose(const turtlesim::Pose::ConstPtr &pose)
{
    ROS_INFO("location is:%.2f,%.2f(x,y),forward %.2f,liner speed :%.2f,angel speed %.2f",
    pose->x,pose->y,pose->theta,pose->linear_velocity,pose->angular_velocity);


}


int main(int argc, char ** argv)
{



    ros::init(argc,argv,"poseSubscriberA");
    ros::NodeHandle nh;
    ros::Subscriber sub=nh.subscribe("/turtle1/pose",100,doPose);
    ros::spin();
    return 0;
}

发布位移:

#include "ros/ros.h"
#include "geometry_msgs/Twist.h"

/*
    public to ctrl         
    topic: turtle/cmd_vel
    news:   geometry_msgs/Twist           
*/



int main(int argc, char ** argv)
{
    ros::init(argc,argv,"myctrl_pub");
    ros::NodeHandle  nh;
    ros::Publisher pub=nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);
    ros::Rate rate(10);
    geometry_msgs::Twist news;
    news.angular.z=10;
    news.linear.x=20;
    int i=0;
    while(ros::ok())
    {
        pub.publish(news);
        rate.sleep();
        ros::spinOnce();
        i++;
        if(i==100)
        {
            news.angular.z*=-1;
            i=1;
        }
    }

    return 0;
}

13.Launch文件解析

13.1  launch标头属性   

deprecated = "已经放弃,建议用。。。"

13.2 node标签属性:

pkg

type

name:在ROS网络中的拓扑名称

args = "xxx xxx xxx"

machine="指定运行的机器”

respawn="true |false"   如果节点退出是否重新启动

respawn_delay=“N"  延时启动

required="true | false"  是否必须,如果true,如果该节点退出,将杀死整个roslaunch

ns="xxx"   在指定命名空间中启动节点

clear_param="true | false"   启动前删除节点私有空间的所有参数

output="log | screen" 是否日志输出

13.2 include 
将另一个xml格式的launch文件导入当前文件

属性:

file="$(find 包名)/launch/xxx.launch   无空格

ns=”指定命名空间导入"        可选

标签:

env:环境变量设置

arg :  参数传递给被包含的文件

13.3  remap话题重新命名

from ="xxx   

to  =  "xxx"

如:<node pkg=""   type ="  "  name = " "  <remap from="" to=”“/> />

13.4  param  服务器添加参数

name="命名空间/参数名”     value="xxx"    type="str |int |double |yaml|bool"

<param  name="param_A" type="int"   value="100"/>

可以在node里面,也可以在node外:


<node  pkg="turtlesim"   type="turtle_teleop_key"   name="turtlekey"  output="screen">
<param  name="param_B" type="int"   value="10"/>
</node>

13.5 rosparam 从yaml文件导入参数,或将参数导入到yaml文件

<rospaam>在<node>标签中被视为私有

属性:

command = "load | dump |delete"

file="$(find xxxx)///xxx/yyyy..."

param="参数名称“

ns="命名空间“

例如:

<rosparam command="load"   file="$(find launch1)/launch/param.yaml />

13.6  group标签   使节点归属为某个命名空间

属性:

ns="命名空间”

clear_params= "true |false"

13.7  arg参数

属性:

name="参数名称“

default="默认值”

value="数值“

doc="描述”

例如:

<arg name="car_width"  default="0.5"/>

<param name="A"      value="$(arg car_width)" />

<param name="B"      value="$(arg car_width)" />

<param name="C"      value="$(arg car_width)" />

并可以通过命令行  传参

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值