cm_740_module.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright 2017 ROBOTIS CO., LTD.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16 
17 /* Author: Kayman */
18 
19 #include <stdio.h>
21 
22 namespace robotis_op
23 {
24 
26  : control_cycle_msec_(8),
27  DEBUG_PRINT(false),
28  present_volt_(0.0)
29 {
30  module_name_ = "cm_740_module"; // set unique module name
31 
32  result_["gyro_x"] = 0.0;
33  result_["gyro_y"] = 0.0;
34  result_["gyro_z"] = 0.0;
35 
36  result_["acc_x"] = 0.0;
37  result_["acc_y"] = 0.0;
38  result_["acc_z"] = 0.0;
39 
40  result_["button_mode"] = 0;
41  result_["button_start"] = 0;
42 
43  result_["present_voltage"] = 0.0;
44  buttons_["button_mode"] = false;
45  buttons_["button_start"] = false;
46  buttons_["published_mode"] = false;
47  buttons_["published_start"] = false;
48 
50 }
51 
53 {
54  queue_thread_.join();
55 }
56 
57 void CM740Module::initialize(const int control_cycle_msec, robotis_framework::Robot *robot)
58 {
59  control_cycle_msec_ = control_cycle_msec;
60  queue_thread_ = boost::thread(boost::bind(&CM740Module::queueThread, this));
61 }
62 
64 {
65  ros::NodeHandle ros_node;
66  ros::CallbackQueue callback_queue;
67 
68  ros_node.setCallbackQueue(&callback_queue);
69 
70  /* publisher */
71  status_msg_pub_ = ros_node.advertise<robotis_controller_msgs::StatusMsg>("/robotis/status", 1);
72  imu_pub_ = ros_node.advertise<sensor_msgs::Imu>("/robotis/cm_740/imu", 1);
73  button_pub_ = ros_node.advertise<std_msgs::String>("/robotis/cm_740/button", 1);
74 
75  ros::WallDuration duration(control_cycle_msec_ / 1000.0);
76  while (ros_node.ok())
77  callback_queue.callAvailable(duration);
78 }
79 
80 void CM740Module::process(std::map<std::string, robotis_framework::Dynamixel *> dxls,
81  std::map<std::string, robotis_framework::Sensor *> sensors)
82 {
83  if (sensors["cm-740"] == NULL)
84  return;
85 
86  uint16_t gyro_x = sensors["cm-740"]->sensor_state_->bulk_read_table_["gyro_x"];
87  uint16_t gyro_y = sensors["cm-740"]->sensor_state_->bulk_read_table_["gyro_y"];
88  uint16_t gyro_z = sensors["cm-740"]->sensor_state_->bulk_read_table_["gyro_z"];
89 
90  uint16_t acc_x = sensors["cm-740"]->sensor_state_->bulk_read_table_["acc_x"];
91  uint16_t acc_y = sensors["cm-740"]->sensor_state_->bulk_read_table_["acc_y"];
92  uint16_t acc_z = sensors["cm-740"]->sensor_state_->bulk_read_table_["acc_z"];
93 
94  uint16_t present_volt = sensors["cm-740"]->sensor_state_->bulk_read_table_["present_voltage"];
95 
96  result_["gyro_x"] = getGyroValue(gyro_x);
97  result_["gyro_y"] = getGyroValue(gyro_y);
98  result_["gyro_z"] = getGyroValue(gyro_z);
99 
100  ROS_INFO_COND(DEBUG_PRINT, "Gyro : %f, %f, %f", result_["gyro_x"], result_["gyro_y"], result_["gyro_z"]);
101 
102  // align axis of Accelerometer to robot
103  result_["acc_x"] = -getAccValue(acc_y);
104  result_["acc_y"] = getAccValue(acc_x);
105  result_["acc_z"] = -getAccValue(acc_z);
106 
107  ROS_INFO_COND(DEBUG_PRINT, "Acc : %f, %f, %f", result_["acc_x"], result_["acc_y"], result_["acc_z"]);
108 
109  uint8_t button_flag = sensors["cm-740"]->sensor_state_->bulk_read_table_["button"];
110  result_["button_mode"] = button_flag & 0x01;
111  result_["button_start"] = (button_flag & 0x02) >> 1;
112 
113  handleButton("mode");
114  handleButton("start");
115 
116  result_["present_voltage"] = present_volt * 0.1;
117  handleVoltage(result_["present_voltage"]);
118 
119  fusionIMU();
120 }
121 
122 // -500 ~ 500dps, dps -> rps
123 double CM740Module::getGyroValue(int raw_value)
124 {
125  return (raw_value - 512) * 500.0 * 2.0 / 1023 * DEGREE2RADIAN;
126 }
127 
128 // -4.0 ~ 4.0g, 1g = 9.8 m/s^2
129 double CM740Module::getAccValue(int raw_value)
130 {
131  return (raw_value - 512) * 4.0 * 2.0 / 1023;
132 }
133 
135 {
136  // fusion imu data
137  imu_msg_.header.stamp = ros::Time::now();
138  imu_msg_.header.frame_id = "body_link";
139 
140  double filter_alpha = 0.4;
141 
142  //in rad/s
143  long int _value = 0;
144  int _arrd_length = 2;
145  imu_msg_.angular_velocity.x = lowPassFilter(filter_alpha, result_["gyro_x"], imu_msg_.angular_velocity.x);
146  imu_msg_.angular_velocity.y = lowPassFilter(filter_alpha, result_["gyro_y"], imu_msg_.angular_velocity.y);
147  imu_msg_.angular_velocity.z = lowPassFilter(filter_alpha, result_["gyro_z"], imu_msg_.angular_velocity.z);
148 
149  //in m/s^2
150  imu_msg_.linear_acceleration.x = lowPassFilter(filter_alpha, result_["acc_x"] * G_ACC,
151  imu_msg_.linear_acceleration.x);
152  imu_msg_.linear_acceleration.y = lowPassFilter(filter_alpha, result_["acc_y"] * G_ACC,
153  imu_msg_.linear_acceleration.y);
154  imu_msg_.linear_acceleration.z = lowPassFilter(filter_alpha, result_["acc_z"] * G_ACC,
155  imu_msg_.linear_acceleration.z);
156 
157  //Estimation of roll and pitch based on accelometer data, see http://www.nxp.com/files/sensors/doc/app_note/AN3461.pdf
158  double mui = 0.01;
159  double sign = copysignf(1.0, result_["acc_z"]);
160  double roll = atan2(result_["acc_y"],
161  sign * sqrt(result_["acc_z"] * result_["acc_z"] + mui * result_["acc_x"] * result_["acc_x"]));
162  double pitch = atan2(-result_["acc_x"],
163  sqrt(result_["acc_y"] * result_["acc_y"] + result_["acc_z"] * result_["acc_z"]));
164  double yaw = 0.0;
165 
166  Eigen::Quaterniond orientation = robotis_framework::convertRPYToQuaternion(roll, pitch, yaw);
167 
168  imu_msg_.orientation.x = orientation.x();
169  imu_msg_.orientation.y = orientation.y();
170  imu_msg_.orientation.z = orientation.z();
171  imu_msg_.orientation.w = orientation.w();
172 
174 }
175 
176 void CM740Module::handleButton(const std::string &button_name)
177 {
178  std::string button_key = "button_" + button_name;
179  std::string button_published = "published_" + button_name;
180 
181  bool pushed = (result_[button_key] == 1.0);
182  // same state
183  if (buttons_[button_key] == pushed)
184  {
185  if (pushed == true && buttons_[button_published] == false)
186  {
187  // check long press
188  ros::Duration button_duration = ros::Time::now() - buttons_press_time_[button_name];
189  if (button_duration.toSec() > 2.0)
190  {
191  publishButtonMsg(button_name + "_long");
192  buttons_[button_published] = true;
193  }
194  }
195  }
196  else // state is changed
197  {
198  buttons_[button_key] = pushed;
199 
200  if (pushed == true)
201  {
202  buttons_press_time_[button_name] = ros::Time::now();
203  buttons_[button_published] = false;
204  }
205  else
206  {
207  ros::Duration button_duration = ros::Time::now() - buttons_press_time_[button_name];
208 
209  if (button_duration.toSec() < 2) // short press
210  publishButtonMsg(button_name);
211  else
212  // long press
213  ;
214 
215  }
216  }
217 }
218 
219 void CM740Module::publishButtonMsg(const std::string &button_name)
220 {
221  std_msgs::String button_msg;
222  button_msg.data = button_name;
223 
224  button_pub_.publish(button_msg);
225  publishStatusMsg(robotis_controller_msgs::StatusMsg::STATUS_INFO, "Button : " + button_name);
226 }
227 
228 void CM740Module::handleVoltage(double present_volt)
229 {
230  double voltage_ratio = 0.4;
232  (previous_volt_ != 0) ? previous_volt_ * (1 - voltage_ratio) + present_volt * voltage_ratio : present_volt;
233 
234  if (fabs(present_volt_ - previous_volt_) >= 0.1)
235  {
236  // check last published time
237  ros::Time now = ros::Time::now();
238  ros::Duration dur = now - last_msg_time_;
239  if (dur.sec < 1)
240  return;
241 
242  last_msg_time_ = now;
243 
245  std::stringstream log_stream;
246  log_stream << "Present Volt : " << present_volt_ << "V";
248  (present_volt_ < 11.0 ?
249  robotis_controller_msgs::StatusMsg::STATUS_WARN : robotis_controller_msgs::StatusMsg::STATUS_INFO),
250  log_stream.str());
251  ROS_INFO_COND(DEBUG_PRINT, "Present Volt : %fV, Read Volt : %fV", previous_volt_, result_["present_voltage"]);
252  }
253 }
254 
255 void CM740Module::publishStatusMsg(unsigned int type, std::string msg)
256 {
257  robotis_controller_msgs::StatusMsg status_msg;
258  status_msg.header.stamp = ros::Time::now();
259  status_msg.type = type;
260  status_msg.module_name = "SENSOR";
261  status_msg.status_msg = msg;
262 
263  status_msg_pub_.publish(status_msg);
264 }
265 
266 double CM740Module::lowPassFilter(double alpha, double x_new, double x_old)
267 {
268  return alpha * x_new + (1.0 - alpha) * x_old;
269 }
270 
271 }
void publish(const boost::shared_ptr< M > &message) const
ros::Publisher status_msg_pub_
Definition: cm_740_module.h:78
double sign(double x)
Eigen::Quaterniond convertRPYToQuaternion(double roll, double pitch, double yaw)
void publishStatusMsg(unsigned int type, std::string msg)
std::map< std::string, bool > buttons_
Definition: cm_740_module.h:66
boost::thread queue_thread_
Definition: cm_740_module.h:65
ros::Publisher button_pub_
Definition: cm_740_module.h:77
std::map< std::string, ros::Time > buttons_press_time_
Definition: cm_740_module.h:67
double lowPassFilter(double alpha, double x_new, double x_old)
void publishButtonMsg(const std::string &button_name)
void handleVoltage(double present_volt)
std::map< std::string, double > result_
void process(std::map< std::string, robotis_framework::Dynamixel * > dxls, std::map< std::string, robotis_framework::Sensor * > sensors)
void setCallbackQueue(CallbackQueueInterface *queue)
#define DEGREE2RADIAN
double getAccValue(int raw_value)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void initialize(const int control_cycle_msec, robotis_framework::Robot *robot)
#define ROS_INFO_COND(cond,...)
double getGyroValue(int raw_value)
static Time now()
bool ok() const
sensor_msgs::Imu imu_msg_
Definition: cm_740_module.h:73
ros::Publisher imu_pub_
Definition: cm_740_module.h:76
void handleButton(const std::string &button_name)


cm_740_module
Author(s): Kayman
autogenerated on Mon Jun 10 2019 14:41:03