锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

ROS_learn

时间:2023-01-24 06:30:00 g3高频电连接器

‘1.ros环境搭建’

python:

1.测试ros:roscore—rosrun turtlesim turtlesim_node—rosrun turtlesim turtle_teleop_key
2.创造工作空间并初始化:
makedir -p demo_ws/src
cd demo_ws
catkin_make#进入工作空间进行编译(cd demo03_ws–>code .启动vscode)
cd src
catkin_create_pkg helloworld roscpp rospy std_msgs
#helloworld是包名,roscpp rospy std_msgs分别对应使用c 的库,python库,标准消息库
#c 库运行效率高,开发效率低,python库反之
mkdir scripts /helloworld
cd scripts
gedit helloworld.py
编辑在helloworld下的CamkeList.txt 文件
cd demo_ws
catkin_make
source ./devel/setup.bash
rosrun 包名 自定义文件名.py
‘’‘source ~/工作空间//工作空间//工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作devel/setup.bash可直接添加.bashrc文件
方法一:使用gedit编辑.bashrc文件,最后添加内容)(ctrl h找到.bashrc,这样,每次文件可以打开一个新的终端,它仍然可以执行rosrun helloworld helloworld.py)
方法二:echo “source ~/工作空间//工作空间//工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作空间/工作devel/setup.bash” >> ~.bashrc’‘’

c :

mkdir -p cpp_ws/src
cd cpp_ws
catkin_make
cd src
catkin_create_pkg demo01 roscpp std_msgs
cd demo01/src
touch helloworld.cpp
#include “ros/ros.h” // 这里必须使用双引号而不是单引号,c 了解单双引号

int main(int argc, char *argv[]) {     ros::init(argc,argv,"helloworld_node");      ROS_INFO("hello world!");     return 0;  } 

修改cmake文件:
add_executable(hello src/helloworld.cpp)#被映射名 可通过映射名hello映射到helloworld.cpp文件
target_link_libraries(hello#目标链接库,名称改为上述映射名
${catkin_LIBRARIES}
)

3.写脚本#可以是/demo01_ws/src/helloworld/下直接用gedit helloworld.py
#!/usr/bin/env python
##指定解释器
#1.导包
import rospy
#2.编写入口
if name==‘main’:
rospy.init_node(‘hello_p’)
#3.初始化ros节点
rospy.loginfo(‘hello world’)
#4.输入日志

4.增加可执行权限:cd ~/demo01_ws/src/hellowold/ — chmod x helloworld.py##利用ll检查是否有可执行权限
一般文件树:
demo01_ws
|
├── build

├── devel
│ ├── cmake.lock
│ ├── env.sh
│ ├── lib
│ ├── local_setup.bash
│ ├── local_setup.sh
│ ├── local_setup.zsh
│ ├── setup.bash#生效文件
│ ├── setup.sh
│ ├── _setup_util.py
│ └── setup.zsh
└── src
├── ~.bashrc
├── CMakeLists.txt -> /opt/ros/noetic/share/catkin/cmake/toplevel.cmake
└── helloworld
├── CMakeLists.txt
├── include
│ └── helloworld
├── package.xml
└── src
└── helloworld.py
5.编辑配置文件:CMakeLists.txt##此步骤的目的是让noetic下可接入python3
mkdir /demo01_ws/src/hellowold/scripts#在helloworld在文件中添加脚本文件夹,这一步不能忘记
gedit hellowold.py—>增加可执行权限
编辑配置文件:

########################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################

Install

########################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################

all install targets should use catkin DESTINATION variables

See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html

Mark executable scripts (Python etc.) for installation

in contrast to setup.py, you can choose the destination

catkin_install_python(PROGRAMS

scripts/my_python_script

DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}

)

|
|
v

Mark executable scripts (Python etc.) for installation

in contrast to setup.py, you can choose the destination

catkin_install_python(PROGRAMS
scripts/helloworld.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

cd demo01_ws
catkin_make
##此处bug:
‘’‘find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs#s不要掉下来,否则编译失败了
)’‘’
source ./devel/setup.bash#刷新环境变量
rosrun helloworld helloworld.py##第一个helloworld是包名,二是脚本

6.综合开发环境:
terminator终端配置https://blog.csdn.net/weixin_42369926/article/details/99712378

下载terminator      sudo apt-get update     sudo apt-get install terminator  新建terminator配置文件      mkdir ~/.config/terminator     vim ~/.config/terminator/config  配置terminator      [global_config]       geometry_hinting = False       handle_size = 1       inactive_color_offset =1.0
      title_font = mry_KacstQurn Bold 11
      title_hide_sizetext = True
    [keybindings]
    [layouts]
      [[default]]
        [[[child1]]]
          parent = window0
          profile = default
          type = Terminal
        [[[window0]]]
          parent = ""
          type = Window
    [plugins]
    [profiles]
      [[default]]
        background_darkness = 0.49
        background_image = '背景图片路径'
        background_type = transparent
        cursor_color = "#3036ec"
        custom_command = tmux
        font = Ubuntu Mono 13
        foreground_color = "#ffffff"
        login_shell = True
        scroll_background = False
        show_titlebar = False
        use_system_font = False

terminator常用快捷方式
序号  快捷键 功能
1   Ctrl+Shift+O    水平分割终端
2   Ctrl+Shift+E    垂直分割终端
3   Ctrl+Shift+F    搜索
4   Ctrl+Shift+C    复制
5   Ctrl+Shift+V    粘贴
6   Ctrl+Shift+W    关闭当前终端
7   Ctrl+Shift+Q    退出当前窗口
8   Ctrl+Shift+T    打开终端
9   Ctrl+Shift+X    切换显示当前窗口
10  F11 全屏状态
11  Ctrl+Shift+G    clear屏幕
12  Ctrl+Shift+Right    在垂直分割的终端中将分割条向右移动
13  Ctrl+Shift+Left 在垂直分割的终端中将分割条向左移动
14  Ctrl+Shift+S    隐藏/显示滚动条

7.当mv,rm,mkdir,touch,cp,等权限不够时可加sudo

sudo cp -rf VSCode-linux-x64 /opt

#sudo rm -r VSCode-linux-x64/强制删除
#sudo chmod 777 Python.sublime-package (最高权限)
#rm -r dir
8.如何下载vscode及其配置:
Ctrl+Shift+P, F1
打开命令面板

Ctrl+p    
快速打开文件

Ctrl+Shift+N     
打开新窗口/实例

Ctrl+Shift+W    
关闭窗口/实例

基础编辑

Ctrl+X      
剪切当前行

Ctrl+C    
复制当前行

Alt+ ↑ / ↓    
向上/向下移动当前行

Shift+Alt + ↓ / ↑    
向上/向下复制当前行

Ctrl+Shift+K   
删除当前行

Ctrl+Enter    
在当前行以下插入

Ctrl+Shift+Enter    
在当前行以上插入

Ctrl+Shift+\      
跳转到匹配的括号

Ctrl+] / [    
缩进/取消缩进

Home     
转到行首

End     
转到行尾

Ctrl+Home    
转到页首

Ctrl+End     
转到页尾

Ctrl+↑ / ↓   
向上/向下滚动

Alt+PgUp / PgDown
向上/向下翻页

Ctrl+Shift+[ 
折叠当前代码块

Ctrl+Shift+]
展开当前代码块

Ctrl+K Ctrl+[  
折叠所有子代码块

Ctrl+K Ctrl+]
展开所有子代码块

Ctrl+K Ctrl+0
折叠所有代码块

Ctrl+K Ctrl+J   
展开所有代码块

Ctrl+K Ctrl+C  
添加行注释

Ctrl+K Ctrl+U
删除行注释

Ctrl+/   
添加/删除行注释

Shift+Alt+A 
添加/删除块注释

Alt+Z  
自动换行

导航

Ctrl+T  
显示所有符号

Ctrl+G
跳转到行

Ctrl+P    
跳转到文件

Ctrl+Shift+O      
跳转到符号

Ctrl+Shift+M  
显示问题面板

F8 
跳转到下一个问题或警告

Shift+F8
跳转到前一个问题或警告

Ctrl+Shift+Tab
显示编辑器文件历史

Alt+ ← / →
向后/向前查看文件

Ctrl+M
开启/关闭 Tab 移动焦点

搜索和替换
Ctrl+F
查找

Ctrl+H
替换

F3 / Shift+F3
查找下一个/前一个

Alt+Enter  
选择所有匹配项

Ctrl+D   
选择下一个匹配项

Ctrl+K Ctrl+D
跳过当前选择项

Alt+C / R / W
切换大小写敏感/正则表达式/全词

多光标与选择
Alt+Click
插入光标

Ctrl+Alt+ ↑ / ↓
向上/向下插入光标

Ctrl+U 
撤销上一个光标

Shift+Alt+I
在选中行的行尾插入光标

Ctrl+I
选择当前行

Ctrl+Shift+L
选择当前选中项的所有匹配项

Ctrl+F2
选择当前单词的所有匹配项

Shift+Alt+→  
扩展选择

Shift+Alt+←
缩小选择

Shift+Alt + (drag mouse)
列(框)选择

Ctrl+Shift+Alt + (arrow key)
列(框)选择

Ctrl+Shift+Alt +PgUp/PgDown

向上页/下页列(框)选择
2、自定义快捷键:(以下代码表示方向键可以自定义)
// Place your key bindings in this file to overwrite the defaults
// alt + i, j, k,l
[{
“key”: “alt+j”,
“command”: “cursorLeft”
},
{
“key”: "alt+j ",
“command”: “list.collapse”,
“when”: “listFocus”
},
{
“key”: “alt+k”,
“command”: “cursorDown”
},
{
“key”: “alt+k”,
“command”: “repl.action.historyNext”,
“when”: “editorTextFocus && inDebugRepl && onLastDebugReplLine”
}, {
“key”: “alt+k”,
“command”: “settings.action.focusSettingsFile”,
“when”: “inSettingsSearch”
}, {
“key”: “alt+k”,
“command”: “showNextParameterHint”,
“when”: “editorTextFocus && parameterHintsMultipleSignatures && parameterHintsVisible”
}, {
“key”: “alt+k”,
“command”: “selectNextSuggestion”,
“when”: “editorTextFocus && suggestWidgetMultipleSuggestions && suggestWidgetVisible”
}, {
“key”: “alt+k”,
“command”: “keybindings.editor.focusKeybindings”,
“when”: “inKeybindings && inKeybindingsSearch”
}, {
“key”: “alt+k”,
“command”: “keybindings.editor.focusKeybindings”,
“when”: “inKeybindings && inKeybindingsSearch”
}, {
“key”: “alt+k”,
“command”: “search.focus.nextInputBox”,
“when”: “inputBoxFocus && searchViewletVisible”
}, {
“key”: “alt+k”,
“command”: “workbench.action.interactivePlayground.arrowDown”,
“when”: “interactivePlaygroundFocus && !editorTextFocus”
},
{
“key”: “alt+l”,
“command”: “cursorRight”
},
{
“key”: “alt+l”,
“command”: “repl.action.acceptSuggestion”,
“when”: “editorTextFocus && inDebugRepl && suggestWidgetVisible”
}, {
“key”: “alt+l”,
“command”: “list.expand”,
“when”: “listFocus”
},
{
“key”: “alt+i”,
“command”: “cursorUp”
},
{
“key”: “alt+i”,
“command”: “repl.action.historyPrevious”,
“when”: “editorTextFocus && inDebugRepl && onLastDebugReplLine”
}, {
“key”: “alt+i”,
“command”: “showPrevParameterHint”,
“when”: “editorTextFocus && parameterHintsMultipleSignatures && parameterHintsVisible”
}, {
“key”: “alt+i”,
“command”: “selectPrevSuggestion”,
“when”: “editorTextFocus && suggestWidgetMultipleSuggestions && suggestWidgetVisible”
},
{
“key”: “alt+i”,
“command”: “list.focusUp”,
“when”: “listFocus”
}, {
“key”: “alt+i”,
“command”: “search.action.focusSearchFromResults”,
“when”: “firstMatchFocus && searchViewletVisible”
}, {
“key”: “alt+i”,
“command”: “search.action.focusSearchFromResults”,
“when”: “firstMatchFocus && searchViewletVisible”
}, {
“key”: “alt+i”,
“command”: “workbench.action.interactivePlayground.arrowUp”,
“when”: “interactivePlaygroundFocus && !editorTextFocus”
}
]

9.用vscode开发ros:
mkdir demo01_ws/src
cd demo01_ws
catkin_make
cd demo01_ws
code .
在/demo01_ws/src下catkin_create_pkg helloworld rospy std_msgs
ctrl+shift+B 调用编译,选择catkin_make:build
修改.vscode/tasks.json:##以后此步骤可以执行,即可以打开task.json,但是不必要修改此文件,直接默认即可

{
// 有关 tasks.json 格式的文档,请参见
// 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”
}
]
}
在demo01_ws/src/hellowold/scripts下新建helloworld.py并添加可执行权限

写脚本:
#! /usr/bin/env python
“”"
Python 版本的 HelloVScode,执行在控制台输出 HelloVScode
实现:
1.导包
2.初始化 ROS 节点
3.日志输出 HelloWorld

“”"

import rospy # 1.导包

if name == “main”:

rospy.init_node("Hello_Vscode_p")  # 2.初始化 ROS 节点
rospy.loginfo("Hello VScode, 我是 Python ....")  #3.日志输出 HelloWorld

配置 CMakeLists.txt:
catkin_install_python(PROGRAMS scripts/自定义文件名.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

编译: ctrl + shift + B#实际上已经代替了catkin_make
激活:source ./devel/setup.bash
rosrun helloworld helloworld.py

10.用launch文件来控制输出:

1…需求

一个程序中可能需要启动多个节点,比如:ROS 内置的小乌龟案例,如果要控制乌龟运动,要启动多个窗口,分别启动 roscore、乌龟界面节点、键盘控制节点。如果每次都调用 rosrun 逐一启动,显然效率低下,如何优化?

官方给出的优化策略是使用 launch 文件,可以一次性启动多个 ROS 节点。
2.实现

选定功能包右击 ---> 添加 launch 文件夹

选定 launch 文件夹右击 ---> 添加 launch 文件

编辑 launch 文件内容


    
    
    
    
    
    



node ---> 包含的某个节点

pkg -----> 功能包

type ----> 被运行的节点文件

name --> 为节点命名

output-> 设置日志的输出目标

运行 launch 文件:roslaunch 包名 launch文件名

3.运行小乌龟:rosrun turtlesim turtlesim_node–>rosrun turtlesim turtle_teleop_key

11.ros架构:
demo01_ws
.
├── build
├── devel
│   ├── cmake.lock
│   ├── env.sh
│   ├── lib
│   ├── local_setup.bash
│   ├── local_setup.sh
│   ├── local_setup.zsh
│   ├── setup.bash
│   ├── setup.sh
│   ├── _setup_util.py
│   ├── setup.zsh
│   └── share
│   └── helloworld
│   └── cmake
│   ├── helloworldConfig.cmake
│   └── helloworldConfig-version.cmake
├── src
│   ├── CMakeLists.txt -> /opt/ros/noetic/share/catkin/cmake/toplevel.cmake
│   └── helloworld
│   ├── CMakeLists.txt
│   ├── include##h
│   │   └── helloworld
│   ├── launch##用于存放
.launch文件
│   │   └── start_turtle.launch
│   ├── package.xml
│   ├── scripts##.py和.sh
│   │   └── helloworld.py
│   └── src##用于存放*.cpp文件
│   └── helloworld.py
└──

12.ros的文件系统:
(可以在rosrun的时候点击2次tab键进行提示)
1.增

catkin_create_pkg 自定义包名 依赖包 === 创建新的ROS功能包

sudo apt install xxx === 安装 ROS功能包
2.删

sudo apt purge xxx ==== 删除某个功能包
3.查

rospack list === 列出所有功能包

rospack find 包名 === 查找某个功能包是否存在,如果存在返回安装路径

roscd 包名 === 进入某个功能包#可以直接进入某个功能包

rosls 包名 === 列出某个包下的文件

apt search xxx === 搜索某个功能包
#apt search noetic | grep -i gmapping(|后的东西是筛选出某些需要的包名)

4.改

rosed 包名 文件名 === 修改功能包文件

需要安装 vim

比如:rosed turtlesim Color.msg
5.执行
5.1roscore

roscore === 是 ROS 的系统先决条件节点和程序的集合, 必须运行 roscore 才能使 ROS 节点进行通信。

roscore 将启动:

    ros master

    ros 参数服务器

    rosout 日志节点

用法:

roscore

或(指定端口号)

roscore -p xxxx

5.2rosrun

rosrun 包名 可执行文件名 === 运行指定的ROS节点

比如:rosrun turtlesim turtlesim_node
5.3roslaunch

roslaunch 包名 launch文件名 === 执行某个包下的 launch 文件

13.ros计算图

1.计算图简介

前面介绍的是ROS文件结构,是磁盘上 ROS 程序的存储结构,是静态的,而 ros 程序运行之后,不同的节点之间是错综复杂的,ROS 中提供了一个实用的工具:rqt_graph。

rqt_graph能够创建一个显示当前系统运行情况的动态图形。ROS 分布式系统中不同进程需要进行数据交互,计算图可以以点对点的网络形式表现数据交互过程。rqt_graph是rqt程序包中的一部分。

2.计算图演示

接下来以 ROS 内置的小乌龟案例来演示计算图

首先,按照前面所示,运行案例

然后,启动新终端,键入: rqt_graph 或 rosrun rqt_graph rqt_graph,可以看到类似下图的网络拓扑图,该图可以显示不同节点之间的关系。

方法一:使用roslaunch启用多个节点

!!!要用roslaunch启动launch文件,不能用rosrun

roslaunch helloworld start_turtle






方法二:用rosrun rqt_graph rqt_graph

.若是出现如下问题
ERROR: cannot launch node of type [pub_sub/pub]: Cannot locate node of type [pub] in package [pub_sub]. Make sure file exists in package path and permission is set to executable (chmod +x)
ERROR: cannot launch node of type [pub_sub/sub]: Cannot locate node of type [sub] in package [pub_sub]. Make sure file exists in package path and permission is set to executable (chmod +x)

要添加可执行权限

‘2.ros通信机制’

机器人是一种高度复杂的系统性实现,在机器人上可能集成各种传感器(雷达、摄像头、GPS…)以及运动控制实现,为了解耦合,在ROS中每一个功能点都是一个单独的进程,每一个进程都是独立运行的。更确切的讲,ROS是进程(也称为Nodes)的分布式框架。 因为这些进程甚至还可分布于不同主机,不同主机协同工作,从而分散计算压力。不过随之也有一个问题: 不同的进程是如何通信的?
也即不同进程间如何实现数据交换的?在此我们就需要介绍一下ROS中的通信机制了。

ROS 中的基本通信机制主要有如下三种实现策略:

话题通信(发布订阅模式):关注--->订阅

服务通信(请求响应模式):server--->client#先通过client发布请求,然后server再响应
                          <---

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

本章的主要内容就是是介绍各个通信机制的应用场景、理论模型、代码实现以及相关操作命令。本章预期达成学习目标如下:

能够熟练介绍ROS中常用的通信机制
能够理解ROS中每种通信机制的理论模型
能够以代码的方式实现各种通信机制对应的案例
能够熟练使用ROS中的一些操作命令
能够独立完成相关实操案例

1.话题通信

话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。话题通信的应用场景也极其广泛,比如下面一个常见场景:

机器人在执行导航功能,使用的传感器是激光雷达,机器人会采集激光雷达感知到的信息并计算,然后生成运动控制信息驱动机器人底盘运动。

在上述场景中,就不止一次使用到了话题通信。

以激光雷达信息的采集处理为例,在 ROS 中有一个节点需要时时的发布当前雷达采集到的数据,导航模块中也有节点会订阅并解析雷达数据。
再以运动消息的发布为例,导航模块会根据传感器采集的数据时时的计算出运动控制信息并发布给底盘,底盘也可以有一个节点订阅运动信息并最终转换成控制电机的脉冲信号。

以此类推,像雷达、摄像头、GPS… 等等一些传感器数据的采集,也都是使用了话题通信,换言之,话题通信适用于不断更新的数据传输相关的应用场景。
概念

以发布订阅的方式实现不同节点之间数据交互的通信模式。
作用

用于不断更新的、少逻辑处理的数据传输场景。

话题通信实现模型是比较复杂的,该模型如下图所示,该模型中涉及到三个角色:

ROS Master (管理者) 
Talker (发布者)
Listener (订阅者)  
    

    (0)advertise('bar',foo:1234)             ---------------------
    |--------------- ----------------------->|    ROS Master      |
    |               |                        |        (媒婆)       |
    |               |<-----xml/rpc---         --------------------
    |                        |       |      (2){foo:1234}|   A 
    |                        |       |------------------>|   |(1)subscribe('bar')
    |                        |                           |   |
    |                        |                           |   |
    |                        V                           |   |

------------------ (3)connect(‘scan’,tcp) V
|Talker |<------------------------- ---------------
|xml/rpc:foo:1234 |--------------------------> | Listener |
|tcp data:foo:2345| (4)tcp server:foo:2345 | (翠花) |
|(二狗子) | | |
| | | |
| | | |
| | (5)connect(‘foo’,2345) | |
| |<------------------------- | |
| |--------------------------> | |
| | (4)data messages:<-----tcp| |
| | ----------------

注解:rpc相当于远程控制,相当于手机号;tcp相当于微信
过程:
(0).狗子提交个人信息(房)—手机号
(1).翠花提交个人信息话题(房)
(2).把狗子的电话发送给翠花
(3).翠花打电话给狗子
(4).狗子响应(加微信)
(5)翠花通过tcp访问狗子(相当于加微信)
(6)发布消息

ROS Master 负责保管 Talker 和 Listener 注册的信息,并匹配话题相同的 Talker 与 Listener,帮助 Talker 与 Listener 建立连接,连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅。

整个流程由以下步骤实现:
0.Talker注册

Talker启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含所发布消息的话题名称。ROS Master 会将节点的注册信息加入到注册表中。
1.Listener注册

Listener启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要订阅消息的话题名。ROS Master 会将节点的注册信息加入到注册表中。
2.ROS Master实现信息匹配

ROS Master 会根据注册表中的信息匹配Talker 和 Listener,并通过 RPC 向 Listener 发送 Talker 的 RPC 地址信息。
3.Listener向Talker发送请求

Listener 根据接收到的 RPC 地址,通过 RPC 向 Talker 发送连接请求,传输订阅的话题名称、消息类型以及通信协议(TCP/UDP)。
4.Talker确认请求

Talker 接收到 Listener 的请求后,也是通过 RPC 向 Listener 确认连接信息,并发送自身的 TCP 地址信息。
5.Listener与Talker件里连接

Listener 根据步骤4 返回的消息使用 TCP 与 Talker 建立网络连接。
6.Talker向Listener发送消息

连接建立后,Talker 开始向 Listener 发布消息。

注意1:上述实现流程中,前五步使用的 RPC协议,最后两步使用的是 TCP 协议

注意2: Talker 与 Listener 的启动无先后顺序要求

注意3: Talker 与 Listener 都可以有多个

注意4: Talker 与 Listener 连接建立后,不再需要 ROS Master。也即,即便关闭ROS Master,Talker 与 Listern 照常通信。

2.话题通信基本操作

需求:

编写发布订阅实现,要求发布方以10HZ(每秒10次)的频率发布文本消息,订阅方订阅消息并将消息内容打印输出。

分析:

在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:

发布方
接收方
数据(此处为普通文本)

流程:

编写发布方实现;
编写订阅方实现;
为python文件添加可执行权限;
编辑配置文件;
编译并执行。

2-1.发布方

#! /usr/bin/env python
“”"
需求: 实现基本的话题通信,一方发布数据,一方接收数据,
实现的关键点:
1.发送方
2.接收方
3.数据(此处为普通文本)

     PS: 二者需要设置相同的话题


消息发布方:
    循环发布信息:HelloWorld 后缀数字编号

实现流程:
    1.导包 
    2.初始化 ROS 节点:命名(唯一)
    3.实例化 发布者 对象
    4.组织被发布的数据,并编写逻辑发布数据

“”"
#1.导包
import rospy
from std_msgs.msg import String

if name == “main”:
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node(“talker_p”)
#3.实例化 发布者 对象
pub = rospy.Publisher(“chatter”,String,queue_size=10)
#4.组织被发布的数据,并编写逻辑发布数据
msg = String() #创建 msg 对象
msg_front = “hello 你好”
count = 0 #计数器
# 设置循环频率
rate = rospy.Rate(1)
while not rospy.is_shutdown():

    #拼接字符串
    msg.data = msg_front + str(count)

    pub.publish(msg)
    rate.sleep()
    rospy.loginfo("写出的数据:%s",msg.data)
    count += 1

2-2.订阅方

#! /usr/bin/env python
“”"
需求: 实现基本的话题通信,一方发布数据,一方接收数据,
实现的关键点:
1.发送方
2.接收方
3.数据(此处为普通文本)

消息订阅方:
    订阅话题并打印接收到的消息

实现流程:
    1.导包 
    2.初始化 ROS 节点:命名(唯一)
    3.实例化 订阅者 对象
    4.处理订阅的消息(回调函数)
    5.设置循环调用回调函数

“”"
#1.导包
import rospy
from std_msgs.msg import String

def doMsg(msg):
rospy.loginfo(“I heard:%s”,msg.data)

if name == “main”:
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node(“listener_p”)
#3.实例化 订阅者 对象
sub = rospy.Subscriber(“chatter”,String,doMsg,queue_size=10)
#4.处理订阅的消息(回调函数)
#5.设置循环调用回调函数
rospy.spin()

3.添加可执行权限

终端下进入 scripts 执行:chmod +x *.py
4.配置 CMakeLists.txt#一般放开注释的find_pkg;catkin_pkg;catkin_install

catkin_install_python(PROGRAMS
scripts/talker_p.py
scripts/listener_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

5.ctrl+shift+b编译执行

1.启动 roscore;

2.启动发布节点:rosrun helloworld talker_p.py

3.启动订阅节点:rosrun helloworld listener_p

PS:可以使用 rqt_graph 查看节点关系:
可以使用rostopic echo

6.总结:
‘’‘talker–publisher’‘’
import rospy
from std_msgs.msg import String

if name == “main”:
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node(“talker”)
#3.实例化 发布者 对象
pub = rospy.Publisher(“house”,String,queue_size=10)#此处要注意,发布方和接收方必须要用相同的话题名称’house’,否则无法执行成功
#4.组织被发布的数据,并编写逻辑发布数据
msg = String() #创建 msg 对象
msg_front = “hello 你好”
count = 0 #计数器
# 设置循环频率
rate = rospy.Rate(1)#每一秒钟循环一次
rospy.sleep(3) #防止丢失数据,要在发布之前休息3S
while not rospy.is_shutdown():

    #拼接字符串
    msg.data = msg_front + str(count)

    pub.publish(msg)#发布msg对象
    rate.sleep()
    rospy.loginfo("订阅的数据:%s",msg.data)#打印数据
    count += 1

‘’‘listener–subscriber’‘’

#1.导包
import rospy
from std_msgs.msg import String

def doMsg(msg):#把订阅到的数据传递进来
rospy.loginfo(“发布的数据:%s”,msg.data)#打印数据

if name == “main”:
#2.初始化 ROS 节点:命名(唯一)
rospy.init_node(“listener”)
#3.实例化 订阅者 对象
sub = rospy.Subscriber(“house”,String,doMsg,queue_size=10)
##订阅者对象里面要有 话题名称,数据类型,回调函数,队列,且talker和listener的队列数要一致
#4.处理订阅的消息(回调函数)
#5.设置循环调用回调函数,如果遗忘它,那么无法接受从talker的数据
rospy.spin()


                 /house

最终的计算图:/talker------------->/subscriber

注意:

##采用rostopic echo chatter来看数据的发布情况
##queue_size的含义
Publisher的消息队列是为了缓存发布节点发布的消息
一旦队列中消息的数量超过了queue_size
那么最先进入队列的(最老的)消息被舍弃

Subscriber的消息队列是为了缓存节点接收到的信息
一旦回调处理的速度过慢,接收到的消息数量超过了queue_size
那么最先进入队列的(最老的)消息会被舍弃

所以,想只处理最新的消息,实际上只需要把两个queue_size都设置成1
那么系统不会缓存数据,自然处理的就是最新的消息

##发布方和接收方必须要用相同的话题’house’,否则无法执行成功
##ros可以实现节点耦合,所以不同的语言写的节点也可以实现交互

‘3.话题通信自定义msg’

在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如: 激光雷达的信息… std_msgs 由于描述性较差而显得力不从心,这种场景下可以使用自定义的消息类型

msgs只是简单的文本文件,每行具有字段类型和字段名称,可以使用的字段类型有:

int8, int16, int32, int64 (或者无符号类型: uint*)

float32, float64

string

time, duration(时间,持续时间)

other msg files(其他消息文件)

variable-length array[] and fixed-length array[C](变长数组,定长数组)

ROS中还有一种特殊类型:Header,标头包含时间戳和ROS中常用的坐标帧信息。会经常看到msg文件的第一行具有Header标头。

需求:创建自定义消息,该消息包含人的信息:姓名、身高、年龄等。

1.流程:

按照固定格式创建 msg 文件
编辑配置文件
编译生成可以被 Python 或 C++ 调用的中间文件

1-1.定义msg文件

功能包下新建 msg 目录,添加文件 Person.msg

string name
uint16 age
float64 height#小数要用float64/32,

1-2.编辑配置文件

package.xml中添加编译依赖与执行依赖

message_generation
message_runtime

##此处的问题是:
‘’‘catkin_package() the catkin package ‘std_msgs’ has been find_package()-ed
but is not listed as a build dependency in the package.xml’‘’
##解决方法:换成如下形式
catkin
roscpp
rospy
std_msgs
message_generation
message_runtime

roscpp
rospy
std_msgs
message_generation
message_runtime

roscpp
rospy
std_msgs
message_runtime
message_generation

CMakeLists.txt编辑 msg 相关配置

#编译式依赖
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)

需要加入 message_generation,必须有 std_msgs

‘’‘find_package和catkin_package相对应,若是编译helloworld的功能包,就必须要依赖于find_packaged的功能包
而find_package的功能包必须依赖于catkin_package的功能包’‘’

配置 msg 源文件

add_message_files(##若是自定义msg,则要放开3个注释,否则都不需要放开(catkin_install除外)
FILES
Person.msg
)

生成消息时依赖于 std_msgs(如果要执行Person.msg就必须要依赖于std_msgs)

generate_messages(
DEPENDENCIES
std_msgs
)

#执行时依赖
catkin_package(

INCLUDE_DIRS include

LIBRARIES demo02_talker_listener

CATKIN_DEPENDS roscpp rospy std_msgs message_runtime#message_runtime是添加的功能包

DEPENDS system_lib

)

add_message_file—generate_messages—catkin_package—find_package
#配置msg源文件—如果要执行Person.msg就必须要依赖于std_msgs—helloworld依赖于find_package—find_package依赖于catkin_package
#所以find_package可以理解为编译式依赖,而catkin_package是运行式依赖

1-3.编译

编译后的中间文件查看:

C++ 需要调用的中间文件(…/工作空间/devel/include/包名/Person.h)

Python 需要调用的中间文件(…/工作空间/devel/lib/python3/dist-packages/包名/msg/Person.py)

后续调用相关 msg 时,是从这些中间文件调用的
my_python_script

4.话题通信自定义msg调用

需求:

编写发布订阅实现,要求发布方以1HZ(每秒1次)的频率发布自定义消息,订阅方订阅自定义消息并将消息内容打印输出。

分析:

在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:

发布方
接收方
数据(此处为自定义消息)

流程:

1.编写发布方实现;
2.编写订阅方实现;
3.为python文件添加可执行权限;
4.编辑配置文件;
5.编译并执行。

4-1.vscode配置

为了方便代码提示以及误抛异常,需要先配置 vscode,将前面生成的 python 文件路径配置进 settings.json

{
“python.autoComplete.extraPaths”: [
“/opt/ros/noetic/lib/python3/dist-packages”,
“/home/kim/demo01/devel/lib/python3/dist-packages/helloworld/msg”
],
“python.analysis.extraPaths”: [
“/opt/ros/noetic/lib/python3/dist-packages”
],
“ros.distro”: “noetic”
}

4-2.发布方

#! /usr/bin/env python
“”"
发布方:
循环发送消息

“”"
import rospy
from demo02_talker_listener.msg import Person

if name == “main”:
#1.初始化 ROS 节点
rospy.init_node(“talker_person_p”)
#2.创建发布者对象
pub = rospy.Publisher(“chatter_person”,Person,queue_size=10)
#3.组织消息
p = Person()
p.name = “葫芦瓦”
p.age = 18
p.height = 0.75

#4.编写消息发布逻辑
rate = rospy.Rate(1)
while not rospy.is_shutdown():
    pub.publish(p)  #发布消息
    rate.sleep()  #休眠
    rospy.loginfo("姓名:%s, 年龄:%d, 身高:%.2f",p.name, p.age, p.height)#输出

4-3.订阅方

#! /usr/bin/env python
“”"
订阅方:
订阅消息

“”"
import rospy
from demo02_talker_listener.msg import Person

def doPerson§:
rospy.loginfo(“接收到的人的信息:%s, %d, %.2f”,p.name, p.age, p.height)

注意:发布方和订阅方都要导入Person

if name == “main”:
#1.初始化节点
rospy.init_node(“listener_person_p”)
#2.创建订阅者对象
sub = rospy.Subscriber(“chatter_person”,Person,doPerson,queue_size=10)
rospy.spin() #3.循环

4-4.权限设置

终端下进入 scripts 执行:chmod +x *.py
4-5.配置 CMakeLists.txt

catkin_install_python(PROGRAMS
scripts/talker_p.py
scripts/listener_p.py
scripts/person_talker.py
scripts/person_listener.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

4-6.执行

1.启动 roscore;

2.启动发布节点;

3.启动订阅节点。

运行结果与引言部分的演示案例2类似。

PS:
可以使用 rqt_graph 查看节点关系。
连续按2次f5可以调试程序
!!!注意:helloworld包下的include,msg,scripts,src是平级别文件不要搞错

!conclude:
1.在cmake中:find_package:message_generation---->add_message_file:Person.msg
----->generate_messages:std_msgs---->catkin_package:message_runtime------>catkin_install_python
2.在xml中:message_generation+message_runtime<—>build_depend+build_export_depend+exec_depend
3.导包:c/s and p/s都要导入:from model.msg/model.srv import *
‘3.通信机制’

服务通信较之于话题通信更简单些,理论模型如下图所示,该模型中涉及到三个角色:

ROS master(管理者)
Server(服务端)
Client(客户端)

ROS Master 负责保管 Server 和 Client 注册的信息,并匹配话题相同的 Server 与 Client ,帮助 Server 与 Client 建立连接,连接建立后,Client 发送请求信息,Server 返回响应信息。

整个流程由以下步骤实现:
0.Server注册

Server 启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含提供的服务的名称。ROS Master 会将节点的注册信息加入到注册表中。
1.Client注册

Client 启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要请求的服务的名称。ROS Master 会将节点的注册信息加入到注册表中。
2.ROS Master实现信息匹配

ROS Master 会根据注册表中的信息匹配Server和 Client,并通过 RPC 向 Client 发送 Server 的 TCP 地址信息。
3.Client发送请求

Client 根据步骤2 响应的信息,使用 TCP 与 Server 建立网络连接,并发送请求数据。
4.Server发送响应

Server 接收、解析请求的数据,并产生响应结果返回给 Client。

注意:

1.客户端请求被处理时,需要保证服务器已经启动;

2.服务端和客户端都可以存在多个。

3.话题,服务端口,客户端,数据载体#要保证话题是一致的

1.服务通信自定义srv

需求:

服务通信中,客户端提交两个整数至服务端,服务端求和并响应结果到客户端,请创建服务器与客户端通信的数据载体。

流程:

srv 文件内的可用数据类型与 msg 文件一致,且定义 srv 实现流程与自定义 msg 实现流程类似:

按照固定格式创建srv文件

编辑配置文件

编译生成中间文件

1-1.定义srv文件

服务通信中,数据分成两部分,请求与响应,在 srv 文件中请求和响应使用—分割,具体实现如下:

功能包下新建 srv 目录,添加 xxx.srv 文件,内容:

客户端请求时发送的两个数字

int32 num1
int32 num2

服务器响应发送的数据

int32 sum

1-2.编辑配置文件

package.xml中添加编译依赖与执行依赖

message_generation
message_runtime

CMakeLists.txt编辑 srv 相关配置

find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)

需要加入 message_generation,必须有 std_msgs

add_service_files(
FILES
AddInts.srv
)

generate_messages(
DEPENDENCIES
std_msgs
)
#find_package是当前创建的包依赖的包,catkin_package是依赖包所依赖的包
注意: 官网没有在 catkin_package 中配置 message_runtime,经测试配置也可以
1-3.编译

编译后的中间文件查看:

C++ 需要调用的中间文件(…/工作空间/devel/include/包名/xxx.h)

Python 需要调用的中间文件(…/工作空间/devel/lib/python3/dist-packages/包名/srv)

后续调用相关 srv 时,是从这些中间件调用的
!!!devel文件下include是专门放c++文件,lib是专门放python文件,但是还需进入到python3/dist-packages/包名/srv/_AddInts.py下查看具体信息

2.服务通信自定义srv调用

需求:

编写服务通信,客户端提交两个整数至服务端,服务端求和并响应结果到客户端。

分析:

在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:

服务端
客户端
数据

流程:

编写服务端实现;
编写客户端实现;
为python文件添加可执行权限;
编辑配置文件;
编译并执行。

2-0.vscode配置

需要像之前自定义 msg 实现一样配置settings.json 文件,如果以前已经配置且没有变更工作空间,可以忽略,如果需要配置,配置方式与之前相同:

{
“python.autoComplete.extraPaths”: [
“/opt/ros/noetic/lib/python3/dist-packages”,
]
}

2-1.服务端

#! /usr/bin/env python
“”"
需求:
编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析

服务器端实现:
    1.导包
    2.初始化 ROS 节点
    3.创建服务对象
    4.回调函数处理请求并产生响应
    5.spin()#有回调函数就必需要有rospy.spin()

“”"

1.导包

import rospy
from model_01 import AddInts,AddIntsRequest,AddIntsResponse

回调函数的参数是请求对象,返回值是响应对象

def doReq(req):
# 1.解析提交的数据
sum = req.num1 + req.num2
rospy.loginfo(“提交的数据:num1 = %d, num2 = %d, sum = %d”,req.num1, req.num2, sum)

# resp = AddIntsResponse()
# resp.sum = sum
# 2.创建响应对象,将结果装进响应对象,并返回响应对象
resp = AddIntsResponse(sum)
return resp#response

if name == “main”:
# 2.初始化 ROS 节点
rospy.init_node(“addints_server_p”)
# 3.创建服务端
server = rospy.Service(“AddInts”,AddInts,doReq)
rospy.loginfo(‘服务器已经启动’)

'''1.addints代表主题,且service和serviceproxy的主题要一致
2.proxy表示代理人;3.第二个参数是service_class,即是服务类型;
4.第三个参数是handler,即是回调函数,回调函数的作用是处理master请求并产生响应
请求会以参数的方式来传递给函数,响应会以返回值的方式来返回'''

# 4.回调函数处理请求并产生响应

# 5.spin 函数
rospy.spin()

总结:
import rospy
from model_02.srv import *

def doReq(req):

sum = req.num1 + req.num2#1.解析数据

response = AddIntsRequest(sum)#2.将数据封装进响应对象;函数传入的数据是请求,返回的响应,

return response

##实际上是1.发出请求,2.返回响应

if name == ‘main’:

rospy.init_node('server')

server = rospy.Server('house',AddInts,doReq)

rospy.spin()

2-2.客户端

#! /usr/bin/env python

“”"
需求:
2- 编写两个节点实现服务通信,客户端节点需要提交两个整数到服务器
服务器需要解析客户端提交的数据,相加后,将结果响应回客户端,
客户端再解析

客户端实现:
    1.导包
    2.初始化 ROS 节点
    3.创建请求对象
    4.发送请求
    5.接收并处理响应

优化:
    加入数据的动态获取

“”"
‘简化版’
import rospy
from helloworld.srv import *
import sys

if name == ‘main’:
#1.初始化节点
rospy.init_node(‘client’)
#2.创建客户端对象
client = rospy.ServiceProxy(‘house’,addInts)
#3.组织请求数据
response = client.call(12,23)#服务参数的对象
#4.处理响应

rospy.loginfo('响应的结果:%d',response.sum)

‘升级版’
#! /usr/bin/env python
#1.导包
import rospy
from demo03_server_client.srv import *
import sys

if name == “main”:

#优化实现
if len(sys.argv) != 3:
    rospy.logerr("请正确提交参数")
    sys.exit(1)#退出程序


# 2.初始化 ROS 节点
rospy.init_node("AddInts_Client_p")
# 3.创建请求对象
client = rospy.ServiceProxy("AddInts",AddInts)
# 请求前,等待服务已经就绪
# 方式1:
# rospy.wait_for_service("AddInts")
# 方式2
client.wait_for_service()
# 4.发送请求,接收并处理响应
# 方式1
# resp = client(3,4)
# 方式2
# resp = client(AddIntsRequest(1,5))
# 方式3
req = AddIntsRequest()##1.发送请求
# req.num1 = 100
# req.num2 = 200 

#优化
req.num1 = int(sys.argv[1])
req.num2 = int(sys.argv[2]) 

resp = client.call(req)##2.处理响应,#当于将调用server,并把req传给doReq(req)的req,并返回resp
rospy.loginfo("响应结果:%d",resp.sum)

!!!sys.argv的作用

argv[0]代表模块文件名、argv[1]代表传入的第一个命令行参数,argv[2]为传入的第二个命令行参数值,以此类推

详解:argv是sys模块的一个全局变量,也称sys模块的一个属性!argv本身为一个list类型的对象,该对象持有的第1个元素是命令行中传入的模块名、从第2个元素开始(含),均为命令行中传入的参数!

注意:argv持有的每个元素的类型均为str(字符串)

举个例子

python temp.py a b c d#在终端中运行python文件的格式

说明:命令行运行temp.py模块,同时传入4个参数:a、b、c、d

sys.argv == [“temp.py”,“a”,“b”,“c”,“d”] #sys.argv是持有5个元素的list对象

sys.argv[0] == “temp.py” #第1个元素为模块名“temp.py”

sys.argv[1] == “a” #第2个元素为"a"

sys.argv[2] == “b” #第3个元素为"b"

sys.argv[3] == “c” #第4个元素为"c"

sys.argv[4] == “d” #第5个元素为"d"

2-3.设置权限

终端下进入 scripts 执行:chmod +x *.py
2-4.配置 CMakeLists.txt

CMakeLists.txt

catkin_install_python(PROGRAMS
scripts/AddInts_Server_p.py
scripts/AddInts_Client_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

2-5.执行

流程:

需要先启动服务:rosrun 包名 服务

然后再调用客户端 :rosrun 包名 客户端 参数1 参数2

结果:

会根据提交的数据响应相加后的结果。


4.参数服务器

参数服务器实现是最为简单的,该模型如下图所示,该模型中涉及到三个角色:

ROS Master (管理者)
Talker (参数设置者)
Listener (参数调用者)

            rosmaster

------------> <---------------------------------
| (1)setParam(‘foo’,1) | |
| |(3){foo:1} |(2)getParam{‘foo’}
| | |
| V |
| V---------------------
talker listener

ROS Master 作为一个公共容器保存参数,Talker 可以向容器中设置参数,Listener 可以获取参数。
整个流程由以下步骤实现:
1.Talker 设置参数

Talker 通过 RPC 向参数服务器发送参数(包括参数名与参数值),ROS Master 将参数保存到参数列表中。
2.Listener 获取参数

Listener 通过 RPC 向参数服务器发送参数查找请求,请求中包含要查找的参数名。
3.ROS Master 向 Listener 发送参数值

ROS Master 根据步骤2请求提供的参数名查找参数值,并将查询结果通过 RPC 发送给 Listener。

!!!talker发送参数—>listener请求参数—>master给listener发送参数

参数可使用数据类型:

32-bit integers

booleans

strings

doubles

iso8601 dates

lists

base64-encoded binary data

字典

注意:参数服务器不是为高性能而设计的,因此最好用于存储静态的非二进制的简单数据

需求:实现参数服务器参数的增删改查操作。
#int float bool list dict
4-1.参数服务器新增(修改)参数

#! /usr/bin/env python
“”"
参数服务器操作之新增与修改(二者API一样)_Python实现:
“”"

import rospy

if name == “main”:
rospy.init_node(“set_update_paramter_p”)

# 设置各种类型参数
rospy.set_param("p_int",10)
rospy.set_param("p_double",3.14)
rospy.set_param("p_bool",True)
rospy.set_param("p_string","hello python")
rospy.set_param("p_list",["hello","haha","xixi"])
rospy.set_param("p_dict",{"name":"hulu","age":8})

# 修改
rospy.set_param("p_int",100)

4-2.参数服务器获取参数

#! /usr/bin/env python

“”"
参数服务器操作之查询_Python实现:
get_param(键,默认值)
当键存在时,返回对应的值,如果不存在返回默认值
get_param_cached
get_param_names
has_param
search_param
“”"

import rospy

if name == “main”:
rospy.init_node(“get_param_p”)

#获取参数
int_value = rospy.get_param("p_int",10000)
double_value = rospy.get_param("p_double")
bool_value = rospy.get_param("p_bool")
string_value = rospy.get_param("p_string")
p_list = rospy.get_param("p_list")
p_dict = rospy.get_param("p_dict")

rospy.loginfo("获取的数据:%d,%.2f,%d,%s",
            int_value,
            double_value,
            bool_value,
            string_value)
for ele in p_list:
    rospy.loginfo("ele = %s", ele)

rospy.loginfo("name = %s, age = %d",p_dict["name"],p_dict["age"])

# get_param_cached
int_cached = rospy.get_param_cached("p_int")#cache:N.是高速缓存器,V.缓存
rospy.loginfo("缓存数据:%d",int_cached)

# get_param_names
names = rospy.get_param_names()
for name in names:
    rospy.loginfo("name = %s",name)

rospy.loginfo("-"*80)

# has_param
flag = rospy.has_param("p_int")
rospy.loginfo("包含p_int吗?%d",flag)#1表示有,0表示无

# search_param
key = rospy.search_param("p_int")
rospy.loginfo("搜索的键 = %s",key)#键为p_int

4-3.参数服务器删除参数

#! /usr/bin/env python
“”"
参数服务器操作之删除_Python实现:
rospy.delete_param(“键”)
键存在时,可以删除成功,键不存在时,会抛出异常
“”"
import rospy

if name == “main”:
rospy.init_node(“delete_param_p”)

try:
    rospy.delete_param("p_int")
except Exception as e:
    rospy.loginfo("删除失败")

##包含get_param/set_param/get_param_cached/get_param_names/has_param/search_param

.输入:rosparam list
/p_bool
/p_dict/age
/p_dict/name
/p_double
/p_list
/p_string
/rosdistro
/roslaunch/uris/host_kim_g3_3590__42061
/rosversion
/run_id

…执行顺序:rosrun model_02 param_set.py -----> rosrun model_02 param_get.py—>rosrun model_02 param_del.py

设置数据:rospy.prama_set(‘int’,12)—>
得到数据:int_value=rospy.param_get(‘int’)/
得到数据名称:names=rospy.param_get_names()/
得到缓存数据:cached = rospy.param_get_cached(‘int’)/
判断数据:flag = rospy.has_param(‘int’

相关文章