laser_rotate3D.h
Go to the documentation of this file.
1 /**************************************************************************************************
2  Software License Agreement (BSD License)
3 
4  Copyright (c) 2011-2013, LAR toolkit developers - University of Aveiro - http://lars.mec.ua.pt
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without modification, are permitted
8  provided that the following conditions are met:
9 
10  *Redistributions of source code must retain the above copyright notice, this list of
11  conditions and the following disclaimer.
12  *Redistributions in binary form must reproduce the above copyright notice, this list of
13  conditions and the following disclaimer in the documentation and/or other materials provided
14  with the distribution.
15  *Neither the name of the University of Aveiro nor the names of its contributors may be used to
16  endorse or promote products derived from this software without specific prior written permission.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 ***************************************************************************************************/
27 /*
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions
30  * are met:
31  * 1. Redistributions of source code must retain the above copyright
32  * notice, this list of conditions and the following disclaimer.
33  * 2. Redistributions in binary form must reproduce the above copyright
34  * notice, this list of conditions and the following disclaimer in the
35  * documentation and/or other materials provided with the distribution.
36  * 3. Neither the name of Ricardo JS Pascoal nor the name of any other
37  * contributor may be used to endorse or promote products derived
38  * from this software without specific prior written permission.
39  *
40  * THIS SOFTWARE IS PROVIDED BY Ricardo JS Pascoal AND CONTRIBUTORS ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED. IN NO EVENT SHALL Ricardo JS Pascoal OR ANY OTHER
44  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
47  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
48  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
49  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
50  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51  */
52 /*
53 
54 */
55 
62 #ifndef _LASER_ROTATE3D_H_
63 #define _LASER_ROTATE3D_H_
64 
65 #define deg2rad 0.017453293 //change this to a standard ros function
66 #define pulse2rad 0.003067962 // convert encoder pulses to radian
67 #define deg2pulse 5.689 //2048/360
68 
69 using namespace serialcom;
70 
76 class RotateLaser: private SerialCom
77 {
78 
79  protected:
80  ros::NodeHandle RotateLaser_nh; // the nodehandler associated with the rotation axis
81 
82  private:
83  /* http://drdobbs.com/cpp/184401518?pgno=2
84 http://www.boost.org/doc/libs/1_37_0/doc/html/interprocess/synchronization_mechanisms.html
85 don't allow the callback to access the variable while it is being used just before sending a message
86 */
87  boost::mutex want2publish_mutex;
88 
89 
90  // data to be transfered from the callback in the read thread to the publisher
91  //std_msgs::String datatopublish; // change accordingly
92  sensor_msgs::JointState joint_state;
93 
96 
97  // serial port specfic data
99  std::string port_name_;
100 
102  char command2send[8]; //may be position or speed
103 
104  // reference frame transformation
105  tf::TransformBroadcaster TransfBroadcaster;
106  tf::Transform Transform2Laser;
107 
108 
109 
110  public:
111  // ROS members
112  //ros::ServiceServer set_speed_srv_, set_position_srv_, set_portandbaud_srv_; TODO use services
113  ros::Publisher RotateLaser_pub;
114  ros::Subscriber RotateLaser_sub;
115 
116  //--------------
117  RotateLaser(); // opens the serial port to enable comm with PIC
118  ~RotateLaser(); // sends the laser to the home position, stop, and closes the serial port
119  bool SetPosition(int desiredposition);
120  bool SetSpeed(int desiredrpm);
121  bool SendCommand(); // send what is in command2send to the PIC
122  void SetJointState(const sensor_msgs::JointState::ConstPtr& set_joint_state);
123  boost::function<void(std::string*)> BoostRotateLaserCallback;
124  void ReadLinesSerialPort(boost::function<void(std::string*)> f);
125  void RotateLaserCallback(std::string* readdata); // callback to be used in the readline thread,
126  //it will publish the information collected from the PIC
127  void Publish(); // change this to make it adequate for the type of message
128 
129 };
130 
137 {
138  stopStream(); //stop the thread, the SerialCom destructor will close it
139 };
140 
146 // RotateLaser::RotateLaser() : RotateLaser_nh("~") // initial values for members
147 RotateLaser::RotateLaser() : RotateLaser_nh("~") // initial values for members
148 {
149  //unlock the mutex
150 // want2publish_mutex.unlock();
151 
152  /*default port name
153  .param Assign value from parameter server, with default. */
154  RotateLaser_nh.param ("port", port_name_, std::string("/default"));
155  RotateLaser_nh.param ("baud", baud_rate_, 115200);
156  std::cout<<"Param port: "<<port_name_<<std::endl;
157 
158  open(port_name_.c_str(),baud_rate_); //opens the serial port for reading and writing, inherited from SerialCom
159 
160  // set initial to home position and zero speed
163  SetPosition(previous_position_request); //send to home
164 
165  ROS_INFO("sent to home");
166 
167  joint_state.header.stamp = ros::Time::now();
168 // joint_state.set_name_size(1);
169  joint_state.name.resize(1);
170 // joint_state.set_position_size(1);
171  joint_state.position.resize(1);
172 // joint_state.set_velocity_size(1);
173  joint_state.velocity.resize(1);
174 
175  joint_state.name[0] =ros::names::remap("shaft");
176  joint_state.position[0] = -1;
177  joint_state.velocity[0] = 0;
178 
179  #if ROS_VERSION_MINIMUM(1, 8, 0)
180  Transform2Laser.setOrigin(tf::Vector3(0,0, 0.0)); //nota estava Transform2Laser.setOrigin( tf::Vector3(0,-1, 0.0) )
181  Transform2Laser.setRotation(tf::Quaternion(0, 0, 0));
182  #else
183  Transform2Laser.setOrigin(btVector3(0,0, 0.0)); //nota estava Transform2Laser.setOrigin( tf::Vector3(0,-1, 0.0) )
184  Transform2Laser.setRotation(btQuaternion(0, 0, 0));
185  #endif
186 
187 // Transform2Laser.setOrigin(tf::Vector3(0,0, 0.0)); //nota estava Transform2Laser.setOrigin( tf::Vector3(0,-1, 0.0) )
188 // Transform2Laser.setRotation(tf::Quaternion(0, 0, 0));
189 
190  printf("remap=%s\n", (ros::names::remap("state")).c_str());
191  // publish the current angular position
192  RotateLaser_pub = RotateLaser_nh.advertise<sensor_msgs::JointState>(ros::names::remap("state"),10); // this advertises the values
193  //sensor_msgs::JointState std_msgs::String
194  // subscribe a command
195  RotateLaser_sub = RotateLaser_nh.subscribe<sensor_msgs::JointState>("cmd",1,&RotateLaser::SetJointState,this);
196  //name, qeue, object member, object type
197 
198  //service to set the serial port and baud rate
199  // set_portandbaud_srv_ = RotateLaser_nh.advertiseService ("port", &RotateLaser::Set, this); TODO make this possible by changing the serial port class
200  //service set speed
201  //set_speed_srv_ = RotateLaser_nh.advertiseService ("speed", &RotateLaser::SetSpeed, this);
202  //service set position
203  //set_position_srv_ = RotateLaser_nh.advertiseService ("position", &RotateLaser::SetPosition, this);
204 
205 
206 };
207 
215 void RotateLaser::SetJointState(const sensor_msgs::JointState::ConstPtr& set_joint_state)
216 {
217 
218  /* it is not possible to request speed and position simultaneously
219  check which request has changed and make that one the active
220  In case both change, give priority to speed requests.
221  */
222 
223  if (set_joint_state->velocity.size()==0)
224  {
225  ROS_WARN("LASER3D VELOCITY REQUEST 0");
226  int position_request = (int)set_joint_state->position[0];
227  int speed_request = (int)set_joint_state->velocity[0];
228  //if(position_request != previous_position_request)
229  {
230  SetPosition((position_request*180./3.14));
231  ROS_INFO("Setting a new position");
232  previous_position_request = position_request;
233  }
234  }
235  else
236  {
237  int position_request = (int)set_joint_state->position[0];
238  int speed_request = (int)set_joint_state->velocity[0];
239  SetSpeed(speed_request);
240  ROS_INFO("Setting a new speed");
241  previous_speed_request = speed_request;
242  previous_position_request = position_request;
243  }
244 
245 };
246 
251 bool RotateLaser::SetPosition(int desiredposition)
252 {
253  //send a command that sets the position of the laser
254  //position is in degrees
255  if ((desiredposition>359) | (desiredposition<0))
256  {
257  ROS_WARN("Demanded position is in integer degrees range {0,...,359}.");
258  return false;
259  }
260 
261  if(desiredposition==0)
262  {
263  command2send[0] = 'h'; // go to home
264  command2send[1] = '\r';
265  sizeofcommand = 2;
266  // sendthecommand
267  return SendCommand();
268  };
269 
270  // common part of the command
271  command2send[0] = 'v';
272  command2send[1] = '1';
273  command2send[2] = 'p'; //position
274 
275  desiredposition = round(desiredposition*deg2pulse); // PIC is expecting pulse count
276 
277  //itoa(desiredposition,command2send[3],10); //this is a nonstandard function
278  sprintf(command2send+3,"%d",desiredposition);
279  sizeofcommand = strlen(command2send);
280  //ROS_INFO("position command received : %s", command2send);
281  command2send[sizeofcommand] = '\r';
282  sizeofcommand+=1;
283 
284  return SendCommand();
285 }
286 
287 
292 bool RotateLaser::SetSpeed(int desiredrpm)
293 {
294  //send a command that sets the angular rate of the laser RPM.
295  if ((desiredrpm>19) & (desiredrpm<100))
296  {
297  command2send[0] = 'v';
298  command2send[1] = '1';
299  command2send[2] = 's';
300  command2send[3] = (desiredrpm - desiredrpm%10)/10 + 48;
301  command2send[4] = desiredrpm%10 + 48; // 48 is the ascii value for 0
302  command2send[5] = '\r';
303  sizeofcommand = 6;
304  return (SendCommand());
305  }
306  else
307  {
308  ROS_WARN("Demanded speed is in integer rpm range {20,...,99}.");
309  return false;
310  };
311 
312 }
313 
319 {
320 
322  {
323  ROS_WARN ("Error writing the command!");
324  return false;
325  }
326  else
327  {
328  return true;
329  }
330 };
331 
336 void RotateLaser::ReadLinesSerialPort(boost::function<void(std::string*)> f)
337 {
338  startReadLineStream(f); //start a stream (thread) for reading from the serial port, inherited from SerialCom
339 };
340 
345 void RotateLaser::Publish() //publish data safely
346 {
347 
348  if(want2publish_mutex.try_lock())
349  {
350  // also lock in the callback for reading the serial port
351  // it is safe to do whatever is needed with msg
352  //ROS_INFO("safe publishing %s \n", "main thread");//readdata->c_str);
353  if(joint_state.position[0]>=0) //it is initialized with -1
354  {
355  // publish the position as a change in a joint_state
356  RotateLaser_pub.publish(joint_state);
357  // publish the position as a change in reference frame
358 
359  #if ROS_VERSION_MINIMUM(1, 8, 0)
360  Transform2Laser.setOrigin( tf::Vector3(0,0.0, 0.0) ); //nota estava Transform2Laser.setOrigin( tf::Vector3(0,-1, 0.0) )
361  #else
362  Transform2Laser.setOrigin(btVector3(0.0,0.0, 0.0)); //nota estava Transform2Laser.setOrigin( tf::Vector3(0,-1, 0.0) )
363  #endif
364 
365 // Transform2Laser.setOrigin( tf::Vector3(1,0, 0.0) ); //nota estava Transform2Laser.setOrigin( tf::Vector3(0,-1, 0.0) )
366 
367  Transform2Laser.setRotation( tf::createQuaternionFromRPY(joint_state.position[0], 0, 0) );
368 // TransfBroadcaster.sendTransform(tf::StampedTransform(Transform2Laser, joint_state.header.stamp, "/atc/laser/roof_rotating", "/atc/laser/roof_rotating/base"));
369  TransfBroadcaster.sendTransform(tf::StampedTransform(Transform2Laser, joint_state.header.stamp, "/atc/laser/roof_rotating/base", "/atc/laser/roof_rotating"));
370 
371  want2publish_mutex.unlock();
372 // ROS_INFO("publishing %s\n","");
373  }
374  else
375  {
376  ROS_INFO("no data available to publish %s\n","");
377  want2publish_mutex.unlock();
378  }
379  }
380 };
381 
382 
383 void RotateLaser::RotateLaserCallback(std::string* readdata)
384  // this function is called back once the readline thread is invoked
385 {
386  int thesize;
387  int aux;
388  char Pos[1024];
389  char Vel[1024];
390  thesize = readdata->size();
391 
392  // for now print on screen what has been read
393 
394  //ROS_INFO("In the rotatelaser callback");
395 
396  // if it is not locked then
397  // have to pass the information in order to safely allow publishing
398  // copy the message to a new variable and unlock
399  // ROS_INFO("in callback string size %s \n", readdata->c_str());//readdata->c_str);
400 
401  joint_state.header.stamp = ros::Time::now();
402 
403 // joint_state.position[0] = atof(readdata->c_str())*pulse2rad;
404  //ROS_INFO("value read %f :", joint_state.position[0]);
405  /*std::stringstream ss;
406  ss << "collected in the callback";
407  datatopublish.data = ss.str();*/
408 
409  //get the posistion in the string P posistion V velocity
410  aux=sscanf(readdata->c_str(),"%*c %s %*c %s\n",Pos,Vel);
411 // ROS_INFO("value read: %s , atof: %f, converted: &f\n", Pos,atof(Pos),atof(Pos)*pulse2rad);
412 // std::cout<<"value read: "<<Pos<<" atof: "<<atof(Pos)<<" converted: "<<atof(Pos)*pulse2rad<<std::endl;
413 
414  want2publish_mutex.lock();
415 
416  joint_state.position[0] = atof(Pos)*pulse2rad;
417  joint_state.velocity[0] = atof(Vel);
418  want2publish_mutex.unlock();
419  usleep(10);
420 
421  Publish(); //new change 2013 - 11 april
422 };
423 
424 
425 #endif //EOF
bool SetPosition(int desiredposition)
SetPosition set the external angular position of the laser.
boost::mutex want2publish_mutex
bool SendCommand()
SendCommand send a command to the PIC controlling the stepper motor.
void RotateLaserCallback(std::string *readdata)
#define deg2pulse
void ReadLinesSerialPort(boost::function< void(std::string *)> f)
ReadLinesSerialPort thread to read from the serial port, inherited from SerialCom.
bool SetSpeed(int desiredrpm)
SetSpeed set the external angular velocity of the laser.
int previous_speed_request
tf::Transform Transform2Laser
int previous_position_request
RotateLaser()
constructor
ros::Subscriber RotateLaser_sub
char command2send[8]
void SetJointState(const sensor_msgs::JointState::ConstPtr &set_joint_state)
SetJointState selects setting the angular position or rate for the external LM200 joint calls SetSpee...
sensor_msgs::JointState joint_state
#define pulse2rad
boost::function< void(std::string *)> BoostRotateLaserCallback
ros::Publisher RotateLaser_pub
ros::NodeHandle RotateLaser_nh
std::string port_name_
tf::TransformBroadcaster TransfBroadcaster
class implements a gateway to communicate with the PIC to rotate the LMS200
~RotateLaser()
destructor
void Publish()
Publish mutex protected publish.


laser_rotate_3d
Author(s): Ricardo Pascoal
autogenerated on Mon Mar 2 2015 01:32:06