Program Listing for File servo_state_publisher.hpp

Return to documentation for file (/tmp/ws/src/mavros/mavros_extras/include/mavros_extras/servo_state_publisher.hpp)

/*
 * Copyright 2021 Vladimir Ermakov.
 *
 * This file is part of the mavros package and subject to the license terms
 * in the top-level LICENSE file of the mavros repository.
 * https://github.com/mavlink/mavros/tree/master/LICENSE.md
 */
#pragma once

#ifndef MAVROS_EXTRAS__SERVO_STATE_PUBLISHER_HPP_
#define MAVROS_EXTRAS__SERVO_STATE_PUBLISHER_HPP_

#include <yaml-cpp/yaml.h>
#include <urdf/model.h>

#include <algorithm>
#include <memory>
#include <string>
#include <list>
#include <shared_mutex>  // NOLINT

#include "rclcpp/macros.hpp"
#include "rclcpp/rclcpp.hpp"

#include "std_msgs/msg/string.hpp"
#include "mavros_msgs/msg/rc_out.hpp"
#include "sensor_msgs/msg/joint_state.hpp"

namespace mavros
{
namespace extras
{

class ServoDescription
{
public:
  std::string joint_name;
  float joint_lower;
  float joint_upper;

  size_t rc_channel;

  uint16_t rc_min;
  uint16_t rc_max;
  uint16_t rc_trim;
  uint16_t rc_dz;
  bool rc_rev;

  explicit ServoDescription(std::string joint_name_ = {})
  : joint_name(joint_name_),
    joint_lower(-M_PI / 4),
    joint_upper(M_PI / 4),
    rc_channel(0),
    rc_min(1000),
    rc_max(2000),
    rc_trim(1500),
    rc_dz(0),
    rc_rev(false)
  {}

  ServoDescription(urdf::Model & model, std::string joint_name_, YAML::Node config);

  inline float normalize(uint16_t pwm)
  {
    // 1) fix bounds
    pwm = std::max(pwm, rc_min);
    pwm = std::min(pwm, rc_max);

    // 2) scale around mid point
    float chan;
    if (pwm > (rc_trim + rc_dz)) {
      chan = (pwm - rc_trim - rc_dz) / static_cast<float>(rc_max - rc_trim - rc_dz);
    } else if (pwm < (rc_trim - rc_dz)) {
      chan = (pwm - rc_trim + rc_dz) / static_cast<float>(rc_trim - rc_min - rc_dz);
    } else {
      chan = 0.0;
    }

    if (rc_rev) {
      chan *= -1;
    }

    if (!std::isfinite(chan)) {
      chan = 0.0;
    }

    return chan;
  }

  inline float calculate_position(uint16_t pwm)
  {
    float channel = normalize(pwm);

    // not sure should i differently map -1..0 and 0..1
    // for now there arduino map() (explicit)
    float position = (channel + 1.0) * (joint_upper - joint_lower) / (1.0 + 1.0) + joint_lower;

    return position;
  }
};

class ServoStatePublisher : public rclcpp::Node
{
public:
  explicit ServoStatePublisher(const std::string & node_name = "servo_state_publisher")
  : ServoStatePublisher(rclcpp::NodeOptions(), node_name) {}

  explicit ServoStatePublisher(
    const rclcpp::NodeOptions & options,
    const std::string & node_name = "servo_state_publisher");

private:
  rclcpp::Subscription<std_msgs::msg::String>::SharedPtr robot_description_sub;
  rclcpp::Subscription<mavros_msgs::msg::RCOut>::SharedPtr rc_out_sub;
  rclcpp::Publisher<sensor_msgs::msg::JointState>::SharedPtr joint_states_pub;

  std::shared_mutex mutex;
  std::list<ServoDescription> servos;

  void robot_description_cb(const std_msgs::msg::String::SharedPtr msg);
  void rc_out_cb(const mavros_msgs::msg::RCOut::SharedPtr msg);
};

}   // namespace extras
}   // namespace mavros

#endif  // MAVROS_EXTRAS__SERVO_STATE_PUBLISHER_HPP_