Architecture
The architecture of the ROS2 CANopen stack is based on the composition concept of ROS2. In ROS2 components are dynamically loadable ROS2 nodes which are loaded by a component manager.
Device Container
The core of the ROS2 CANopen stack is the ros2_canopen::DeviceContainer which implements the rclcpp::ComponentManager class. The DeviceContainer enables loading drivers for the CANopen master and the devices on the bus, that have been exported as rclcpp_components. CANopen Master drivers need to implement the ros2_canopen::CanopenMasterInterface, CANopen Device drivers need to implement the ros2_canopen::CanopenDriverInterface.
The difference between the ros2_canopen::DeviceContainer and the rclcpp::ComponentContainer is that the device container loads only master and driver components specified in the bus configuration (bus.yml). It does not have services for loading components online. All components that are connected or will be connected to the CANopen Bus need to be known and specified in the bus.yml before starting the device container.
The device container will first load the master specified in the bus configuration. Then it will load the drivers specified in the bus configuration. If the master and drivers specified in the bus configuration are managed nodes it will as well load the ros2_canopen::LifecycleManager.
CANopen Master Driver Architecture
The architecture for CANopen master drivers looks as depicted in the class diagram. All master drivers consist of three main classes.
The first class is the functionality class that contains the drivers functionailities independently of the ROS2 node type. This class needs to implement the ros2_canopen::node_interfaces::NodeCanopenMasterInterface. ros2_canopen::node_interfaces::NodeCanopenMaster is an abstract class that provides some useful functionality and implements the ros2_canopen::node_interfaces::NodeCanopenMasterInterface. Usually, master drivers will inherit from ros2_canopen::node_interfaces::NodeCanopenMaster.
The second class is the class that wraps the functionality class in a rclcpp::Node. This class should implement the ros2_canopen::CanopenMasterInterface. The canopen_core package provides a convenience class ros2_canopen::CanopenMaster that should be inherited from and implements the ros2_canopen::CanopenMasterInterface.
The third class is the class that wraps the functionality class in a rclcpp_lifecycle::LifecycleNode. This class should implement the ros2_canopen::CanopenMasterInterface. The canopen_core package provides a convenience class ros2_canopen::LifecycleCanopenMaster that should be inherited from and implements the ros2_canopen::CanopenMasterInterface.
CANopen Device Driver Architecture
The architecture for CANopen device drivers looks as depicted in the class diagram. All device drivers consist of three main classes.
The first class is the functionality class that contains the drivers functionailities independently of the ROS2 node type. This class needs to implement the ros2_canopen::node_interfaces::NodeCanopenDriverInterface. ros2_canopen::node_interfaces::NodeCanopenDriver is an abstract class that provides some useful functionality and implements the ros2_canopen::node_interfaces::NodeCanopenDriverInterface. If you plan to write a driver from scratch based on Lely Core library, your functionality class should inherit from ros2_canopen::node_interfaces::NodeCanopenDriver. If you want to use the existing lely_driver_bridge, your functionality class should inherit from ros2_canopen::NodeCanopenBaseDriver.
The second class is the class that wraps the functionality class in a rclcpp::Node. This class should implement the ros2_canopen::CanopenDriverInterface. The canopen_core package provides a convenience class ros2_canopen::CanopenDriver that should be inherited from and implements the ros2_canopen::CanopenDriverInterface.
The third class is the class that wraps the functionality class in a rclcpp_lifecycle::LifecycleNode. This class should implement the ros2_canopen::CanopenDriverInterface. The canopen_core package provides a convenience class ros2_canopen::LifecycleCanopenDriver that should be inherited from and implements the ros2_canopen::CanopenDriverInterface.