Skip to content
Snippets Groups Projects
SpeedControl.cpp 5.17 KiB
Newer Older
#include <cmath>
#include <iostream>

#include <ros/ros.h>
#include "SpeedControl.h"
#include "tools/loadRosConfig.h"

using namespace std;

// Robot dimensions in m
//       
//       
//  /-------------\  <-- MAX_X
//  |      x      |
//  |      |      |
//  |      |      |
//  | y-----      |
//  |             |
//  |    ROBOT    |
//  |             |
//  \-------------/  <-- MIN_X
//  ^             ^
//  |             |
//  MAX_Y      MIN_Y
//
float ROBOT_MIN_X = -0.45;
float ROBOT_MAX_X =  0.30;
float ROBOT_MIN_Y = -0.27;
float ROBOT_MAX_Y =  0.27;


namespace {
  Eigen::AlignedBox2f InnerDangerZone,
        OuterDangerZone;
  float InnerDangerZoneFactor,
        OuterDangerZoneFactor;

  inline Eigen::AlignedBox2f loadRect(const string& path)
  {
    pair<float, float> pX, pY;
    loadConfigValue(path + "/x_min", pX.first);
    loadConfigValue(path + "/x_max", pX.second);
    loadConfigValue(path + "/y_min", pY.first);
    loadConfigValue(path + "/y_max", pY.second);

    Eigen::Vector2f first(pX.first, pY.first), second(pX.second, pY.second);
    return Eigen::AlignedBox2f(first, second);
  }  
}

void SpeedControl::loadDimensions()
{
  InnerDangerZone = loadRect("/homer_navigation/speed_control/inner_danger_zone");
  InnerDangerZoneFactor;
  loadConfigValue("/homer_navigation/speed_control/inner_danger_zone/speed_factor", InnerDangerZoneFactor);
  OuterDangerZone = loadRect("/homer_navigation/speed_control/inner_danger_zone");
  OuterDangerZoneFactor;
  loadConfigValue("/homer_navigation/speed_control/outer_danger_zone/speed_factor", OuterDangerZoneFactor);
  if(!OuterDangerZone.contains(InnerDangerZone))
    ROS_WARN_STREAM("InnerDangerZone is not contained in OuterDangerZone");
}

float SpeedControl::getSpeedFactor(const vector<geometry_msgs::Point>& points, float minVal, float maxVal )
{
  float minFactor = 1.0;
  for (unsigned i = 0; i < points.size(); i++)
  {
    Eigen::Vector2f point(points[i].x, points[i].y);
    if(InnerDangerZone.contains(point))
    {
      minFactor = InnerDangerZoneFactor;
      break;
    }
    if(OuterDangerZone.contains(point))
      minFactor = OuterDangerZoneFactor;
  }
  minFactor = sqrt(minFactor);
  float range = maxVal - minVal;
  minFactor = minVal + range*minFactor;
  return minFactor;
}

float SpeedControl::getMaxMoveDistance(vector<geometry_msgs::Point> points)
{
  float minDistance = 4; // distance in m to nearest obstacle in front
  for (unsigned int i = 0; i < points.size(); i++)
  {
      if(points[i].y > ROBOT_MIN_Y && points[i].y < ROBOT_MAX_Y && points[i].x > ROBOT_MAX_X)
      {
        float distance = sqrt((points[i].x * points[i].x) + (points[i].y * points[i].y));
        if (distance < minDistance)
        {
          minDistance = distance;
        }
      }
  }
  float maxMoveDist = minDistance - ROBOT_MAX_X;
  if (maxMoveDist < 0) {
    maxMoveDist = 0.0;
  }
  return maxMoveDist;
}

float SpeedControl::getMaxMoveDistance(std::vector< Eigen::Vector3d >* kinectData, float minObstacleHeight, float minObstacleFromRobotDistance, float maxObstacleFromRobotDistance)
{
  // Check for obstacles in Kinect image: Look for closest point

  float minDistance = 4; // distance to nearest obstacle in front

  for(int i=0;i<kinectData->size();++i)
  {
    Eigen::Vector2d p = Eigen::Vector2d(kinectData->at(i).x(), kinectData->at(i).y());
    if(!std::isnan(p.x()))
    {
      // Filter point cloud
        if(p.x() > minObstacleFromRobotDistance && p.x() < maxObstacleFromRobotDistance && kinectData->at(i).z() > minObstacleHeight)
      {
        // Check for collisions outside of robot
        if(p.y() > ROBOT_MIN_Y && p.y() < ROBOT_MAX_Y && p.x() > ROBOT_MAX_X)
        {
          float distance = sqrt((p.x() * p.x()) + (p.y() * p.y()));
          if (distance < minDistance)
          {
            minDistance = distance;
          }
        }
      }
    }
  }

  float maxMoveDist = minDistance - ROBOT_MAX_X;
  if (maxMoveDist < 0) {
    maxMoveDist = 0.0;
  }
  return maxMoveDist;
}

float SpeedControl::getTurnSpeedFactor( float speedFactor, float turnAngle, float minVal, float maxVal )
{
  //turn faster for larger angles
  float angleDependentFactor = sqrt( fabs(turnAngle) / M_PI );
  angleDependentFactor = minVal + angleDependentFactor*(maxVal-minVal);
  return sqrt( speedFactor * angleDependentFactor );
}

float SpeedControl::getMinTurnAngle(std::vector<geometry_msgs::Point> laserData, float minAngle, float maxAngle, float minDistance, float maxDistance)
{
    float turn_factor = 1.0;
    for (unsigned int i = 0; i < laserData.size(); i++)
    {
        if(laserData[i].y > ROBOT_MIN_Y && laserData[i].y < ROBOT_MAX_Y && laserData[i].x > ROBOT_MAX_X)
        {
          float distance = sqrt((laserData[i].x * laserData[i].x) + (laserData[i].y * laserData[i].y));
          if (distance < minDistance + ROBOT_MAX_X)
          {
            turn_factor = 0.0;
          }
          else if(distance > maxDistance + ROBOT_MAX_X)
          {
              turn_factor = 1.0;
          }
          else
          {
              turn_factor = (distance - minDistance)/maxDistance;
          }
        }
    }
    float range = maxAngle - minAngle;
    return minAngle + turn_factor * range;
}

SpeedControl::SpeedControl() {
}

SpeedControl::~SpeedControl() {
}