ubuntu 20.04 安装 ros1 和ros2
ubuntu 选择Hong Kong 源
1. ROS1安装
添加 sources.list(设置你的电脑可以从 packages.ros.org 接收软件.)
sudo sh -c '. /etc/lsb-release && echo "deb [arch=amd64] http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'
添加 keys
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
安装ROS1桌面完整版
sudo apt update
sudo apt install ros-noetic-desktop-full
环境测试
source /opt/ros/noetic/setup.bash
补全rosdep
sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
sudo apt install python3-rosdep
sudo rosdep init
rosdep update
2. ROS2安装
确保系统要支持 UTF-8:
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8
设置软件源
sudo apt update sudo apt install curl gnupg2 lsb-release # 下面这条语句,我的输出错误: gpg: no valid OpenPGP data found # curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add - # 解决上面的问题,可以换成下面这条语句: $ curl http://repo.ros2.org/repos.key | sudo apt-key add - # 之后再添加源: sudo sh -c '. /etc/lsb-release && echo "deb
[arch=amd64]
http://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros2-latest.list'
安装ROS2桌面完整版
sudo apt update
sudo apt install ros-foxy-desktop
sudo apt install python3-colcon-common-extensions
环境测试
source /opt/ros/foxy/setup.bash
自动补全工具
sudo apt update
sudo apt install python3-argcomplete
sudo apt update
sudo apt install ros-foxy-rmw-connext-cpp
安装ros1转换bridge
sudo apt update
sudo apt install ros-foxy-ros1-bridge
ROS1和ROS2混合配置
sudo gedit ~/.bashrc
打开.bashrc文本文件后在末尾加上如下代码,完成环境变量设置。
#source /opt/ros/noetic/setup.bash
echo "ros noetic(1) or ros2 foxy(2)?"
read edition
if [ "$edition" -eq "1" ];then
source /opt/ros/noetic/setup.bash
else
source /opt/ros/foxy/setup.bash
fi
ROS1和ROS2差异
编译
catkin_make --> colcon build
catkin_make -DCATKIN_WHITELIST_PACKAGES="" --> colcon build --packages-select PACKAGE_NAME
bashrc存入
echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc --> echo "source ~/colcon_ws/install/setup.bash" >> ~/.bashrc
terminal 命令
rosrun --> ros2 run
rosnode --> ros2 node
roslaunch --> ros2 launch
rosparam --> ros2 param
rospkg --> ros2 pkg
rosservice --> ros2 service
rossrv --> ros2 srv
rostopic --> ros2 topic
rosaction --> ros2 action
ROS2写法
有一说一,ROS2的class管理还是比较好的,ROS2相比ROS1在语法上有了很大的改变,在编程思路还是一样。这里给出最简单的topic通讯。
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
/* This example creates a subclass of Node and uses std::bind() to register a
* member function as a callback from the timer. */
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0)
{
publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
auto message = std_msgs::msg::String();
message.data = "Hello, world! " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalPublisher>());
rclcpp::shutdown();
return 0;
}
对上述代码进行简单分析:
头文件部分
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
命名空间
using namespace std::chrono_literals;
使用面向对象中的继承,类名为MinimalPublisher继承rclcpp::Node这个类,继承方式为public;
class MinimalPublisher : public rclcpp::Node
私有成员有回调函数timer_callback,计时器对象timer_,发布者对象publisher_,统计数量的count_;
该timer_callback函数是设置消息数据和实际发布消息的地方。该RCLCPP_INFO宏确保每个发布的消息都打印到控制台。还有计时器、发布者和计数器字段的声明。
private:
void timer_callback()
{
auto message = std_msgs::msg::String();
message.data = "Hello, world! " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
公有成员:类的构造函数用于对私有成员进行初始化;
公共构造函数命名节点minimal_publisher并初始化count_为 0。在构造函数内部,发布者使用String消息类型、主题名称topic和所需的队列大小进行初始化,以在发生备份时限制消息。接下来,timer_被初始化,这会导致timer_callback函数每秒执行两次。this指的是该节点
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0)
{
publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
主函数部分
rclcpp::init初始化 ROS 2,并rclcpp::spin开始处理来自节点的数据,包括来自计时器的回调。
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalPublisher>());
rclcpp::shutdown();
return 0;
}
创建订阅者
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using std::placeholders::_1;
class MinimalSubscriber : public rclcpp::Node
{
public:
MinimalSubscriber()
: Node("minimal_subscriber")
{
subscription_ = this->create_subscription<std_msgs::msg::String>(
"topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
}
private:
void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
{
RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalSubscriber>());
rclcpp::shutdown();
return 0;
}
修改CMakeLists.txt文件,将下面内容复制到文件中并保存
add_executable(talker src/publisher_member_function.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
add_executable(listener src/subscriber_member_function.cpp)
ament_target_dependencies(listener rclcpp std_msgs)
install(TARGETS
talker
listener
DESTINATION lib/${PROJECT_NAME})