【ros】ROS1的安装和相关使用方法

安装ROS1:noetic

小鱼一键安装

wget http://fishros.com/install -O fishros && . fishros

问题:联网问题,依然安装比较繁琐
ROS官网
仓库地址

sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'

设置密钥(去ros官网获取更新)

sudo apt-key adv --keyserver 'hkp://pgp.mit.edu:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

开始安装

sudo apt update
sudo apt install ros-noetic-desktop-full

环境变量

source /opt/ros/noetic/setup.bash

开机自动设置环境变量

echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc

实验:

roscore

检查:

sudo apt-get install -y ros-noetic-navigation
sudo apt-get install -y ros-noetic-robot-localization
sudo apt-get install -y ros-noetic-robot-state-publisher

ROS_noetic

rosbag的使用方法

ROS2和ROS1数据集的转换

ros最强大的地方在于开源工具多。
转换工具需要有如下特点:
● 可以无缝实现bag和db3的互相转换
● 提供了db3文件的读写接口,非常方便。
● 转换速度很快。
● 不用依赖ros2、ros1
这个工具就是
rosbags
更新对ros2 mcap格式数据支持。注意rosbags版本要大于等于0.9.15

pip install --upgrade rosbags

关键是这个包还不用依赖ros2和ros1,在python3下可以直接使用
其文档在操作文档
代码托管在gitlab上,github地址
安装

pip install rosbags

将ros2的db3转为bag,rosbag2_2023_01_31-14_40_45是文件夹,必须包含metadata.yaml文件

rosbags-convert rosbag2_2023_01_31-14_40_45
rosbags-convert --dst /home/john/rosbag/dcl/Campus_Road_1.bag Campus_Road_1

即可得到rosbag2_2023_01_31-14_40_45.bag
将bag文件转为ros2的db3

rosbags-convert rosbag2_2023_01_31-14_40_45.bag

从db3中读取msg

from rosbags.rosbag2 import Reader
from rosbags.serde import deserialize_cdr

# create reader instance and open for reading
with Reader('/home/xxx/data/rosbag2_2023_01_04-17_24_41') as reader:
    connections = [x for x in reader.connections if x.topic == '/Imu']
    for connection, timestamp, rawdata in reader.messages(connections=connections):
         msg = deserialize_cdr(rawdata, connection.msgtype)
         print(msg.header.frame_id)

Linux查看pcd云图方法

如果直接输入命令:

pcl_viewer xxx.pcd

提示没有相关软件包信息。
安装pcl工具包
输入命令:

sudo apt install pcl-tools

等待安装完毕。
输入打开pcd文件命令:

pcl_viewer xxx.pcd

ros中的节点、话题、TF树,以lio-sam为例

rqt_graph

rqt_tf_tree

c++和yaml文件

利用ROS自带的XmlRpc::XmlRpcValue实现一维数组或者二位数组等类似json数据的读取

yaml文件

这套代码需要很多设置
在$(find test_cpp)/config/config.yaml

# yaml文件
scanners: 
- {pub_topic: "scan_head", frame_id: "laser_scanner_link_head",server_ip: "192.168.167.100",server_port: 2111}
- {pub_topic: "scan_middle",frame_id: "laser_scanner_link_middle",server_ip: "192.168.167.101",server_port: 2111}
- {pub_topic: "scan_tail",frame_id: "laser_scanner_link_tail",server_ip: "192.168.167.102",server_port: 2111}

merge_area: 
    car: {left: 0, top: 0.5, right: 1.0, bottom: 1.25}
    bus: {left: 0.125, top: 0.5, right: 0.875, bottom: 1.25}
    person: {left: -0.25, top: 0.75, right: 1.25, bottom: 1.25}

num_list: [37.783, 1.414, 3.14, 0.618]

C++读取代码

#include <ros/ros.h>
#include <std_msgs/String.h>
#include <string>
#include <XmlRpcValue.h>  // 确保包含 XmlRpc 库

using namespace std;

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

    // 字典数组的解析
    XmlRpc::XmlRpcValue params;  // 定义 params 变量
    if (nh.getParam("/scanners", params)) {  // 检查是否成功获取参数
        if (params.getType() == XmlRpc::XmlRpcValue::TypeArray) {  // 确保 params 是一个数组
            for (size_t i = 0; i < params.size(); ++i) {
                const std::string& server_ip = static_cast<std::string>(params[i]["server_ip"]);
                const std::string& frame_id = static_cast<std::string>(params[i]["frame_id"]);
                const std::string& pub_topic = static_cast<std::string>(params[i]["pub_topic"]);
                const int server_port = static_cast<int>(params[i]["server_port"]);  // 去掉引用,这里直接使用值

                printf("ip:%s, id:%s, topic:%s, port:%d \r\n", server_ip.c_str(), frame_id.c_str(), pub_topic.c_str(), server_port);
            }
        } else {
            ROS_ERROR("Expected 'scanners' to be an array");
        }
    } else {
        ROS_ERROR("Failed to get param 'scanners'");
    }

    // 数组写入向量
    XmlRpc::XmlRpcValue nums;  // 定义 nums 变量
    if (nh.getParam("/num_list", nums)) {  // 检查是否成功获取参数
        if (nums.getType() == XmlRpc::XmlRpcValue::TypeArray) {  // 确保 nums 是一个数组
            std::vector<double> num_list;
            for (size_t i = 0; i < nums.size(); ++i) {
                XmlRpc::XmlRpcValue tmp_value = nums[i];
                if (tmp_value.getType() == XmlRpc::XmlRpcValue::TypeDouble) {
                    double value = static_cast<double>(tmp_value);  // 类型转换
                    num_list.push_back(value);
                    printf("get one num: %f\r\n", value);
                } else {
                    ROS_WARN("Element %zu is not a double", i);
                }
            }
        } else {
            ROS_ERROR("Expected 'num_list' to be an array");
        }
    } else {
        ROS_ERROR("Failed to get param 'num_list'");
    }

    // 字典读取,注意类型对应
    XmlRpc::XmlRpcValue area;  // 定义 area 变量
    if (nh.getParam("/merge_area", area)) {  // 检查是否成功获取参数
        if (area.hasMember("car")) {  // 检查是否包含 'car' 字段
            XmlRpc::XmlRpcValue car = area["car"];
            if (car.getType() == XmlRpc::XmlRpcValue::TypeStruct) {  // 确保 car 是一个字典
                printf("car_area = top: %f, left: %d, bottom: %f, right: %f\r\n", 
                       static_cast<double>(car["top"]), 
                       static_cast<int>(car["left"]), 
                       static_cast<double>(car["bottom"]), 
                       static_cast<double>(car["right"]));
            } else {
                ROS_ERROR("'car' is not a struct");
            }
        } else {
            ROS_ERROR("No 'car' member found in 'merge_area'");
        }
    } else {
        ROS_ERROR("Failed to get param 'merge_area'");
    }
}

注意类型的转换,需要注意一一对应,如果不对应,就会报错,(如:int不能使用double强转)
报错信息:terminate called after throwing an instance of ‘XmlRpc::XmlRpcException’

用launch启动的方法

<launch>
    
    <node pkg="test_cpp" type="test_cpp" name="test" output="screen" />
        <rosparam file="$(find test_cpp)/config/config.yaml" command="load"/>
    <!-- </node> -->
<!-- <node pkg="learning_topic" type="person_publisher" name="listener" output="screen" />  -->
</launch>

1 launch文件结构(启动需要CMakeList)
● 由XML语言写的,可实现多个节点的配置和启动。
● 不再需要打开多个终端用多个rosrun命令来启动不同的节点了
● 可自动启动ROS Master
例子:

<launch>
	<node pkg="learning_topic" type="person_subscriber" name="talker" output="screen" />
	<node pkg="learning_topic" type="person_publisher" name="listener" output="screen" /> 
</launch>
 <launch>

    <!-- Turtlesim Node-->
    <node pkg="turtlesim" type="turtlesim_node" name="sim"/>
    <node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>

    <node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle1" name="turtle1_tf_broadcaster" />
    <node pkg="learning_tf" type="turtle_tf_broadcaster" args="/turtle2" name="turtle2_tf_broadcaster" />

    <node pkg="learning_tf" type="turtle_tf_listener" name="listener" />

  </launch>
<launch>

	<!-- Turtlesim Node-->
	<node pkg="turtlesim" type="turtlesim_node" name="sim"/>
	<node pkg="turtlesim" type="turtle_teleop_key" name="teleop" output="screen"/>

	<node name="turtle1_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py">
	  <param name="turtle" type="string" value="turtle1" />
	</node>
	<node name="turtle2_tf_broadcaster" pkg="learning_tf" type="turtle_tf_broadcaster.py">
	  <param name="turtle" type="string" value="turtle2" /> 
	</node>

    <node pkg="learning_tf" type="turtle_tf_listener.py" name="listener" />

</launch>
<launch>

	<param name="/turtle_number"   value="2"/>

    <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node">
		<param name="turtle_name1"   value="Tom"/>
		<param name="turtle_name2"   value="Jerry"/>

		<rosparam file="$(find learning_launch)/config/param.yaml" command="load"/>
	</node>

    <node pkg="turtlesim" type="turtle_teleop_key" name="turtle_teleop_key" output="screen"/>

</launch>
<launch>

	<include file="$(find learning_launch)/launch/simple.launch" />

    <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node">
		<remap from="/turtle1/cmd_vel" to="/cmd_vel"/>
	</node>

</launch>

CMakeList.txt

cmake_minimum_required(VERSION 3.0.2)
project(test_cpp)

## 找到catkin和任何其他需要的包
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rosmsg
  rospy
  std_msgs
)

## 声明catkin包
catkin_package()

## 指定包含目录
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

## 将源文件编译为可执行文件
add_executable(test_cpp src/test_cpp.cpp)

## 连接目标所需的库
target_link_libraries(test_cpp
  ${catkin_LIBRARIES}
)

## 安装可执行文件
install(TARGETS test_cpp
  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

python文件

创建工作空间

mkdir -p ~/catkin_data/src

进入src文件夹:

cd catkin_date/src/

初始化文件夹(在src文件夹下):

catkin_init_workspace

创建功能包
2、进入data功能包

cd catkin_data/src/data/

创建launch文件夹和scripts文件夹

mkdir launch scripts

在launch文件夹中创建demo_py.launch,内容如下:

touch demo_py.launch
<launch>
        <param name="date" value="2021-03-18" />
        <param name="vvvv" value="5" />
        <node pkg="demo_py" name="demo_py" type="hello.py" output="screen">
        </node>
</launch>

name区别于type和pkg

● pkg:指定了节点所属的 ROS 包(在这里是 cut_rosbag_py)。
● type:指定了要运行的可执行文件或脚本(在这里是 cut_rosbag.py)。
● name:指定了节点的唯一名称(在这里是 cut_rosbag)。

在scripts文件中创建hello.py,内容如下:

touch hello.py
#!/usr/bin/env python
# coding:utf-8
import rospy

def gsp(data):
    # 回调函数
    rospy.loginfo("Received GPS position: latitude=%f, longitude=%f", data.latitude, data.longitude)


if __name__ == '__main__':
    # 创建节点
    rospy.init_node("pyhello")
    print("hello Irvingao! this is ur first ros python code! Good luck for u!")

    # 一个脚本只有一个节点,anonymous意思是:week_3662,防止和week节点重名
    # rospy.init_node('week', anonymous=True)
    print(rospy.has_param('/date')) # 是否存在参数
    date=rospy.get_param('date') # 获取参数
    record=rospy.get_param('vvvv')
    print(record) # 打印参数
    print(date)
    # rospy.Subscriber('/minibus/gpsposition', GpsPosition, gsp)
    rospy.spin()

可执行权限修改

cd scripts
chmod a+x hello.py

默认编写的py文件是不具备执行权限的。因此我们需要手动讲文件权限修改为可执行。

通过roslaunch运行

cd catkin_date/

编译工作空间

catkin_make
source devel/setup.bash
roslaunch demo_py demo_py.launch 

运行后打印在launch文件中设置好的参数

launch文件需要放在某个package目录下,最好放在最主要的package目录下,醒目
launch文件是可以跨包的,不要因为roslaunch test_pkg test.launch运行在test_pkg下而认为只能执行test_pkg下的节点,只要配置好对应的包名,节点,和执行文件即可
launch文件后缀必须是.launch
output 设置成screen是输出到屏幕,默认是输出到日志文件,日志保存在.ros/log目录下
respawn和required, 关于节点运行出错的处理,两个只能选一种
arg和param配合通过变量控制参数值,可以在执行launch时给定参数值,运行命令没有给定时使用默认值default设置的值
● C++ ,注意使用对应的参数类型
内部参数使用~ :比如rosRate为ssd_pkg的内部参数,其他包不能使用
全局参数加/ :version为全局参数,所有包可以加载
当然内部参数可以使用全路径方式指定:/ssd_pkg/rosRate
● python获取
version = rospy.get_param(‘/version’) # 获取全局参数带/
rete = rospy.get_param(‘~rosRate’)# 获取私有命名空间参数需要带~
config.yaml , 文件放在了test_pkg的同级目录,
注意
1.yaml使用空格设置层级,多少个空格没关系,保持一致即可,不能使用table
2. -开头组成列表(当然也可以使用[]),字典使用{}加键值对
3. 类型会自动识别字符串和数字,如果要指定为字符串需要用双引号
4. 重点说明:yaml缩进不能使用table

ROS自定义msg的使用(包括srv)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值