laser_transform_core.cpp
Go to the documentation of this file.
00001 #include <iostream>
00002 #include <sstream>
00003 #include <fstream>
00004 #include <cmath>
00005 #include <stdio.h>
00006 #include <sys/types.h>
00007 #include <sys/stat.h>
00008 #include <fcntl.h>
00009 #include <termios.h>
00010 #include "ros/ros.h"
00011 #include "laser_transform_core.h"
00012 #include "pcl_ros/transforms.h"
00013 #include "sensor_msgs/PointCloud2.h"
00014 #include "sensor_msgs/NavSatFix.h"
00015 #include "sensor_msgs/Imu.h"
00016 #include "sensor_msgs/MagneticField.h"
00017 #include "nav_msgs/Odometry.h"
00018 #include <geodesy/wgs84.h>
00019 #include <geodesy/utm.h>
00020 #include <geometry_msgs/Point.h>
00021 #include "ip_connection.h"
00022 #include "brick_imu.h"
00023 #include "brick_imu_v2.h"
00024 #include "bricklet_gps.h"
00025 #include "bricklet_industrial_digital_in_4.h"
00026 #include "bricklet_dual_button.h"
00027 #include <tf/transform_broadcaster.h>
00028 #include "octomap_msgs/BoundingBoxQuery.h"
00029 
00030 #define HOST "localhost"
00031 #define PORT 4223
00032 
00033 #define GPS_LOGFILE false
00034 #define VELO_LOGFILE false
00035 #define FULL_SENSOR_LOGFILE true
00036 #define TIME_TO_STOP 3
00037 #define LOGFILE_PATH "/home/vmuser/logs/"
00038 
00039 /*----------------------------------------------------------------------
00040  * LaserTransform()
00041  * Constructor
00042  *--------------------------------------------------------------------*/
00043 
00044 LaserTransform::LaserTransform()
00045 {
00046   publish_new_pcl = false;
00047   is_imu_connected = false;
00048   is_imu_v2_connected = false;
00049   is_gps_connected = false;
00050   is_idi4_connected = false;
00051   isMeasure = false;
00052   new_pcl_filtered = false;
00053   isPlc = false;
00054   start_latitude = 0;
00055   start_longitude = 0;
00056   velocity = 0.0;
00057   velocity_gps = 0.0;
00058   imu_convergence_speed = 0;
00059   rev = 0.0;
00060   last_rev = ros::Time::now();
00061 
00062   xpos = ypos = 0;
00063 
00064   std::stringstream ss;
00065 
00066   time_t t;
00067   struct tm *ts;
00068   char buff[80];
00069 
00070   // build filename
00071   t = time(NULL);
00072   ts = localtime(&t);
00073 
00074   // open gps log file
00075   if (GPS_LOGFILE)
00076   {
00077     strftime(buff, 80, "gps_log_%Y_%m_%d-%H_%M_%S.txt", ts);
00078     ss << LOGFILE_PATH << buff;
00079 
00080     gps_log.open(ss.str().c_str(), std::ios::out);
00081   }
00082 
00083   // open velocity log file
00084   if (VELO_LOGFILE)
00085   {
00086     strftime(buff, 80, "velo_log_%Y_%m_%d-%H_%M_%S.txt", ts);
00087     ss << LOGFILE_PATH << buff;
00088 
00089     velo_log.open(ss.str().c_str(), std::ios::out);
00090   }
00091 }
00092 
00093 /*----------------------------------------------------------------------
00094  * ~LaserTransform()
00095  * Destructor
00096  *--------------------------------------------------------------------*/
00097 
00098 LaserTransform::~LaserTransform()
00099 {
00100   // clean up tf devices
00101   if (is_imu_connected)
00102   {
00103     imu_leds_off(&imu);
00104     imu_destroy(&imu);
00105   }
00106   if (is_imu_v2_connected)
00107   {
00108     imu_v2_leds_off(&imu_v2);
00109     imu_v2_destroy(&imu_v2);
00110   }
00111   if (is_gps_connected)
00112   {
00113     gps_destroy(&gps);
00114   }
00115   if (is_idi4_connected)
00116   {
00117     industrial_digital_in_4_destroy(&idi4);
00118   }
00119   if (is_imu_v2_connected || is_imu_connected || is_idi4_connected ||
00120       is_gps_connected)
00121   {
00122     ipcon_destroy(&ipcon);
00123   }
00124   // close gps logfile
00125   if (gps_log.is_open())
00126     gps_log.close();
00127   // close velo logfile
00128   if (velo_log.is_open())
00129     velo_log.close();
00130 }
00131 
00132 /*----------------------------------------------------------------------
00133  * Init()
00134  * Init the TF-Devices
00135  *--------------------------------------------------------------------*/
00136 
00137 int LaserTransform::init()
00138 {
00139   // create IP connection
00140   ipcon_create(&ipcon);
00141 
00142   // connect to brickd
00143   if(ipcon_connect(&ipcon, HOST, PORT) < 0) {
00144     std::cout << "could not connect to brickd!" << std::endl;
00145     return false;
00146   }
00147 
00148   // register connected callback to "cb_connected"
00149   ipcon_register_callback(&ipcon,
00150     IPCON_CALLBACK_CONNECTED,
00151     (void*)callbackConnected,
00152     this);
00153 
00154   // register enumeration callback to "cb_enumerate"
00155   ipcon_register_callback(&ipcon,
00156     IPCON_CALLBACK_ENUMERATE,
00157     (void*)callbackEnumerate,
00158     this);
00159 
00160   return 0;
00161 }
00162 
00163 /*----------------------------------------------------------------------
00164  * publishPclMessage()
00165  * Publish the transformed plc data.
00166  *--------------------------------------------------------------------*/
00167 
00168 void LaserTransform::publishPclMessage(ros::Publisher *pub_message)
00169 {
00170   if (publish_new_pcl)
00171   {
00172     pub_message->publish(pcl_out);
00173     publish_new_pcl = false;
00174   }
00175 }
00176 
00177 /*----------------------------------------------------------------------
00178  * publishImuMessage()
00179  * Publish the Imu message.
00180  *--------------------------------------------------------------------*/
00181 
00182 void LaserTransform::publishImuMessage(ros::Publisher *pub_message)
00183 {
00184   int16_t acc_x, acc_y, acc_z;
00185   int16_t mag_x, mag_y, mag_z;
00186   int16_t ang_x, ang_y, ang_z;
00187   int16_t temp;
00188   float x = 0.0, y = 0.0, z = 0.0, w = 0.0;
00189   int16_t ix = 0, iy = 0, iz = 0, iw = 0;
00190   static uint32_t seq = 0;
00191   ros::Time current_time = ros::Time::now();
00192   tf::TransformBroadcaster tf_broadcaster;
00193   if (is_imu_connected || is_imu_v2_connected)
00194   {
00195     sensor_msgs::Imu imu_msg;
00196 
00197     // for the conversions look at rep 103 http://www.ros.org/reps/rep-0103.html
00198     // for IMU v1 http://www.tinkerforge.com/de/doc/Software/Bricks/IMU_Brick_C.html#imu-brick-c-api
00199     // for IMU v2 http://www.tinkerforge.com/de/doc/Software/Bricks/IMUV2_Brick_C.html#imu-v2-brick-c-api
00200     if (is_imu_connected)
00201     {
00202       // check if imu is initialized
00203       /*if (ros::Time::now().sec - imu_init_time.sec < 3)
00204         return;
00205       else
00206         imu_set_convergence_speed(&imu, imu_convergence_speed);
00207       */
00208       imu_get_quaternion(&imu, &x, &y, &z, &w);
00209 
00210       imu_get_all_data(&imu, &acc_x, &acc_y, &acc_z, &mag_x, &mag_y,
00211         &mag_z, &ang_x, &ang_y, &ang_z, &temp);
00212 
00213       ang_x = ang_x / 14.375;
00214       ang_y = ang_y / 14.375;
00215       ang_z = ang_z / 14.375;
00216 
00217       acc_x = (acc_x/1000.0)*9.80605;
00218       acc_y = (acc_y/1000.0)*9.80605;
00219       acc_z = (acc_z/1000.0)*9.80605;
00220     }
00221     else
00222     {
00223       imu_v2_get_quaternion(&imu_v2, &ix, &iy, &iz, &iw);
00224       x = ix / 16383.0;
00225       y = iy / 16383.0;
00226       z = iz / 16383.0;
00227       w = iw / 16383.0;
00228 
00229       imu_v2_get_linear_acceleration(&imu_v2, &acc_x, &acc_y, &acc_z);
00230       imu_v2_get_angular_velocity(&imu_v2, &ang_x, &ang_y, &ang_z);
00231 
00232       ang_x = ang_x * 16;
00233       ang_y = ang_y * 16;
00234       ang_z = ang_z * 16;
00235 
00236       acc_x = acc_x * 100;
00237       acc_y = acc_y * 100;
00238       acc_z = acc_z * 100;
00239     }
00240     // message header
00241     imu_msg.header.seq = seq;
00242     imu_msg.header.stamp = current_time;
00243     imu_msg.header.frame_id = "base_link";
00244 
00245     //TODO adapt values for IMU v2
00246     imu_msg.orientation.x = w;
00247     imu_msg.orientation.y = z*-1;
00248     imu_msg.orientation.z = y;
00249     imu_msg.orientation.w = x*-1;
00250 
00251     // orientation_covariance
00252     boost::array<const double, 9> oc =
00253       { 0.1, 0.1, 0.1,
00254         0.1, 0.1, 0.1,
00255         0.1, 0.1, 0.1};
00256 
00257     imu_msg.orientation_covariance = oc;
00258 
00259     // velocity from °/14.375 to rad/s
00260     imu_msg.angular_velocity.x = deg2rad(ang_x);
00261     imu_msg.angular_velocity.y = deg2rad(ang_y);
00262     imu_msg.angular_velocity.z = deg2rad(ang_z);
00263 
00264     // velocity_covariance
00265     boost::array<const double, 9> vc =
00266       { 0.1, 0.1, 0.1,
00267         0.1, 0.1, 0.1,
00268         0.1, 0.1, 0.1};
00269     imu_msg.angular_velocity_covariance = vc;
00270 
00271     // acceleration from mG to m/s²
00272     imu_msg.linear_acceleration.x = acc_x;
00273     imu_msg.linear_acceleration.y = acc_y;
00274     imu_msg.linear_acceleration.z = acc_z;
00275 
00276     // linear_acceleration_covariance
00277     boost::array<const double, 9> lac =
00278       { 0.1, 0.1, 0.1,
00279         0.1, 0.1, 0.1,
00280         0.1, 0.1, 0.1};
00281     imu_msg.linear_acceleration_covariance = lac;
00282 
00283     pub_message->publish(imu_msg);
00284 
00285     seq++;
00286   }
00287 }
00288 
00289 /*----------------------------------------------------------------------
00290  * checkConvergenceSpeed()
00291  * Set the speed of convergence depends on the angular velocity.
00292  *--------------------------------------------------------------------*/
00293 
00294 void LaserTransform::checkConvergenceSpeed()
00295 {
00296   if (is_imu_connected)
00297   {
00298     int16_t ang_x, ang_y, ang_z;
00299     imu_get_angular_velocity(&imu, &ang_x, &ang_y, &ang_z);
00300     // Realistische Drehraten: Siehe IPython Notebook,
00301     // Kapitel "Roll-/Pitch-/Yawrate"
00302     // http://nbviewer.ipython.org/github/balzer82/ICINCO-2014/blob/master/Extended-Kalman-Filter-CTRV-Attitude.ipynb
00303     if (ang_x > 5 || ang_x < -5 || ang_y > 5 || ang_y < -5 || ang_z > 5 || ang_z < -5)
00304     {
00305       // Fast turning: No Magnetic Field, just RotationRate
00306       imu_set_convergence_speed(&imu, 0);
00307     }
00308     else
00309       imu_set_convergence_speed(&imu, imu_convergence_speed);
00310   }
00311 }
00312 
00313 /*----------------------------------------------------------------------
00314  * publishMagneticFieldMessage()
00315  * Publish the MagneticField message.
00316  *--------------------------------------------------------------------*/
00317 
00318 void LaserTransform::publishMagneticFieldMessage(ros::Publisher *pub_message)
00319 {
00320   static uint32_t seq = 0;
00321   if (is_imu_connected || is_imu_v2_connected)
00322   {
00323     int16_t x = 0, y = 0, z = 0;
00324 
00325     // for the conversions look at rep 103 http://www.ros.org/reps/rep-0103.html
00326     // for IMU v1 http://www.tinkerforge.com/de/doc/Software/Bricks/IMU_Brick_C.html#imu-brick-c-api
00327     // for IMU v2 http://www.tinkerforge.com/de/doc/Software/Bricks/IMUV2_Brick_C.html#imu-v2-brick-c-api
00328     if (is_imu_connected)
00329     {
00330       imu_get_magnetic_field(&imu, &x, &y, &z); // nT -> T
00331       x = x / 10000000.0;
00332       y = y / 10000000.0;
00333       z = z / 10000000.0;
00334     }
00335     else
00336     {
00337       imu_v2_get_magnetic_field(&imu_v2, &x, &y, &z); // µT -> T
00338       x = x / 1000000.0;
00339       y = y / 1000000.0;
00340       z = z / 1000000.0;
00341     }
00342 
00343     sensor_msgs::MagneticField mf_msg;
00344 
00345     // message header
00346     mf_msg.header.seq =  seq;
00347     mf_msg.header.stamp = ros::Time::now();
00348     mf_msg.header.frame_id = "base_link";
00349 
00350     // magnetic field from mG to T
00351     mf_msg.magnetic_field.x = x;
00352     mf_msg.magnetic_field.y = y;
00353     mf_msg.magnetic_field.z = z;
00354 
00355     boost::array<const double, 9> mfc =
00356       { 0.01, 0.01, 0.01,
00357         0.01, 0.01, 0.01,
00358         0.01, 0.01, 0.01};
00359 
00360     mf_msg.magnetic_field_covariance = mfc;
00361 
00362     pub_message->publish(mf_msg);
00363 
00364     seq++;
00365   }
00366   return;
00367 }
00368 
00369 /*----------------------------------------------------------------------
00370  * publishNavSatFixMessage()
00371  * Publish the NavSatFix message.
00372  *--------------------------------------------------------------------*/
00373 
00374 void LaserTransform::publishNavSatFixMessage(ros::Publisher *pub_message)
00375 {
00376   static uint32_t seq = 0;
00377   uint8_t fix, satellites_view, satellites_used;
00378   uint16_t pdop, hdop, vdop, epe;
00379   uint32_t latitude, longitude;
00380   uint32_t altitude, geoidal_separation;
00381   uint32_t course, speed;
00382   char ns, ew;
00383   if (is_gps_connected)
00384   {
00385     // get gps sensor status
00386     gps_get_status(&gps, &fix, &satellites_view, &satellites_used);
00387 
00388     if (fix != GPS_FIX_3D_FIX)
00389       return; // No valid data
00390 
00391     gps_get_coordinates(&gps, &latitude, &ns, &longitude, &ew, &pdop,
00392       &hdop, &vdop, &epe);
00393     gps_get_altitude(&gps, &altitude, &geoidal_separation);
00394     // course in deg, speed in 1/100 km/h
00395     gps_get_motion(&gps, &course, &speed);
00396 
00397     if (this->velocity > 0.0)
00398     {
00399       this->velocity_gps = (speed*100) / 3.6; // in m/s
00400       this->course_gps = deg2rad(course*100);
00401       ROS_INFO_STREAM("GPS-Velocity:" << this->velocity_gps);
00402       ROS_INFO_STREAM("GPS-Course:" << this->course_gps);
00403     }
00404     else
00405     {
00406       this->velocity_gps = 0.0;
00407       this->course_gps = 0.0;
00408     }
00409 
00410     // generate NavSatFix message from gps sensor data
00411     sensor_msgs::NavSatFix gps_msg;
00412 
00413     // message header
00414     gps_msg.header.seq =  seq;
00415     gps_msg.header.stamp = ros::Time::now();
00416     gps_msg.header.frame_id = "gps";
00417     // gps status
00418     gps_msg.status.status = gps_msg.status.STATUS_SBAS_FIX;
00419     gps_msg.status.service = gps_msg.status.SERVICE_GPS;
00420 
00421     gps_msg.latitude = latitude/1000000.0;
00422     gps_msg.longitude = longitude/1000000.0;
00423     gps_msg.altitude = altitude/100.0;
00424     gps_msg.position_covariance_type = gps_msg.COVARIANCE_TYPE_UNKNOWN;
00425 
00426     // log gps data if GPS_LOGFILE is true
00427     if (gps_log.is_open() && GPS_LOGFILE)
00428     {
00429       std::string separator = "|";
00430       gps_log << ros::Time::now().sec;
00431       gps_log << gps_log << separator;
00432       gps_log << gps_msg.latitude;
00433       gps_log << separator;
00434       gps_log << gps_msg.longitude;
00435       gps_log << separator;
00436       gps_log << gps_msg.altitude;
00437       gps_log << std::endl;
00438     }
00439 
00440     // create UTM coordinates from gps data
00441     // this is the only use of packages geodesy and geographic_msgs
00442     // if the utm conversion not longer necessary, remove also dependencies from
00443     // CMakeLists.txt and package.xml and includes
00444     geographic_msgs::GeoPoint ll;
00445     ll = geodesy::toMsg(gps_msg);
00446     geodesy::UTMPoint pt;
00447     geodesy::fromMsg(ll,pt);
00448     if (xpos == 0 && ypos == 0)
00449     {
00450       xpos = pt.easting;
00451       ypos = pt.northing;
00452     }
00453     else
00454     {
00455       //ROS_INFO_STREAM("COORDS_1:" << pt.easting << "::" << pt.northing);
00456       //ROS_INFO_STREAM("COORDS_2:" << xpos << "::" << ypos);
00457 
00458       //std::cout << "COORDS_3:" << (int)(xpos-pt.easting) << "::" << (int)(ypos-pt.northing) << std::endl;
00459       //ROS_INFO_STREAM("COORDS_3:" << (int)xpos-pt.easting << "::" << (int)ypos-pt.northing);
00460     }
00461     // publish gps msg to ros
00462     pub_message->publish(gps_msg);
00463 
00464     seq++;
00465   }
00466 }
00467 
00468 /*----------------------------------------------------------------------
00469  * callbackPcl()
00470  * Callback function for laser scanner pcl.
00471  *--------------------------------------------------------------------*/
00472 
00473 void LaserTransform::callbackPcl(const sensor_msgs::PointCloud2::ConstPtr& msg)
00474 {
00475   pcl_out = *msg;
00476   //pcl_ros::transformPointCloud("/base_link", laser_pose,  *msg, pcl_out);
00477   //publishPclMessage(pcl_pub);
00478   new_pcl_filtered = true;
00479   isPlc = true;
00480 }
00481 
00482 /*----------------------------------------------------------------------
00483  * callbackOdometryFiltered()
00484  * Callback function for filtered odometry from robot localization.
00485  *--------------------------------------------------------------------*/
00486 
00487 void LaserTransform::callbackOdometryFiltered(const nav_msgs::Odometry::ConstPtr& msg)
00488 {
00489   // set curremt position values for octomap clear, x, y, yaw
00490   xpos = msg->pose.pose.position.x;
00491   ypos = msg->pose.pose.position.y;
00492 
00493   //std::cout << "x:" << msg->pose.pose.position.x << std::endl;
00494 
00495   tf::Quaternion q (msg->pose.pose.orientation.x,msg->pose.pose.orientation.y,msg->pose.pose.orientation.z,msg->pose.pose.orientation.w);
00496   tf::Matrix3x3 m(q);
00497   double roll, pitch, yaw;
00498   m.getRPY(roll, pitch, yaw);
00499   yy = yaw;
00500 
00501   if (new_pcl_filtered == true)
00502   {
00503     // transform pcl to laser position
00504     pcl_ros::transformPointCloud("/base_link", laser_pose,  pcl_out, pcl_out);
00505 
00506     // publish transformed plc
00507     publish_new_pcl = true;
00508     new_pcl_filtered = false;
00509     publishPclMessage(pcl_pub);
00510   }
00511 }
00512 
00513 /*----------------------------------------------------------------------
00514  * callbackConnected()
00515  * Callback function for Tinkerforge ip connected
00516  *--------------------------------------------------------------------*/
00517 
00518 void LaserTransform::callbackConnected(uint8_t connect_reason, void *user_data)
00519 {
00520   LaserTransform *lt = (LaserTransform*) user_data;
00521   if (lt->is_imu_connected == false)
00522     ipcon_enumerate(&(lt->ipcon));
00523   return;
00524 }
00525 
00526 /*----------------------------------------------------------------------
00527  * callbackEnumerate()
00528  * Callback function for Tinkerforge enumerate
00529  *--------------------------------------------------------------------*/
00530 
00531 void LaserTransform::callbackEnumerate(const char *uid, const char *connected_uid,
00532                   char position, uint8_t hardware_version[3],
00533                   uint8_t firmware_version[3], uint16_t device_identifier,
00534                   uint8_t enumeration_type, void *user_data)
00535 {
00536   LaserTransform *lt = (LaserTransform*) user_data;
00537 
00538   if(enumeration_type == IPCON_ENUMERATION_TYPE_DISCONNECTED)
00539   {
00540     return;
00541   }
00542 
00543   // check if device is an imu
00544   if(device_identifier == IMU_DEVICE_IDENTIFIER)
00545   {
00546     if (lt->is_imu_v2_connected)
00547       return;
00548     ROS_INFO_STREAM("found IMU with UID:" << uid);
00549     // Create IMU device object
00550     imu_create(&(lt->imu), uid, &(lt->ipcon));
00551     imu_set_convergence_speed(&(lt->imu),lt->imu_convergence_speed);
00552     imu_leds_on(&(lt->imu));
00553     lt->imu_init_time = ros::Time::now();
00554     lt->is_imu_connected = true;
00555   }
00556   else if (device_identifier == IMU_V2_DEVICE_IDENTIFIER)
00557   {
00558     if (lt->is_imu_connected)
00559       return;
00560     ROS_INFO_STREAM("found IMU_v2 with UID:" << uid);
00561     // Create IMU_v2 device object
00562     imu_v2_create(&(lt->imu_v2), uid, &(lt->ipcon));
00563     imu_leds_on(&(lt->imu_v2));
00564     lt->is_imu_v2_connected = true;
00565   }
00566   else if (device_identifier == GPS_DEVICE_IDENTIFIER)
00567   {
00568     ROS_INFO_STREAM("found GPS with UID:" << uid);
00569     // Create GPS device object
00570     gps_create(&(lt->gps), uid, &(lt->ipcon));
00571     lt->is_gps_connected = true;
00572   }
00573   else if (device_identifier == INDUSTRIAL_DIGITAL_IN_4_DEVICE_IDENTIFIER)
00574   {
00575     ROS_INFO_STREAM("found IDI4 with UID:" << uid);
00576     // Create IndustrialDigitalIn4 device object
00577     industrial_digital_in_4_create(&(lt->idi4), uid, &(lt->ipcon));
00578 
00579     // Register callback for interrupts
00580     industrial_digital_in_4_register_callback(&(lt->idi4),
00581       INDUSTRIAL_DIGITAL_IN_4_CALLBACK_INTERRUPT,
00582       (void*)callbackIdi4,
00583       lt);
00584 
00585     // set debounce period
00586     industrial_digital_in_4_set_debounce_period(&(lt->idi4),10);
00587 
00588     // Enable interrupt on pin 0
00589     industrial_digital_in_4_set_interrupt(&(lt->idi4), 1 << 0);
00590 
00591     lt->is_idi4_connected = true;
00592   }
00593   else if (device_identifier == DUAL_BUTTON_DEVICE_IDENTIFIER)
00594   {
00595     ROS_INFO_STREAM("found DualButton with UID:" << uid);
00596     dual_button_create(&(lt->db), uid, &(lt->ipcon));
00597 
00598     // Register state changed callback to function cb_state_changed
00599     dual_button_register_callback(&(lt->db),
00600                                   DUAL_BUTTON_CALLBACK_STATE_CHANGED,
00601                                   (void *)callbackDb,
00602                                   lt);
00603   }
00604 }
00605 
00606 /*----------------------------------------------------------------------
00607  * callbackIdi4()
00608  * Callback function for Tinkerforge Industrial Digital In 4 Bricklet
00609  *--------------------------------------------------------------------*/
00610 
00611 void LaserTransform::callbackIdi4(uint8_t interrupt_mask, uint8_t value_mask, void *user_data)
00612 {
00613   LaserTransform *lt = (LaserTransform*) user_data;
00614   static ros::Time begin = ros::Time(0,0);
00615 
00616   // check if correct input channel
00617   if (interrupt_mask != 0x1)
00618     return;
00619 
00620   // check for falling edge (ignore)
00621   if (interrupt_mask == 0x1 && value_mask == 0x0)
00622     return;
00623 
00624   if (begin.sec == 0)
00625     begin = ros::Time::now();
00626   else {
00627     ros::Time end = ros::Time::now();
00628     // calculate time between two impulses in ms
00629     float diff = (end.sec* 1000 + end.nsec / 1000000) - (begin.sec * 1000 + begin.nsec / 1000000);
00630 
00631     // check if vehicle is moving
00632     if (diff < 3000)
00633     {
00634       // calculate rev
00635       lt->rev = (1000.0/diff)/4.0; // 4 magnets
00636       // ... and the velocity in m/s
00637       // Der Faktor 1.40273 ist empirisch ermittelt worden
00638       // Berechnung dazu ist zu finden: Projekt Kommunaltechniksystem/Messungen/Drehzahlmessungen/messung k-gebaude_1.ods
00639       lt->velocity = (1.325 * lt->rev)/3.6;
00640 
00641       if (lt->isMeasure == true)
00642         lt->velo_log << end <<  "::" << lt->rev << "::" << diff << std::endl;
00643 
00644       //ROS_INFO_STREAM("Zeit End:" << end.sec << "::" << end.nsec);
00645       //ROS_INFO_STREAM("Zeit Start:" << begin.sec << "::" << begin.nsec);
00646       //ROS_INFO_STREAM("Diff:" << diff << " ms");
00647       ROS_INFO_STREAM("Drehzahl:" << lt->rev << " #### Geschwindigkeit:" << (lt->velocity*3.6) << " km/h");
00648     } else
00649     {
00650       // ignore first rev value after stand still
00651       ROS_INFO_STREAM("START");
00652     }
00653 
00654     // reset timestamps
00655     begin = end;
00656     lt->last_rev = ros::Time::now();
00657   }
00658   return;
00659 }
00660 
00661 /*----------------------------------------------------------------------
00662  * callbackDb()
00663  * Callback function for Tinkerforge Dual Button Bricklet
00664  *--------------------------------------------------------------------*/
00665 
00666 void LaserTransform::callbackDb(uint8_t button_l, uint8_t button_r,
00667                       uint8_t led_l, uint8_t led_r,
00668                       void *user_data)
00669 {
00670   LaserTransform *lt = (LaserTransform*) user_data;
00671   (void)led_l; // avoid unused parameter warning
00672   (void)led_r; // avoid unused parameter warning
00673   (void)user_data; // avoid unused parameter warning
00674 
00675   if (VELO_LOGFILE == false)
00676     return;
00677 
00678   if(button_l == DUAL_BUTTON_BUTTON_STATE_PRESSED && lt->isMeasure == false)
00679   {
00680     lt->rpm_cnt = 0;
00681     std::stringstream ss;
00682 
00683     time_t t;
00684     struct tm *ts;
00685     char buff[80];
00686 
00687     // build filename
00688     t = time(NULL);
00689     ts = localtime(&t);
00690 
00691     strftime(buff, 80, "#####%Y_%m_%d-%H_%M_%S#####", ts);
00692     lt->velo_log << buff  << std::endl;
00693     lt->isMeasure = true;
00694   }
00695 
00696   if(button_r == DUAL_BUTTON_BUTTON_STATE_PRESSED)
00697   {
00698     lt->isMeasure = false;
00699   }
00700 }
00701 
00702 /*----------------------------------------------------------------------
00703  * getQuaternion()
00704  * get IMU quaternion
00705  *--------------------------------------------------------------------*/
00706 
00707 tf::Quaternion LaserTransform::getQuaternion()
00708 {
00709   float x = 0.0, y = 0.0, z = 0.0, w = 0.0;
00710   int16_t ix = 0, iy = 0, iz = 0, iw = 0;
00711 
00712   if (is_imu_connected)
00713     imu_get_quaternion(&imu, &x, &y, &z, &w);
00714   if (is_imu_v2_connected)
00715   {
00716     imu_v2_get_quaternion(&imu_v2, &ix, &iy, &iz, &iw);
00717     x = ix / 16383.0;
00718     y = iy / 16383.0;
00719     z = iz / 16383.0;
00720     w = iw / 16383.0;
00721   }
00722   //-------
00723   float yaw   =  atan2(2.0*(x*y + w*z), pow(w,2)+pow(x,2)-pow(y,2)-pow(z,2));
00724   float pitch = -asin(2.0*(w*y - x*z));
00725   float roll  = -atan2(2.0*(y*z + w*x), -(pow(w,2)-pow(x,2)-pow(y,2)+pow(z,2)));
00726   std::cout << "y:" << rad2deg(yaw) << ":: p:" << rad2deg(pitch) << ":: r:" << rad2deg(roll) << std::endl;
00727   //-------
00728 
00729   tf::Quaternion q;
00730   q.setRPY(roll, pitch, yaw);
00731   return q;
00732 }
00733 
00734 /*----------------------------------------------------------------------
00735  * publishOdometryMessage()
00736  * Publish the odometry data (velocity vx)
00737  *--------------------------------------------------------------------*/
00738 
00739 void LaserTransform::publishOdometryMessage(ros::Publisher *pub_message)
00740 {
00741   static uint32_t seq = 0;
00742   static bool isStand = false;
00743   tf::TransformBroadcaster odom_broadcaster;
00744   ros::Time current_time = ros::Time::now();
00745 
00746   // check if vehicle stand still, after TIME_TO_STOP seconds without rev
00747   if (ros::Time::now().sec - last_rev.sec >= TIME_TO_STOP)
00748   {
00749     if (isStand == false)
00750     {
00751       ROS_INFO_STREAM("Vehicle stand still!");
00752       isStand = true;
00753     }
00754     velocity = 0.0;
00755   }
00756   else
00757   {
00758     isStand = false;
00759   }
00760 
00761   // publish the transform over tf
00762   geometry_msgs::TransformStamped odom_trans;
00763   geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(0);
00764 
00765   odom_trans.header.stamp = current_time;
00766   odom_trans.header.frame_id = "odom";
00767   odom_trans.child_frame_id = "base_link";
00768 
00769   odom_trans.transform.translation.x = 0.0;
00770   odom_trans.transform.translation.y = 0.0;
00771   odom_trans.transform.translation.z = 0.0;
00772 
00773   odom_trans.transform.rotation = odom_quat;
00774 
00775   //send the transform
00776   odom_broadcaster.sendTransform(odom_trans);
00777 
00778   nav_msgs::Odometry odo_msg;
00779 
00780   // message header
00781   odo_msg.header.seq =  seq;
00782   odo_msg.header.stamp = current_time;
00783   odo_msg.header.frame_id = "odom";
00784   odo_msg.child_frame_id = "base_link";
00785 
00786   odo_msg.pose.pose.position.x = 0;
00787   odo_msg.pose.pose.position.y = 0;
00788   odo_msg.pose.pose.position.z = 0;
00789 
00790   odo_msg.twist.twist.linear.x = velocity;
00791   odo_msg.twist.twist.angular.x = 0;
00792 
00793   // twist.covariance
00794   // TODO: to fill with plausible values
00795   boost::array<const double, 36> tc =
00796     { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
00797       0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
00798       0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
00799 
00800   odo_msg.twist.covariance = tc;
00801 
00802   // pose.covariance
00803   // TODO: to fill with plausible values
00804   boost::array<const double, 36> pc =
00805     { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
00806       0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
00807       0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
00808 
00809   odo_msg.pose.covariance = pc;
00810 
00811   pub_message->publish(odo_msg);
00812 
00813   seq++;
00814 
00815   return;
00816 }
00817 
00818 /*----------------------------------------------------------------------
00819  * setLaserPose()
00820  * Set the laser pose
00821  *--------------------------------------------------------------------*/
00822 void LaserTransform::setLaserPose(double x, double y, double z,
00823   double yaw, double pitch, double roll)
00824 {
00825   tf::Quaternion q;
00826   q.setRPY(deg2rad(roll),deg2rad(pitch),deg2rad(yaw));
00827   laser_pose.setOrigin(tf::Vector3(x, y, z));
00828   laser_pose.setRotation(q);
00829   //std::cout << x << "::" << y << "::" << z << "::" << yaw << "::" << pitch << "::" << roll << std::endl;
00830   return;
00831 }
00832 
00833 /*----------------------------------------------------------------------
00834  * getAngle()
00835  * get angle for clear octomap function
00836  *--------------------------------------------------------------------*/
00837 
00838 float getAngle(float angle, float rot)
00839 {
00840   if ( angle + rot > 360.0)
00841     return rot - ( 360.0 - angle);
00842   if ( angle + rot < 0.0 )
00843     return 360 - ( -rot - angle);
00844   return angle + rot;
00845 }
00846 
00847 /*----------------------------------------------------------------------
00848  * clearOctomap()
00849  * Set the unnecessary part of the octomap free
00850  *--------------------------------------------------------------------*/
00851 void LaserTransform::clearOctomap(ros::ServiceClient *client)
00852 {
00853   octomap_msgs::BoundingBoxQuery srv;
00854   int bb_width = 30, bb_height = 20, bb_depth = 5;
00855   float x = 0.0, y = 0.0, z = 0.0, w = 0.0;
00856   float yaw;
00857 
00858   yaw = yy;
00859 
00860   // calculate points for clearing bounding box, no resize of the tree size
00861   // clear quadrants as following, always two
00862   // 0°-45° ← # 0°-180 ↓ # 180°-225° → # 225°-360° ↑
00863   if (rad2deg(yaw) < 0)
00864     yaw = deg2rad(180 + (180 + rad2deg(yaw)));
00865 
00866   if (rad2deg(yaw) >= 0 && rad2deg(yaw) <= 45)
00867   {
00868     srv.request.max.x = int(xpos) + 1;
00869     srv.request.max.y = int(ypos) + 3 * bb_depth;
00870     srv.request.max.z = bb_height;
00871 
00872     srv.request.min.x = int(xpos) - bb_width;
00873     srv.request.min.y = int(ypos) - 3 * bb_depth;
00874     srv.request.min.z = -bb_height;
00875   }
00876   if (rad2deg(yaw) > 45 &&  rad2deg(yaw) <= 180.0)
00877   {
00878     srv.request.max.x = int(xpos) + bb_width;
00879     srv.request.max.y = int(ypos);
00880     srv.request.max.z = bb_height;
00881 
00882     srv.request.min.x = int(xpos) - bb_width;
00883     srv.request.min.y = int(ypos) - 3 * bb_depth;
00884     srv.request.min.z = -bb_height;
00885   }
00886   if (rad2deg(yaw) > 180 && rad2deg(yaw) <= 225)
00887   {
00888     srv.request.max.x = int(xpos) + bb_width;
00889     srv.request.max.y = int(ypos) + 3 * bb_depth;
00890     srv.request.max.z = bb_height;
00891 
00892     srv.request.min.x = int(xpos) - 1;
00893     srv.request.min.y = int(ypos) - 3 * bb_depth;
00894     srv.request.min.z = -bb_height;
00895   }
00896   if (rad2deg(yaw) > 225 && rad2deg(yaw) <= 360)
00897   {
00898     srv.request.max.x = int(xpos) + bb_width;
00899     srv.request.max.y = int(ypos) + 3 * bb_depth;
00900     srv.request.max.z = bb_height;
00901 
00902     srv.request.min.x = int(xpos) - bb_width;
00903     srv.request.min.y = int(ypos);
00904     srv.request.min.z = -bb_height;
00905   }
00906 
00907   std::cout << "Pos:" << int(xpos) << " :: " << int(ypos) << " :: " << rad2deg(yaw) << std::endl;
00908   std::cout << "Pos:" << int(srv.request.max.x) << " :: " << int(srv.request.max.y) << std::endl;
00909   std::cout << "Pos:" << int(srv.request.min.x) << " :: " << int(srv.request.min.y) << std::endl;
00910   std::cout << "################################################################" << std::endl;
00911 
00912   //if (isPlc == false)
00913 //      return;
00914   //isPlc == false;
00915   // TODO: verknuepfe cloud_in mit dieser Funktion
00916 
00917   // limit the octomap region clear rate
00918   // wenn versucht wird die octomap zu leeren, bevor diese daten enthaelt,
00919   // stuertzt die octomap node ab
00920   static int u = 400;
00921   u++;
00922   if (u < 800)
00923    return;
00924   u= 700;
00925 
00926   if (client->exists())  // check if octomap service exists
00927   {
00928     ; // success
00929   }
00930   else
00931   {
00932     ; // fail
00933   }
00934   if (client->call(srv)) // call octomap clear service
00935   {
00936     ; // success
00937   }
00938   else
00939   {
00940     ; // fail
00941   }
00942 }
00943 
00944 /*----------------------------------------------------------------------
00945  * getPosition()
00946  * get Position
00947  *--------------------------------------------------------------------*/
00948 
00949 int LaserTransform::getPosition(float *x_pos, float *y_pos, float *z_pos)
00950 {
00951   *x_pos = xpos;
00952   *y_pos = ypos;
00953   *z_pos = 0;
00954   return true;
00955 }


tinkerforge_laser_transform
Author(s): M.Fischer
autogenerated on Thu Jun 6 2019 20:39:25