swerve.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2021, Qiayuan Liao
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *******************************************************************************/
33 
34 //
35 // Created by qiayuan on 4/23/21.
36 //
37 
39 
40 #include <angles/angles.h>
42 
43 namespace rm_chassis_controllers
44 {
46  ros::NodeHandle& controller_nh)
47 {
48  if (!ChassisBase::init(robot_hw, root_nh, controller_nh))
49  return false;
50  XmlRpc::XmlRpcValue modules;
51  controller_nh.getParam("modules", modules);
53  for (const auto& module : modules)
54  {
55  ROS_ASSERT(module.second.hasMember("position"));
56  ROS_ASSERT(module.second["position"].getType() == XmlRpc::XmlRpcValue::TypeArray);
57  ROS_ASSERT(module.second["position"].size() == 2);
58  ROS_ASSERT(module.second.hasMember("pivot"));
59  ROS_ASSERT(module.second["pivot"].getType() == XmlRpc::XmlRpcValue::TypeStruct);
60  ROS_ASSERT(module.second.hasMember("wheel"));
61  ROS_ASSERT(module.second["wheel"].getType() == XmlRpc::XmlRpcValue::TypeStruct);
62  ROS_ASSERT(module.second["wheel"].hasMember("radius"));
63 
64  Module m{ .position_ = Vec2<double>((double)module.second["position"][0], (double)module.second["position"][1]),
65  .pivot_offset_ = module.second["pivot"]["offset"],
66  .wheel_radius_ = module.second["wheel"]["radius"],
68  .ctrl_wheel_ = new effort_controllers::JointVelocityController() };
69  ros::NodeHandle nh_pivot = ros::NodeHandle(controller_nh, "modules/" + module.first + "/pivot");
70  ros::NodeHandle nh_wheel = ros::NodeHandle(controller_nh, "modules/" + module.first + "/wheel");
71  if (!m.ctrl_pivot_->init(effort_joint_interface_, nh_pivot) ||
72  !m.ctrl_wheel_->init(effort_joint_interface_, nh_wheel))
73  return false;
74  if (module.second["pivot"].hasMember("offset"))
75  m.pivot_offset_ = module.second["pivot"]["offset"];
76  joint_handles_.push_back(m.ctrl_pivot_->joint_);
77  joint_handles_.push_back(m.ctrl_wheel_->joint_);
78  modules_.push_back(m);
79  }
80  return true;
81 }
82 
83 // Ref: https://dominik.win/blog/programming-swerve-drive/
84 
85 void SwerveController::moveJoint(const ros::Time& time, const ros::Duration& period)
86 {
87  Vec2<double> vel_center(vel_cmd_.x, vel_cmd_.y);
88  for (auto& module : modules_)
89  {
90  Vec2<double> vel = vel_center + vel_cmd_.z * Vec2<double>(-module.position_.y(), module.position_.x());
91  double vel_angle = std::atan2(vel.y(), vel.x()) + module.pivot_offset_;
92  // Direction flipping and Stray module mitigation
93  double a = angles::shortest_angular_distance(module.ctrl_pivot_->joint_.getPosition(), vel_angle);
94  double b = angles::shortest_angular_distance(module.ctrl_pivot_->joint_.getPosition(), vel_angle + M_PI);
95  module.ctrl_pivot_->setCommand(std::abs(a) < std::abs(b) ? vel_angle : vel_angle + M_PI);
96  module.ctrl_wheel_->setCommand(vel.norm() / module.wheel_radius_ * std::cos(a));
97  module.ctrl_pivot_->update(time, period);
98  module.ctrl_wheel_->update(time, period);
99  }
100 }
101 
102 geometry_msgs::Twist SwerveController::odometry()
103 {
104  geometry_msgs::Twist vel_data{};
105  geometry_msgs::Twist vel_modules{};
106  for (auto& module : modules_)
107  {
108  geometry_msgs::Twist vel;
109  vel.linear.x = module.ctrl_wheel_->joint_.getVelocity() * module.wheel_radius_ *
110  std::cos(module.ctrl_pivot_->joint_.getPosition());
111  vel.linear.y = module.ctrl_wheel_->joint_.getVelocity() * module.wheel_radius_ *
112  std::sin(module.ctrl_pivot_->joint_.getPosition());
113  vel.angular.z =
114  module.ctrl_wheel_->joint_.getVelocity() * module.wheel_radius_ *
115  std::cos(module.ctrl_pivot_->joint_.getPosition() - std::atan2(module.position_.x(), -module.position_.y()));
116  vel_modules.linear.x += vel.linear.x;
117  vel_modules.linear.y += vel.linear.y;
118  vel_modules.angular.z += vel.angular.z;
119  }
120  vel_data.linear.x = vel_modules.linear.x / modules_.size();
121  vel_data.linear.y = vel_modules.linear.y / modules_.size();
122  vel_data.angular.z =
123  vel_modules.angular.z / modules_.size() /
124  std::sqrt(std::pow(modules_.begin()->position_.x(), 2) + std::pow(modules_.begin()->position_.y(), 2));
125  return vel_data;
126 }
127 
129 } // namespace rm_chassis_controllers
angles::shortest_angular_distance
static double shortest_angular_distance(double from, double to)
swerve.h
ros::NodeHandle::getParam
bool getParam(const std::string &key, bool &b) const
rm_chassis_controllers::SwerveController::moveJoint
void moveJoint(const ros::Time &time, const ros::Duration &period) override
Definition: swerve.cpp:116
rm_chassis_controllers::ChassisBase< rm_control::RobotStateInterface, hardware_interface::EffortJointInterface >::vel_cmd_
geometry_msgs::Vector3 vel_cmd_
Definition: chassis_base.h:200
rm_chassis_controllers::ChassisBase< rm_control::RobotStateInterface, hardware_interface::EffortJointInterface >::effort_joint_interface_
hardware_interface::EffortJointInterface * effort_joint_interface_
Definition: chassis_base.h:177
rm_chassis_controllers::SwerveController::odometry
geometry_msgs::Twist odometry() override
Definition: swerve.cpp:133
XmlRpc::XmlRpcValue::TypeStruct
TypeStruct
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(RobotLocalization::EkfNodelet, nodelet::Nodelet)
effort_controllers::JointVelocityController
controller_interface::ControllerBase
rm_chassis_controllers::SwerveController
Definition: swerve.h:86
hardware_interface::RobotHW
rm_chassis_controllers::SwerveController::modules_
std::vector< Module > modules_
Definition: swerve.h:95
XmlRpc::XmlRpcValue::getType
const Type & getType() const
XmlRpc::XmlRpcValue::TypeArray
TypeArray
Vec2
typename Eigen::Matrix< T, 2, 1 > Vec2
rm_chassis_controllers::SwerveController::init
bool init(hardware_interface::RobotHW *robot_hw, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh) override
Definition: swerve.cpp:76
rm_chassis_controllers::ChassisBase::init
bool init(hardware_interface::RobotHW *robot_hw, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh) override
Get and check params for covariances. Setup odometry realtime publisher + odom message constant field...
Definition: chassis_base.cpp:83
effort_controllers::JointPositionController
ros::Time
rm_chassis_controllers::ChassisBase< rm_control::RobotStateInterface, hardware_interface::EffortJointInterface >::joint_handles_
std::vector< hardware_interface::JointHandle > joint_handles_
Definition: chassis_base.h:178
class_list_macros.hpp
ROS_ASSERT
#define ROS_ASSERT(cond)
ros::Duration
XmlRpc::XmlRpcValue
ros::NodeHandle
angles.h
rm_chassis_controllers
Definition: balance.h:15


rm_chassis_controllers
Author(s): Qiayuan Liao
autogenerated on Sun May 4 2025 02:57:17