00001
00002
00003
00004
00005
00006 #include <uos_freespace/uos_freespace.h>
00007 #include <cmath>
00008 #include <cstdio>
00009 #include <geometry_msgs/Twist.h>
00010 #include <geometry_msgs/QuaternionStamped.h>
00011
00012 #define EPSILON 0.000001 // arbitrarily small value for cos limit to prevent numerical instability
00013 #define min(a,b) ((a)<(b)?(a):(b)) //carried over from old code, possible cmath is enough
00014 #define max(a,b) ((a)>(b)?(a):(b))
00015 #define LASERSCAN_OPENING_ANGLE_WIDTH 270 //the viewing angle of the laserscanner (possibly only for lms100)
00016 #define LASERSCAN_DEADZONE 45 //the angle range one either side of the scanner to ignore
00017
00018 FreeSpace::FreeSpace():
00019 turn_state_(0),
00020 scanner_orientation_(0),
00021 turn_omega_(0),
00022 private_nh_("~")
00023 {
00024
00025 private_nh_.param("max_vel_x_", max_vel_x_, 0.5);
00026 private_nh_.param("max_rotational_vel_", max_rotational_vel_, 0.3);
00027
00028 turn_state_ = 0;
00029
00030 scanner_orientation_ = 0;
00031
00032
00033 vel_pub_ = nh_.advertise<geometry_msgs::Twist>("cmd_vel", 1);
00034 laser_sub_ = nh_.subscribe("scan", 10, &FreeSpace::autonomousBehaviour, this);
00035 ROS_DEBUG("constructor");
00036 }
00037
00038 double FreeSpace::calcFreespace(const sensor_msgs::LaserScan::ConstPtr &laserscan){
00039 unsigned int i;
00040 double phi;
00041 double sinSum = 0.0, cosSum = 0.0;
00042 double orientationWeight;
00043 double alpha = 0.0;
00044
00045 for (i = 0; i < laserscan->ranges.size(); i++) {
00046 if(laserscan->ranges[i] > 0.1){
00047 phi = laserscan->angle_min + i * laserscan->angle_increment;
00048
00049
00050
00051
00052
00053
00054 orientationWeight = cos(phi/2) * 1.0/(1.0+exp(-(laserscan->ranges[i]-1)/0.5));
00055 sinSum += sin(phi) * orientationWeight;
00056 cosSum += cos(phi) * orientationWeight;
00057 }
00058 }
00059 if (fabs(cosSum) > EPSILON){
00060 alpha = atan2(sinSum, cosSum);
00061 }
00062 return alpha;
00063 }
00064
00065 int FreeSpace::isInvertedScannerCheck(const sensor_msgs::LaserScan::ConstPtr &laserscan){
00066
00067
00068 tf::Quaternion q;
00069 q.setRPY(0.0, 0.0, laserscan->angle_min);
00070 tf::Stamped<tf::Quaternion> min_q(q, laserscan->header.stamp,laserscan->header.frame_id);
00071 q.setRPY(0.0, 0.0, laserscan->angle_max);
00072 tf::Stamped<tf::Quaternion> max_q(q, laserscan->header.stamp,laserscan->header.frame_id);
00073
00074 try {
00075
00076
00077 tf_.waitForTransform("base_link", "laser",laserscan->header.stamp,ros::Duration(1.0));
00078 tf_.transformQuaternion("base_link", min_q, min_q);
00079 tf_.transformQuaternion("base_link", max_q, max_q);
00080 }
00081 catch(tf::TransformException& e) {
00082
00083 ROS_WARN("Unable to transform min/max laser angles into base frame: %s",e.what());
00084 return 0;
00085 }
00086
00087 ROS_DEBUG("Successfully transformed min/max laser angles into base frame");
00088
00089
00090 double minAngle = tf::getYaw(min_q);
00091 double maxAngle = tf::getYaw(max_q);
00092 double baseFrameAngleIncrement = (maxAngle - minAngle) / laserscan->ranges.size();
00093
00094 ROS_DEBUG("Laser angles in base frame: min: %.3f max: %.3f inc: %.3f", minAngle, maxAngle, baseFrameAngleIncrement);
00095 if (baseFrameAngleIncrement < 0){
00096
00097 ROS_DEBUG("Inverting scan");
00098 return -1;
00099 }
00100 return 1;
00101 }
00102
00103 int FreeSpace::checkRange(
00104 const sensor_msgs::LaserScan::ConstPtr &laserscan,
00105 double xregion, double yregion,
00106 int *indexOfObstacle,
00107 double *distanceToObstacle)
00108 {
00109 unsigned int i;
00110 double generalDistance = 65536.0;
00111 *distanceToObstacle = 65536.0;
00112 *indexOfObstacle = -1;
00113
00114
00115 int deadzonePoints = int(floor((((LASERSCAN_DEADZONE)*(M_PI/180))/laserscan->angle_increment)));
00116 ROS_WARN("deadzonepoints :%d", deadzonePoints);
00117
00118
00119 for (i = fabs(deadzonePoints); i < (laserscan->ranges.size() - fabs(deadzonePoints)); i++) {
00120 if(laserscan->ranges[i] > 0.1){
00121 double x = laserscan->ranges[i] * cos(laserscan->angle_min + i * laserscan->angle_increment);
00122 double y = laserscan->ranges[i] * sin(laserscan->angle_min + i * laserscan->angle_increment);
00123 if ((x < xregion) && (fabs(y) < (yregion / 2))) {
00124
00125 if (*distanceToObstacle > x) {
00126
00127 *distanceToObstacle = x;
00128 *indexOfObstacle = i;
00129 ROS_WARN("set index to obstacle %d", i);
00130 }
00131 }
00132 if ((x > xregion) && (fabs(y) < (yregion / 2))) {
00133
00134 if (generalDistance > x) {
00135
00136 generalDistance = x;
00137
00138 }
00139 }
00140 }
00141 }
00142
00143 if (*indexOfObstacle == -1){
00144
00145 *distanceToObstacle = generalDistance;
00146 }
00147 ROS_WARN("distance to obstacle :%f", *distanceToObstacle);
00148 ROS_WARN(" index obstacle :%d", *indexOfObstacle);
00149 return 0;
00150 }
00151
00152
00153
00154
00155
00156
00157
00158 void FreeSpace::autonomousBehaviour(const sensor_msgs::LaserScan::ConstPtr &laserscan){
00159 ROS_DEBUG("autonomousBehaviour");
00160
00161
00162 double xregion = 0.5;
00163 double yregion = 0.5;
00164 double DTOStopTurning = 1.0;
00165 double DTOStartTurning = 0.5;
00166 int indexOfObstacle = -1;
00167 double frontMaxDistance = 0;
00168
00169 double uTurning = 0.2 * max_vel_x_;
00170 double distanceToObstacle = INFINITY;
00171 double omega = calcFreespace(laserscan);
00172 double u = max_vel_x_;
00173
00174
00175
00176 for(unsigned int i = 0; i < laserscan->ranges.size(); i++) {
00177 if(laserscan->ranges[i] > frontMaxDistance) {
00178 frontMaxDistance = laserscan->ranges[i];
00179 }
00180 }
00181
00182 if(scanner_orientation_ == 0) {
00183 scanner_orientation_ = isInvertedScannerCheck(laserscan);
00184 ROS_DEBUG("scanner_orientation_: %d", scanner_orientation_);
00185 }
00186
00187
00188 checkRange(laserscan,xregion,yregion,&indexOfObstacle,&distanceToObstacle);
00189
00190
00191 if (indexOfObstacle != -1) {
00192 u = max(distanceToObstacle - 0.2 / (xregion * max_vel_x_),0);
00193 }
00194
00195
00196
00197 if (turn_state_ == 1) {
00198 ROS_WARN("turn_state: 1");
00199 if ( (distanceToObstacle > DTOStopTurning)) {
00200 turn_state_ = 0;
00201 }
00202 else {
00203
00204 ROS_WARN("turning away");
00205 }
00206 u = min(u, uTurning);
00207 }
00208
00209 if (((frontMaxDistance < DTOStopTurning) || (distanceToObstacle < DTOStartTurning)) && (turn_state_ == 0) ) {
00210
00211
00212 if (indexOfObstacle > laserscan->ranges.size() / 2) {
00213 turn_omega_ = -max_rotational_vel_;
00214
00215 ROS_WARN("turning_left");
00216 }
00217 else if (indexOfObstacle <= laserscan->ranges.size() / 2 && indexOfObstacle >= 0) {
00218 turn_omega_ = max_rotational_vel_;
00219
00220
00221 ROS_WARN("turning_right");
00222 }
00223 turn_state_ = 1;
00224 u = min(u, uTurning);
00225 }
00226 if (turn_state_ == 1){
00227 omega = turn_omega_;
00228 }
00229
00230 geometry_msgs::Twist vel;
00231 vel.linear.x = u;
00232 vel.angular.z = scanner_orientation_ * omega;
00233 vel_pub_.publish(vel);
00234 }