2 #include <boost/algorithm/clamp.hpp> 7 this->m_lidar_subscriber =
8 m_node_handle.subscribe<sensor_msgs::LaserScan>(
TOPIC_LASER_SCAN, 1, &WallFollowing::lidarCallback,
this);
9 this->m_drive_parameter_publisher = m_node_handle.advertise<drive_msgs::drive_param>(
TOPIC_DRIVE_PARAMETERS, 1);
11 this->updateDynamicConfig();
13 m_dyn_cfg_server.setCallback([&](wallfollowing1::wallfollowing1Config& cfg, uint32_t) {
14 m_min_range = cfg.min_range;
15 m_max_range = cfg.max_range;
17 m_fallback_range = cfg.fallback_range;
19 m_sample_angle_1 =
static_cast<float>(cfg.sample_angle_1) *
DEG_TO_RAD;
20 m_sample_angle_2 =
static_cast<float>(cfg.sample_angle_2) *
DEG_TO_RAD;
22 m_wall_following_max_speed = cfg.wall_following_max_speed;
23 m_wall_following_min_speed = cfg.wall_following_min_speed;
25 m_prediction_distance = cfg.prediction_distance;
27 m_target_wall_distance = cfg.target_wall_distance;
29 m_time_between_scans = cfg.time_between_scans;
34 float map(
float in_lower,
float in_upper,
float out_lower,
float out_upper,
float value)
36 return out_lower + ((out_upper - out_lower) * (value - in_lower) / (in_upper - in_lower));
39 float WallFollowing::getRangeAtDegree(
const sensor_msgs::LaserScan::ConstPtr& lidar,
float angle)
41 int sampleCount = (lidar->angle_max - lidar->angle_min) / lidar->angle_increment;
42 int index =
map(lidar->angle_min, lidar->angle_max, 0, sampleCount, angle);
46 || index >= sampleCount
47 || lidar->ranges[index] < m_min_range
48 || lidar->ranges[index] > m_max_range) {
49 ROS_INFO_STREAM(
"Could not sample lidar, using fallback value");
50 return m_fallback_range;
54 return lidar->ranges[index];
57 Wall WallFollowing::getWall(
const sensor_msgs::LaserScan::ConstPtr& lidar,
bool right_wall)
59 float leftRightSign = right_wall ? -1 : 1;
61 float angle1 = m_sample_angle_1 * leftRightSign;
62 float angle2 = m_sample_angle_2 * leftRightSign;
63 float range1 = this->getRangeAtDegree(lidar, angle1);
64 float range2 = this->getRangeAtDegree(lidar, angle2);
66 return Wall(angle1, angle2, range1, range2);
78 void WallFollowing::followSingleWall(
const sensor_msgs::LaserScan::ConstPtr& lidar,
bool right_wall)
80 float leftRightSign = right_wall ? -1 : 1;
82 Wall wall = this->getWall(lidar, right_wall);
83 float predictedWallDistance = wall.
predictDistance(m_prediction_distance);
85 float error = m_target_wall_distance - predictedWallDistance;
88 float steeringAngle = atan(leftRightSign * correction) * 2 / M_PI;
89 float velocity = m_wall_following_max_speed * (1 - std::abs(steeringAngle));
90 velocity = boost::algorithm::clamp(velocity, m_wall_following_min_speed, m_wall_following_max_speed);
94 createPoint(m_prediction_distance, -error * leftRightSign, 0),
97 this->m_debug_geometry.
drawLine(2,
createPoint(m_prediction_distance, -error * leftRightSign, 0),
98 createPoint(m_prediction_distance + std::cos(wallAngle) * 2,
99 (-error + std::sin(wallAngle) * 2) * leftRightSign, 0),
102 this->publishDriveParameters(velocity, steeringAngle);
105 void WallFollowing::followWalls(
const sensor_msgs::LaserScan::ConstPtr& lidar)
107 Wall leftWall = this->getWall(lidar,
false);
108 Wall rightWall = this->getWall(lidar,
true);
114 float steeringAngle = atan(correction) * 2 / M_PI;
115 float velocity = m_wall_following_max_speed * (1 - std::max(0.0f, std::abs(steeringAngle) - 0.15f));
116 velocity = boost::algorithm::clamp(velocity, m_wall_following_min_speed, m_wall_following_max_speed);
122 float distance2 = m_prediction_distance + 2;
128 this->publishDriveParameters(velocity, steeringAngle);
131 void WallFollowing::publishDriveParameters(
float velocity,
float angle)
133 drive_msgs::drive_param drive_parameters;
134 drive_parameters.velocity = velocity;
135 drive_parameters.angle = angle;
136 this->m_drive_parameter_publisher.publish(drive_parameters);
139 void WallFollowing::lidarCallback(
const sensor_msgs::LaserScan::ConstPtr& lidar)
141 this->followWalls(lidar);
144 void WallFollowing::updateDynamicConfig()
146 wallfollowing1::wallfollowing1Config cfg;
148 cfg.min_range = m_min_range;
149 cfg.max_range = m_max_range;
151 cfg.fallback_range = m_fallback_range;
153 cfg.sample_angle_1 = m_sample_angle_1 /
DEG_TO_RAD;
154 cfg.sample_angle_2 = m_sample_angle_2 /
DEG_TO_RAD;
156 cfg.wall_following_max_speed = m_wall_following_max_speed;
157 cfg.wall_following_min_speed = m_wall_following_min_speed;
159 cfg.prediction_distance = m_prediction_distance;
161 cfg.target_wall_distance = m_target_wall_distance;
163 cfg.time_between_scans = m_time_between_scans;
165 m_dyn_cfg_server.updateConfig(cfg);
168 int main(
int argc,
char** argv)
170 ros::init(argc, argv,
"wall_following");
float updateAndGetCorrection(float error, float deltaTime)
constexpr const char * TOPIC_LASER_SCAN
constexpr const char * LIDAR_FRAME
std_msgs::ColorRGBA createColor(double r, double g, double b, double a)
int main(int argc, char **argv)
constexpr const char * TOPIC_VISUALIZATION
float predictDistance(float distancce_to_current_position)
void draw(RvizGeometryPublisher &geometry, int id, std_msgs::ColorRGBA color)
string TOPIC_DRIVE_PARAMETERS
constexpr float DEG_TO_RAD
void drawLine(int id, geometry_msgs::Point point1, geometry_msgs::Point point2, std_msgs::ColorRGBA color, float width)
geometry_msgs::Point createPoint(float x, float y, float z)
float map(float in_lower, float in_upper, float out_lower, float out_upper, float value)