0. 前言

在使用ROS时候,我们常常感叹ROS的好用,但是在ROS开发方面,从前的我常常会拘泥于教程上的POP的开发方式,这样让我在开发相对大型的机器人程序时就倍感不适。而在19年开始我尝试着在ROS1中使用OOP的形式编程。但是我们知道ROS2和ROS1存在着差异性,所以我们不能直接套用ROS1的编程习惯去实现ROS2的编程。为此本文针对ROS2去给出一套POP和OOP编程以供各位对比。这里也感谢fishros对ROS2开源社区的贡献。

在这里插入图片描述

#include <ros/ros.h>
#include <std_msgs/UInt8.h>

class TopicPublish
{
public:

    TopicPublish(std::string pub_name);
    void publish(uint8_t dat);

private:

    ros::NodeHandle nh;

    ros::Publisher topic_pub;
};

TopicPublish::TopicPublish(std::string pub_name)
{
    topic_pub = nh.advertise<std_msgs::UInt8>(pub_name, 10);
}

void TopicPublish::publish(uint8_t dat)
{
    std_msgs::UInt8 msgs;
    msgs.data = dat;
    topic_pub.publish(msgs);
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "topic_publish_node");
    TopicPublish mypub("/profect");
    ros::Rate loop(10);
    while(ros::ok())
    {
        mypub.publish(8);
        ros::spinOnce();
        loop.sleep();
    }

    return 0;
}

1.POP和OOP概念

一、面向过程编程:(POP:Procedure Oriented Programming)
面向过程编程是以功能为中心来进行思考和组织的一种编程方法,它强调的是功能(即系统的数据被加工和处理的过程),在程序设计中主要以函数或者过程为程序的基本组织方式,系统功能是由一组相关的过程和函数序列构成。
从思维上来讲,面向过程更强调细节,忽视了整体性和边界性。
典型代表是 C/C++的结构体

  • 优点

    • 流程化编程任务明确,在开发之前基本考虑了实现方式和最终结果;
    • 开发效率高,代码的短小精悍,善于结合数据结构来开发高效率的程序;
    • 流程明确,具体步骤清楚,便于节点分析。
  • 缺点

    • 需要深入的思考,耗费精力;
    • 代码重用性低,不易扩展,维护起来难度大;
    • 对复杂业务,面向过程的模块化难度较高,耦合度比较高。

二、面向对象编程:(OOP:Object Oriented Programming)
面向对象编程以对象为中心,面向对象作为一种新型的程序设计方法,其是以对象模型为基础进行的抽象过程,并在应用过程中形成了描述自己的抽象概念定义,包括对象、类、封装、继承以及多态等
面向对象是一种编程范式,满足面向对象编程的语言,一般会提供类、封装、继承等语法和概念来辅助我们进行面向对象编程。

  • 优点
    • 结构清晰,注重 对象和职责,不同的对象承担不同的职责;
    • 封装性,将事务高度抽象,便于流程中的行为分析、操作;
    • 容易扩展,代码重用率高,可继承,可覆盖;
    • 实现简单,可有效地减少程序的维护工作量。
  • 缺点
    • 面向对象在面向过程的基础上高度抽象,从而和代码底层的直接交互非常少,从而不适合底层开发和游戏开发,甚至是多媒体开发;
    • 复杂性,对于事务开发而言,事务本身是面向过程的,过度的封装导致事务本身的复杂性提高。

2. POP与OOP

基于POP的ROS2

#include "rclcpp/rclcpp.hpp"


int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    /*产生一个HERMIT的节点*/
    auto node = std::make_shared<rclcpp::Node>("HERMIT");
    // 打印一句自我介绍
    RCLCPP_INFO(node->get_logger(), "这里是HERMIT.");
    /* 运行节点,并检测退出信号*/
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

基于OOP的ROS2

#include "rclcpp/rclcpp.hpp"

/*
    创建一个类节点,名字叫做HERMITNode,继承自Node.
*/
class HERMITNode: public rclcpp::Node
{

public:
    // 构造函数,有一个参数为节点名称
    HERMITNode(std::string name) : Node(name)
    {
        // 打印一句自我介绍
        RCLCPP_INFO(this->get_logger(), "这里是%s.",name.c_str());
    }

private:

};

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    /*产生一个HERMIT的节点*/
    auto node = std::make_shared<HERMITNode>("HERMIT");
    /* 运行节点,并检测退出信号*/
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

3. 总结

POP编程是以功能为中心来思考和组织程序,注重功能的实现,达到效果就可以了;而OOP则注重封装,以对象为中心,强调整体性,代码整体变得更规范。我们可以发现ROS这一种机器人系统虽然在OOP的开发下,代码量会增加,但是在主类中所需要处理的任务更少了,这样可以将核心业务中的通用业务,比如日志记录、性能统计、安全控制、事务处理、异常处理等打在不同包中,不在核心业务中呈现。