phidgets_high_speed_encoder.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * ROS driver for Phidgets high speed encoder
5  * Copyright (c) 2010, Bob Mottram
6  * Copyright (c) 2017, Jose Luis Blanco Claraco
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *********************************************************************/
33 
34 #include <ros/ros.h>
35 #include <stdio.h>
36 #include <cstdlib>
37 #include <sstream>
38 #include <std_msgs/String.h>
39 #include <vector>
40 #include <mutex>
41 #include <numeric> // std::accumulate()
42 #include "phidgets_api/encoder.h"
43 
44 #include <sensor_msgs/JointState.h>
45 #include "phidgets_high_speed_encoder/EncoderDecimatedSpeed.h"
46 
47 // (Default=20 Hz) Rate for publishing encoder states
48 double PUBLISH_RATE = 20; // [Hz]
49 // (Default=10) Number of samples for the sliding window average filter of speeds.
51 // (Default=1) Number of "ITERATE" loops without any new encoder tick before resetting the filtered average velocities.
53 
55 {
56  int tickPos = .0;
57  double instantaneousSpeed = .0;
58  std::vector<double> speeds_buffer;
59  bool speed_buffer_updated = false;
61 };
62 std::vector<TStatePerChannel> encoder_states;
63 std::mutex encoder_states_mux;
64 
67 {
68 public:
69  EncoderNode() : phidgets::Encoder()
70  {
71  }
72 
74  {
75  const int serial_number = Phidget::getDeviceSerialNumber();
76  const int version = Phidget::getDeviceVersion();
77  const int num_encoders = Encoder::getEncoderCount();
78  const std::string dev_type = Phidget::getDeviceType();
79  const int num_inputs = Encoder::getInputCount();
80 
81  ROS_INFO("Device type : %s", dev_type.c_str());
82  ROS_INFO("Device serial : %d", serial_number);
83  ROS_INFO("Device version : %d", version);
84  ROS_INFO("Number of encoders: %d", num_encoders);
85  ROS_INFO("Number of inputs : %d", num_inputs);
86  }
87 
88 protected:
89  void attachHandler() override
90  {
91  const int serial_number = Phidget::getDeviceSerialNumber();
92  const std::string name = Phidget::getDeviceName();
93  const int inputcount = Encoder::getEncoderCount();
94 
95  {
96  std::lock_guard<std::mutex> lock(encoder_states_mux);
97  encoder_states.resize(inputcount);
98  }
99  ROS_INFO("%s Serial number %d attached with %d encoders!",
100  name.c_str(), serial_number, inputcount);
101 
102  //the 1047 requires enabling of the encoder inputs, so enable them if this is a 1047
103  for (int i = 0 ; i < inputcount ; i++)
104  Encoder::setEnabled(i, true);
105  }
106 
107  void detachHandler() override
108  {
109  const int serial_number = Phidget::getDeviceSerialNumber();
110  const std::string name = Phidget::getDeviceName();
111  ROS_INFO("%s Serial number %d detached!",
112  name.c_str(), serial_number);
113  }
114 
115  void errorHandler(int ErrorCode) override
116  {
117  ROS_ERROR("Error handled. %d - %s", ErrorCode,
118  Phidget::getErrorDescription(ErrorCode).c_str());
119  }
120 
121  void positionChangeHandler(int index, int time, int positionChange) override
122  {
123  const int Position = Encoder::getPosition(index);
124  ROS_DEBUG("Encoder %d Count %d", index, Position);
125 
126  std::lock_guard<std::mutex> lock(encoder_states_mux);
127  if (index < (int)encoder_states.size())
128  {
129  TStatePerChannel &spc = encoder_states[index];
130  spc.tickPos = Position;
131  spc.instantaneousSpeed = positionChange / (time * 1e-6);
132  spc.speeds_buffer.push_back(spc.instantaneousSpeed);
133  spc.speed_buffer_updated = true;
135  }
136  }
137 
138  void indexHandler(int index, int indexPosition) override
139  {
140 
141  }
142 
143 
144 }; // end EncoderNode
145 
146 int main(int argc, char *argv[])
147 {
148  ros::init(argc, argv, "phidgets_high_speed_encoder");
149  ros::NodeHandle n;
150  ros::NodeHandle nh("~");
151 
152  std::vector<std::string> joint_names = { "joint0", "joint1", "joint2", "joint3" };
153  std::vector<double> joint_tick2rad = { 1.0, 1.0, 1.0, 1.0 };
154  for (unsigned int i = 0; i < joint_names.size(); i++)
155  {
156  char str[100];
157  sprintf(str, "joint%u_name", i);
158  nh.getParam(str, joint_names[i]);
159 
160  sprintf(str, "joint%u_tick2rad", i);
161  nh.getParam(str, joint_tick2rad[i]);
162 
163  ROS_INFO("Channel %u: '%s'='%s'", i, str, joint_names[i].c_str());
164  }
165 
166  int serial_number = -1;
167  if (serial_number == -1)
168  {
169  nh.getParam("serial_number", serial_number);
170  }
171 
172  std::string frame_id;
173  nh.getParam("frame_id", frame_id);
174  ROS_INFO("frame_id = '%s'", frame_id.c_str());
175  nh.getParam("PUBLISH_RATE", PUBLISH_RATE);
176  nh.getParam("SPEED_FILTER_SAMPLES_LEN", SPEED_FILTER_SAMPLES_LEN);
177  nh.getParam("SPEED_FILTER_IDLE_ITER_LOOPS_BEFORE_RESET", SPEED_FILTER_IDLE_ITER_LOOPS_BEFORE_RESET);
178 
179  // First time: create publishers:
180  const std::string topic_path = "joint_states";
181  ROS_INFO("Publishing state to topic: %s", topic_path.c_str());
182 
183  ros::Publisher encoder_pub = n.advertise<sensor_msgs::JointState>(topic_path, 100);
184  std::vector<ros::Publisher> encoder_decimspeed_pubs;
185 
186  // The encoder object instance:
187  EncoderNode encoder_node;
188 
189  //open the device:
190  encoder_node.open(serial_number);
191 
192  // get the program to wait for an encoder device to be attached
193  if (serial_number == -1)
194  {
195  ROS_INFO("Waiting for any High Speed Encoder Phidget to be attached.");
196  }
197  else
198  {
199  ROS_INFO("Waiting for High Speed Encoder Phidget %d to be attached....",
200  serial_number);
201  }
202 
203  const int result = encoder_node.waitForAttachment(10000);
204 
205  if (result != 0)
206  {
207  const auto sError = encoder_node.getErrorDescription(result);
208  ROS_ERROR("Problem waiting for attachment: %s", sError.c_str());
209  return 1; // !=0 exit status means error in main()
210  }
211 
212  encoder_node.display_properties();
213 
214  ros::Rate rate(PUBLISH_RATE);
215  ROS_INFO("Publishing encoder states at %.03f Hz", PUBLISH_RATE);
216  while (ros::ok())
217  {
218  ros::spinOnce();
219  rate.sleep();
220 
221  // Publish:
222  {
223  std::lock_guard<std::mutex> lock(encoder_states_mux);
224  const unsigned int N = encoder_states.size();
225 
226  // First time? We need to create decimated speed publisher here,
227  // once we know how many channel we have. Also, they must be independent
228  // for each channel due to the unsynchronous nature of the filtering
229  // algorithm:
230  if (encoder_decimspeed_pubs.size() != N)
231  {
232  encoder_decimspeed_pubs.resize(N);
233  for (unsigned int i = 0; i < N; i++)
234  {
235  std::string s = topic_path;
236  char buf[100];
237  sprintf(buf, "_ch%u_decim_speed", i);
238  s += buf;
239  ROS_INFO("Publishing decimated speed of channel %u to topic: %s", i, s.c_str());
240  encoder_decimspeed_pubs[i] =
241  n.advertise<phidgets_high_speed_encoder::EncoderDecimatedSpeed>(
242  s,
243  10);
244  }
245  }
246 
247  sensor_msgs::JointState js_msg;
248  static uint32_t seq_cnt = 0;
249  js_msg.header.seq = (seq_cnt++);
250  js_msg.header.stamp = ros::Time::now();
251  js_msg.header.frame_id = frame_id;
252 
253  js_msg.name.resize(N);
254  for (unsigned int i = 0; i < std::min<size_t>(joint_names.size(), N); i++)
255  js_msg.name[i] = joint_names[i];
256 
257  js_msg.position.resize(N);
258  js_msg.velocity.resize(N);
259  js_msg.effort.clear();
260 
261  for (unsigned int i = 0; i < N; i++)
262  {
264 
265  js_msg.position[i] = spc.tickPos * joint_tick2rad[i];
266  js_msg.velocity[i] = spc.instantaneousSpeed * joint_tick2rad[i];
267 
268  spc.instantaneousSpeed = 0; // Reset speed
269 
270  if (SPEED_FILTER_SAMPLES_LEN > 0)
271  {
272  if (!spc.speed_buffer_updated)
273  {
275  {
276  phidgets_high_speed_encoder::EncoderDecimatedSpeed e;
277  e.header.stamp = ros::Time::now();
278  e.header.frame_id = frame_id;
279  e.avr_speed = .0;
280  encoder_decimspeed_pubs[i].publish(e);
281  }
282  }
283  else
284  {
286 
287  if (int(spc.speeds_buffer.size()) >= SPEED_FILTER_SAMPLES_LEN)
288  {
289  const double avrg = std::accumulate(spc.speeds_buffer.begin(), spc.speeds_buffer.end(), 0.0) / spc.speeds_buffer.size();
290  spc.speeds_buffer.clear();
291 
292  phidgets_high_speed_encoder::EncoderDecimatedSpeed e;
293  e.header.stamp = ros::Time::now();
294  e.header.frame_id = frame_id;
295  e.avr_speed = avrg * joint_tick2rad[i];
296  encoder_decimspeed_pubs[i].publish(e);
297  }
298  }
299  }
300  }
301 
302  encoder_pub.publish(js_msg);
303 
304  } // end lock guard
305  } // end while ros::ok()
306 
307  return 0;
308 }
std::vector< double > speeds_buffer
XmlRpcServer s
void detachHandler() override
unsigned int loops_without_update_speed_buffer
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
int open(int serial_number)
int waitForAttachment(int timeout)
static std::string getErrorDescription(int errorCode)
double PUBLISH_RATE
void indexHandler(int index, int indexPosition) override
void attachHandler() override
#define ROS_INFO(...)
ROSCPP_DECL bool ok()
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool sleep()
int SPEED_FILTER_IDLE_ITER_LOOPS_BEFORE_RESET
int main(int argc, char *argv[])
void errorHandler(int ErrorCode) override
std::vector< TStatePerChannel > encoder_states
bool getParam(const std::string &key, std::string &s) const
static Time now()
int SPEED_FILTER_SAMPLES_LEN
void positionChangeHandler(int index, int time, int positionChange) override
std::mutex encoder_states_mux
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
#define ROS_DEBUG(...)


phidgets_high_speed_encoder
Author(s): Geoff Viola
autogenerated on Tue May 7 2019 03:19:26