| 参考:
1 安装ROS
1.1 更换国内源
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'
1.2 设置 key
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
1.3 安装操作
sudo apt update
sudo apt install ros-noetic-desktop-full
sudo apt remove ros-noetic-* # 卸载 ros
1.4 配置环境变量
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc
1.5 安装依赖项
sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
sudo apt install python3-rosdep
sudo rosdep init
# 终端代理 proxychains
sudo apt install proxychains
sudo vim /etc/proxychains.conf
# 添加代理,以 socks5 为例
socks5 127.0.0.1 9999 username password
# 使用方法:在需要用到代理的命令行前加上 proxychains
proxychains curl cip.cc
rosdep update # # 这一步需要访问外网资源,所以需要设置一下终端代理,命令如下
proxychains rosdep update
2 HelloWorld 实例演示
2.1 创建空间并初始化
mkdir -p test/src && cd test
catkin_make
2.2 添加依赖性
cd src
catkin_create_pkg helloworld(自定义ROS包名) roscpp rospy std_msgs
2.3 编程实现
# 该目录下 test/src/helloworld/src
touch helloworld_c.cpp
sudo vim helloworld_c.cpp # 编写源码文件
#############################
# 文件内容如下:
// 1. 包含 ros 头文件
#include "ros/ros.h"
// 2. 编写 main 函数
int main(int argc, char *argv[]) {
// 3. 初始化 ros 节点
ros::init(argc, argv, "hello_node");
// 4. 输出日志
ROS_INFO("hello world");
return 0;
}
2.4 编辑 CMakeList.txt 文件
# vim 显示行号
:set number
add_executable(源文件名 src/源文件名.cpp) # 第一个参数可随意起名,映射到第二个参数指定的文件
add_executable(hello src/helloworld_c.cpp)
target_link_libraries(源文件名 ${catkin_LIBRARIES})
target_link_libraries(hello ${catkin_LIBRARIES})
2.5 编译运行
# 在工作空间下 /home/sebas/projects/ros-projects/test 编译
catkin_make
# 启动,另起一个窗口
roscore
# 在工作空间下 /home/sebas/projects/ros-projects/test 编译
source ./devel/setup.bash
rosrun helloworld(包名) hello
编译和运行截图如下:
3 VSCode开发环境配置
3.1 terminator 使用
sudo apt install terminator
# 快捷键
Ctrl+Shift+O //水平分割终端
Ctrl+Shift+E //垂直分割终端
Ctrl+Shift+F //搜索
Ctrl+Shift+C //复制选中的内容到剪贴板
Ctrl+Shift+V //粘贴剪贴板的内容到此处
Ctrl+Shift+W //关闭当前终端
Ctrl+Shift+Q //退出当前窗口,当前窗口的所有终端都将被关闭
Ctrl+Shift+X //最大化显示当前终端
Ctrl+Shift+Z //最大化显示当前终端并使字体放大
Ctrl+Shift+N or Ctrl+Tab //移动到下一个终端
Ctrl+Shift+P or Ctrl+Shift+Tab //Crtl+Shift+Tab 移动到之前的一个终端
4 中国科学院软件所 ROS 入门
ROS 工程结构
4.1 package
ROS软件的基本组织形式,catkin编译的基本单元,一个package可以包含多个可执行文件(节点)。基本组成:CMakeList.txt 和 package.xml
-
CMakeList.txt : 规定 catkin 编译的规则,例如源文件、依赖项、目标文件
-
package.xml : 定义了 package 的属性,例如包名、版本号、作者、依赖等。
-
manifest.xml:rosbuild 编译系统采用的包信息清单,类似 catkin 的 package.xml
-
自定义通信格式:消息(msg)、服务(srv)、动作(action)
-
launch 以及配置文件: launch 文件(一次性运行多个可执行文件)、配置文件(yaml)
-
常用的包管理指令
4.2 基本流程
# 安装 tree,以树形结构展示目录
sudo apt install tree
mkdir -p catkin_ws/src && cd catkin_ws
tree
catkin_make # 初始化
tree
cd src
catkin_create_pkg test1 # 最基础的 package
catkin_create_pkg test2 roscpp rospy std_msgs nav_msgs # 安装所需要的依赖项
tree
proxychains git clone https://github.com/DroidAITech/ROS-Academy-for-Beginners.git
cd ..
rosdep install --from-paths src --ignore-src --rosdistro=noetic -y
5 lingyun_ros
5.1 目录结构
catkin_ws
- build(保存编译完成后的二进制可执行文件)
- devel
- map_data (数据文件)
- src (该目录存放功能包等要实现的文件)
- lingyun_subscriber (订阅图像和点云)
- CMakeLists.txt(需要自行编辑 需要的库、要编译的源文件等)
- src
- image_subscriber.cc
- pointCloud_subscriber.cc
- lingyun_launch(启动多个ros节点)
- launch
- lingyun.launch
5.2 详细步骤
- 创建工作空间并配置环境变量
# 创建一个工作空间并初始化
mkdir -p catkin_ws/src
cd catkin_ws/src
catkin_init_workspace
# 编译工作空间
cd catkin_ws/
catkin_make
# 环境变量
# 每次编译(catkin_make)完成后,需要更新一下环境变量
source devel/setup.bash
# 也可以把这句写到 ~/.bashrc 中,这样就不用每次都更新
# 检查环境变量
echo $ROS_PACKAGE_PATH
- 创建功能包
cd catkin_ws/src
catkin_create_pkg lingyun_subscriber std_msgs rospy roscpp
# 创建功能包 lingyun_subscriber 后,该目录下会自动生成 CMakeLists.txt 和 package 等文件,CMakeLists.txt 文件需要自己配置,具体参考附件 。src 目录下存放要实现的源码文件
# 例如实现订阅图像和点云的功能,具体代码参考附件
touch image_subscriber.cc
touch pointCloud_subscriber.cc
# 编译功能包,在 catkin_ws 目录下执行以下命令
catkin_make
# 编译完成后在build目录下会生成对应的二进制可执行文件
source catkin_ws/devel/setup.bash
自己编写的定位建图等代码也可以直接放到 src 目录下,将 code 复制到 src 目录下,配置好 CMakeList.txt 文件,使用 catkin_make 也可以编译成功
- roslaunch文件的编写
# roslaunch
cd catkin_ws/src
# 在 catkin_ws/src 目录下创建 roslaunch 的功能包
catkin_create_pkg lingyun_launch
# 创建一个 launch 目录用于存放 launch 文件
cd lingyun_launch
mkdir launch && cd launch
touch lingyun.launch
# lingyun.launch 文件内容
# pkg:节点所在功能包名称
# name:节点的可执行文件名称
# type:节点运行时的名称
<launch>
<node pkg="tlingyun_subscriber" name="image_subscriber" type="image_subscriber"/>
<node pkg="lingyun_subscriber" name="pointCloud_subscriber" type="pointCloud_subscriber"/>
<node pkg="code" name="test_lattest" type="test_lattest"/>
</launch>
# 编写完 launch 文件后,回到 catkin_ws 目录执行编译操作并更新环境变量
catkin_make
source devel/setup.bash # 如果在 ~/.bashrc 文件中配置了就不需要这一步
# 使用 launch 文件启动多个 ros 节点
roslaunch lingyun_launch lingyun.launch
使用 roslaunch 命令启动节点的时候,可能会报错找不到可执行的二进制文件,需要把 catkin_ws/build/code 和 catkin_ws/build/lingyun_subscriber 目录下的二进制可执行文件分别复制到 catkin_ws/src/code 和 catkin_ws/src/lingyun_subscribe 目录下。
附件
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
IF(NOT ROS_BUILD_TYPE)
SET(ROS_BUILD_TYPE Release)
ENDIF()
MESSAGE("Build type: " ${ROS_BUILD_TYPE})
project(lidar_relocalization)
set(CMAKE_C_FLAGS_RELEASE "-O3")
add_definitions(-w)
################################
# OpenCV
################################
find_package(OpenCV 3)
if(NOT OpenCV_FOUND)
find_package(OpenCV 2.4.3 QUIET)
if(NOT OpenCV_FOUND)
message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
endif()
endif()
find_package(Eigen3 3.1.0 REQUIRED)
find_package(PCL REQUIRED COMPONENT common io visualization filters)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
geometry_msgs
nav_msgs
tf
cv_bridge
)
# include_directories(${CATKIN_INCLUDE_DIRS})
include_directories(${catkin_INCLUDE_DIRS})
include_directories(${roscpp_INCLUDE_DIRS})
include_directories(${PCL_INCLUDE_DIRS})
include_directories(${OpenCV_INCLUDE_DIRS})
include_directories(src)
message(${PCL_INCLUDE_DIRS})
# add_definitions(-DLOG_OUT)
# target_include_directories(reloc PUBLIC
# orbslam_lib/include
# orbslam_lib/include/CameraModels
# orbslam_lib/Thirdparty/Sophus
# orbslam_lib)
# Node for monocular camera
# rosbuild_add_executable(Test test_ros.cc)
# target_link_libraries(Test reloc ${OpenCV_LIBRARIES} ${PCL_LIBRARIES})
# add_executable(test_ros test_ros.cc)
# target_link_libraries(test_ros reloc ${catkin_LIBRARIES} ${OpenCV_LIBRARIES} ${PCL_LIBRARIES})
# add_executable(test1 test.cc)
# target_link_libraries(test1 reloc ${catkin_LIBRARIES} ${OpenCV_LIBRARIES} ${PCL_LIBRARIES})
add_executable(image_subscriber src/image_subscriber.cc)
target_link_libraries(image_subscriber ${OpenCV_LIBRARIES} ${roscpp_LIBRARIES} ${catkin_LIBRARIES})
add_executable(pointCloud_subscriber src/pointCloud_subscriber.cc)
target_link_libraries(pointCloud_subscriber ${OpenCV_LIBRARIES} ${PCL_LIBRARIES} ${roscpp_LIBRARIES} ${catkin_LIBRARIES})
# add_executable(main main.cc)
# target_link_libraries(main reloc ${OpenCV_LIBRARIES} ${PCL_LIBRARIES})
#add_executable(test test.cc)
# target_include_directories(test PUBLIC
# orbslam_lib/include
# orbslam_lib/include/CameraModels
# orbslam_lib/Thirdparty/Sophus
# orbslam_lib)
#target_link_libraries(test reloc ${OpenCV_LIBRARIES} ${PCL_LIBRARIES})
订阅图像和点云
- image_subscriber.cc
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/core/mat.hpp>
#include <time.h>
#include <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
using namespace std;
string cam0_path = "./SaveImgAndPCD/cam0/";
void ImageCallback(const sensor_msgs::ImageConstPtr& img_msg)
{
ROS_INFO("image: ",img_msg -> data);
// // Copy the ros image message to cv::Mat.
// cv_bridge::CvImageConstPtr cv_ptr;
// try
// {
// cv_ptr = cv_bridge::toCvShare(msg);
// }
// catch (cv_bridge::Exception& e)
// {
// ROS_ERROR("cv_bridge exception: %s", e.what());
// return;
// }
//double timestamps = img_msg -> header.stamp.toSec();
//image_times.push_back(timestamps);
cv_bridge::CvImageConstPtr ptr;
ptr = cv_bridge::toCvCopy(img_msg, img_msg -> encoding);
cv::Mat show_image = ptr -> image;
double timestamps = img_msg -> header.stamp.toSec();
string image_name = to_string(timestamps) + ".jpg";
cv::imwrite(cam0_path + image_name, show_image); // 保存
cv::imshow("img", show_image);
//images.push_back(show_image);
}
int main(int argc, char **argv) {
ros::init(argc, argv, "RGBD");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe("/usb_cam_30s/image_raw", 10, ImageCallback);
ros::spin();
return 0;
}
- pointCloud_subscriber.cc
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/core/mat.hpp>
#include <time.h>
#include <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include "pcl/io/pcd_io.h"
#include "pcl/point_cloud.h"
#include "pcl/point_types.h"
#include "pcl_conversions/pcl_conversions.h"
#include "ros/ros.h"
#include "sensor_msgs/PointCloud2.h"
static size_t counter = 0;
std::string PCD_PATH = "./SaveImgAndPCD/PCD/";
void PointCloudCallback(const sensor_msgs::PointCloud2ConstPtr& lidar_message) {
pcl::PointCloud<pcl::PointXYZI> point_cloud;
pcl::fromROSMsg(*lidar_message, point_cloud);
counter++;
std::string file_name = "point_cloud_" + std::to_string(counter) + ".pcd";
pcl::io::savePCDFile(PCD_PATH + file_name, point_cloud);
}
int main(int argc, char **argv) {
ros::init(argc, argv, "point_cloud_subscriber");
ros::NodeHandle node_handle;
ros::Subscriber point_cloud_sub = node_handle.subscribe("/benewake_ros_driver_node/benewake_pointcloud", 1, PointCloudCallback);
ros::spin();
return 0;
}