This package is a part of the OpenVMP project. But it's designed to be universal and usable independently from the rest of OpenVMP or in a combination with select OpenVMP packages.
This package implements a minimalistic protocol to relay input and output to and from compatible microcontrollers to leverage their I/O connectivity.
The high level features:
- I/O connectivity of microcontrollers is shared with other nodes
- All ROS2 messaging overhead resides on the computer running this package
- Microcontroller is exclusively responsible for I/O operations with the least overhead possible
- Microcontrollers I/O contacts are mapped to ROS2 services and topics using YAML config files
The currently supported I/O channels:
- PWM
- Arbitrary position and velocity control using the ROS2 built-in std_msgs::msg::UInt16
- remote_actuator
- both position and velocity variants are supported
- see remote_hardware_interface for info on how to consume this interface
- PUL and PUL/DIR pulse train generation
- Arbitrary velocity control using the ROS2 built-in std_msgs::msg::Int32 (pulses per second, sign is the direction)
- remote_actuator for velocity control
- see remote_hardware_interface for info on how to consume this interface
- remote_stepper_driver
- pulses per revolution and other parameter tuning
- provides the remote_actuator interface too
- GPIO
- Arbitrary state control using the ROS2 built-in std_msgs::msg::Boolean
- remote_switch
- UART ports
- Arbitrary serial input and output using the ROS2 built-in std_msgs::msg::String
- remote_serial
It currently supports Arduino Mega2560 and Arduino Uno. But it was only tested on Arduino Mega2560.
Support for other Arduino boards can be added with trivial changes. Support for other microcontroller boards would require a little more effort. Contributors are very welcome!
See the details of mapping I/O channels to the pins of the microcontroller here.
Since this package and some of its dependencies are not yet added to ROS2
distribution packages, you will have to clone all of them into the src
folder of your ROS2 workspace.
mkdir src
git clone https://github.com/openvmp/actuator.git src/remote_actuator
git clone https://github.com/openvmp/encoder.git src/remote_encoder
git clone https://github.com/openvmp/switch.git src/remote_switch
git clone https://github.com/openvmp/serial.git src/remote_serial
git clone https://github.com/openvmp/microcontroller.git src/remote_microcontroller
After building the workspace, you can link against this package as a library
// In the declaration of your node class
std::shared_ptr<remote_microcontroller::Implementation> mcu_;
/// In the definition of your node class
#include <remote_microcontroller/factory.hpp>
...
mcu_ = remote_microcontroller::Factory::New(this, exec); // where exec is the multithreaded executor your node is running in
or run it as a standalone process:
ros2 run remote_microcontroller remote_microcontroller_standalone ...
In both cases the following parameters need to be provided:
- microcontroller_config: path to the configuration file
- serial_is_remote: false
- serial_dev_name: i.e. /dev/ttyACM0
- serial_baud_rate: i.e. 115200
See remote_serial for more serial port parameters if needed.
Here is an example of the configuration file for controlling a single servo:
pwm:
- channel: 0 # maps to pin 2 on Arduino Mega2560 and pin 3 on Arduino Uno
type: simple_pwm # fixed value, one of several supported types
name: actuator0 # this will be used to produce the node name, no need to match with any other values
prefix: /pwm0 # where to expose ROS2 interfaces
pwm_min: 0
pwm_max: 255
If this configuration file is used, then the following command can be used to control the servo motor:
ros2 topic pub /pwm0/pwm std_msgs/msg/UInt16 '{"data":150}'
The following packages are needed to integrate with ros2_control
:
git clone https://github.com/openvmp/remote_hardware_interface.git src/remote_hardware_interface
Add the following section to the URDF file:
<ros2_control name="HardwareSystem" type="system">
<hardware>
<plugin>remote_hardware_interface/RemoteSystemInterface</plugin>
<param name="namespace">/robot</param>
</hardware>
<joint name="joint0">
<command_interface name="velocity" />
</joint>
</ros2_control>
Add the following into ros2_controllers.yaml
:
controller_manager:
ros__parameters:
update_rate: 20 # match this value with your performance expectations
velocity_controller:
type: velocity_controllers/JointGroupVelocityController
velocity_controller:
ros__parameters:
joints:
- joint0
Use the following configuration file (note that simple_pwm
is replaced with actuator_position
which provides the interface consumed by remote_hardware_interface
)
pwm:
- channel: 0 # maps to the pin 2 on Mega2560 and the pin 3 on Uno
type: actuator_velocity # can be "actuator_position" depending on the type of servo
name: joint0 # this will be used to produce the node name, no need to match with any other values
prefix: /robot/actuator/joint0 # namespace + "/actuator/" + joint name
actuator_velocity_min: -3.14 # or "actuator_position_min"
actuator_velocity_max: 3.14 # or "actuator_position_max"
pwm_min: 0
pwm_max: 255
Please, note, if the channel is not specified explicitly then the natural order of channels is assumed (the first YAML entry is the channel 0, the second one is the channel 1 etc).
Now launch your robot and let ros2_control
do the work.
ros2 topic pub /velocity_controller/commands std_msgs/msg/Float64MultiArray '{"data":[1.0]}'
Unlike this package, micro-ROS implements DDS messaging middleware on the microcontroller itself, allowing it to communicate with other ROS2 nodes over intermittent and lossy connections.
In some designs where the microcontroller is permanently connected to a more powerful computer (even a Raspberry Pi), there is no benefit in using the constrained resources of a microcontroller to run DDS and to handle all the ROS2 messaging overhead. If the system is designed in a way so that the worst case scenario traffic does not saturate the permanent channel between the computer and the microcontroller, then it's better to delegate messaging functionality to the computer.
If there is no permanent connection to the computer or if the worst case scenario may saturate the channel (and it is believed that QoS features will save the day), then it's better to use micro-ROS instead of this package.