Intro

A simple ROS Control Hardware Interface for differential drive control of robot whose motors are connected via an Arduino (or similar microcontroller).

This node is designed to provide an interface between a diff_drive_controller from ros_control and an Arduino running firmware from ros_arduino_bridge

Adds ROS2 Galactic and Humble support

This node is designed to provide an interface between a diff_drive_controller from ros_control and an Arduino running firmware from ros_arduino_bridge.

diffdrive_arduino.cpp
#include "diffdrive_arduino/diffdrive_arduino.h"
 
 
#include "hardware_interface/types/hardware_interface_type_values.hpp"
 
 
 
 
DiffDriveArduino::DiffDriveArduino()
    : logger_(rclcpp::get_logger("DiffDriveArduino"))
{}
 
 
 
 
 
return_type DiffDriveArduino::configure(const hardware_interface::HardwareInfo & info)
{
  if (configure_default(info) != return_type::OK) {
    return return_type::ERROR;
  }
 
  RCLCPP_INFO(logger_, "Configuring...");
 
  time_ = std::chrono::system_clock::now();
 
  cfg_.left_wheel_name = info_.hardware_parameters["left_wheel_name"];
  cfg_.right_wheel_name = info_.hardware_parameters["right_wheel_name"];
  cfg_.loop_rate = std::stof(info_.hardware_parameters["loop_rate"]);
  cfg_.device = info_.hardware_parameters["device"];
  cfg_.baud_rate = std::stoi(info_.hardware_parameters["baud_rate"]);
  cfg_.timeout = std::stoi(info_.hardware_parameters["timeout"]);
  cfg_.enc_counts_per_rev = std::stoi(info_.hardware_parameters["enc_counts_per_rev"]);
 
  // Set up the wheels
  l_wheel_.setup(cfg_.left_wheel_name, cfg_.enc_counts_per_rev);
  r_wheel_.setup(cfg_.right_wheel_name, cfg_.enc_counts_per_rev);
 
  // Set up the Arduino
  arduino_.setup(cfg_.device, cfg_.baud_rate, cfg_.timeout);  
 
  RCLCPP_INFO(logger_, "Finished Configuration");
 
  status_ = hardware_interface::status::CONFIGURED;
  return return_type::OK;
}
 
std::vector<hardware_interface::StateInterface> DiffDriveArduino::export_state_interfaces()
{
  // We need to set up a position and a velocity interface for each wheel
 
  std::vector<hardware_interface::StateInterface> state_interfaces;
 
  state_interfaces.emplace_back(hardware_interface::StateInterface(l_wheel_.name, hardware_interface::HW_IF_VELOCITY, &l_wheel_.vel));
  state_interfaces.emplace_back(hardware_interface::StateInterface(l_wheel_.name, hardware_interface::HW_IF_POSITION, &l_wheel_.pos));
  state_interfaces.emplace_back(hardware_interface::StateInterface(r_wheel_.name, hardware_interface::HW_IF_VELOCITY, &r_wheel_.vel));
  state_interfaces.emplace_back(hardware_interface::StateInterface(r_wheel_.name, hardware_interface::HW_IF_POSITION, &r_wheel_.pos));
 
  return state_interfaces;
}
 
std::vector<hardware_interface::CommandInterface> DiffDriveArduino::export_command_interfaces()
{
  // We need to set up a velocity command interface for each wheel
 
  std::vector<hardware_interface::CommandInterface> command_interfaces;
 
  command_interfaces.emplace_back(hardware_interface::CommandInterface(l_wheel_.name, hardware_interface::HW_IF_VELOCITY, &l_wheel_.cmd));
  command_interfaces.emplace_back(hardware_interface::CommandInterface(r_wheel_.name, hardware_interface::HW_IF_VELOCITY, &r_wheel_.cmd));
 
  return command_interfaces;
}
 
 
return_type DiffDriveArduino::start()
{
  RCLCPP_INFO(logger_, "Starting Controller...");
 
  arduino_.sendEmptyMsg();
  // arduino.setPidValues(9,7,0,100);
  // arduino.setPidValues(14,7,0,100);
  arduino_.setPidValues(30, 20, 0, 100);
 
  status_ = hardware_interface::status::STARTED;
 
  return return_type::OK;
}
 
return_type DiffDriveArduino::stop()
{
  RCLCPP_INFO(logger_, "Stopping Controller...");
  status_ = hardware_interface::status::STOPPED;
 
  return return_type::OK;
}
 
hardware_interface::return_type DiffDriveArduino::read()
{
 
  // TODO fix chrono duration
 
  // Calculate time delta
  auto new_time = std::chrono::system_clock::now();
  std::chrono::duration<double> diff = new_time - time_;
  double deltaSeconds = diff.count();
  time_ = new_time;
 
 
  if (!arduino_.connected())
  {
    return return_type::ERROR;
  }
 
  arduino_.readEncoderValues(l_wheel_.enc, r_wheel_.enc);
 
  double pos_prev = l_wheel_.pos;
  l_wheel_.pos = l_wheel_.calcEncAngle();
  l_wheel_.vel = (l_wheel_.pos - pos_prev) / deltaSeconds;
 
  pos_prev = r_wheel_.pos;
  r_wheel_.pos = r_wheel_.calcEncAngle();
  r_wheel_.vel = (r_wheel_.pos - pos_prev) / deltaSeconds;
 
 
 
  return return_type::OK;
 
  
}
 
hardware_interface::return_type DiffDriveArduino::write()
{
 
  if (!arduino_.connected())
  {
    return return_type::ERROR;
  }
 
  arduino_.setMotorValues(l_wheel_.cmd / l_wheel_.rads_per_count / cfg_.loop_rate, r_wheel_.cmd / r_wheel_.rads_per_count / cfg_.loop_rate);
 
 
 
 
  return return_type::OK;
 
 
  
}
 
 
 
#include "pluginlib/class_list_macros.hpp"
 
PLUGINLIB_EXPORT_CLASS(
  DiffDriveArduino,
  hardware_interface::SystemInterface
)