Give A Quick Summary On What Each Part of This Code Does and Its Expected Outcomes
Give A Quick Summary On What Each Part of This Code Does and Its Expected Outcomes
include
information about the mutexs and callbacks and what these link too. #include "laserprocessing.h"
#include <algorithm> #include <numeric> #include <thread> #include <mutex> #include
<condition_variable> using namespace std;
LaserProcessing::LaserProcessing(sensor_msgs::LaserScan laserScan): laserScan_(laserScan) { }
unsigned int LaserProcessing::countObjectReadings(){ //This function computes the amount of
objects unsigned int count=0; for (unsigned int i = 0; i < laserScan_.ranges.size(); ++i) { if
((laserScan_.ranges.at(i) > laserScan_.range_min) && (laserScan_.ranges.at(i) <
laserScan_.range_max) && !isnan(laserScan_.ranges.at(i)) && isfinite(laserScan_.ranges.at(i)))
{ count++; } } return count; } int LaserProcessing::countSegments() //This function detects the
cones and stores them into a vector of pairs. If the object detected is larger than a cone, a flag is
sent and the stopMission() function is called. { unsigned int count=0; if (cones_.size() > 0) { return
cones_.size(); } unsigned int i = 1; while (i < laserScan_.ranges.size()) { bool countFlag = true; bool
init = false; unsigned int st = i, en = i; double distance = 0; if (isinf(laserScan_.ranges.at(i - 1))) { i+
+; continue; } if (laserScan_.ranges.at(i -1) != laserScan_.ranges.at(i - 1)) { i++; continue; } while
(countFlag && i < laserScan_.ranges.size()) { if (isinf(laserScan_.ranges.at(i))) { countFlag = false; }
else { geometry_msgs::Point prev; float prevAngle = laserScan_.angle_min +
laserScan_.angle_increment * (i -1); prev.x = laserScan_.ranges.at(i - 1) * cos(prevAngle); prev.y =
laserScan_.ranges.at(i - 1) * sin(prevAngle); prev.z = 0; geometry_msgs::Point curr; float currAngle
= laserScan_.angle_min + laserScan_.angle_increment * i; curr.x = laserScan_.ranges.at(i) *
cos(currAngle); curr.y = laserScan_.ranges.at(i) * sin(currAngle); curr.z = 0; distance =
sqrt(pow(curr.x - prev.x, 2) + pow(curr.y - prev.y, 2)); if (distance < 0.3) { if (!init) { st = i; init = true;
} } else if(distance > 0.3 && distance < 2){ //the comparison of the distance between two flags
being 0.3 < distance < 2 means the flag is only activated if two points are taller than the cone
height ROS_INFO("Foreign Object Detected. Stopping mission."); return -1; // -1 count returns the
flag to the run function so that the stopMisson function can be called } else { countFlag = false; } }
if (!countFlag) { en = i; } i++; } if (st != en) { count++; double xC = 0, yC = 0; for (unsigned j = st; j
< en; j++) { float angle = laserScan_.angle_min + laserScan_.angle_increment * (j -1); xC +=
laserScan_.ranges.at(j - 1) * cos(angle); yC += laserScan_.ranges.at(j - 1) * sin(angle); // distance to
the point is converted to coordinates with trigonometry } xC = xC / (en - st); yC = yC / (en - st);
cones_.push_back(std::make_pair(xC, yC)); } } return count; } geometry_msgs::Point
LaserProcessing::detectClosestCone(){ //This function searches the cones_ vector, populated from
countSegments(), for the closest cone. geometry_msgs::Point point; unsigned int count =
countSegments(); if (count == 0) { return {}; } double dclosest = laserScan_.range_max; unsigned
int idx = 0, i = 0; for (auto cone : cones_) { double d = pow(pow(cone.first, 2) + pow(cone.second,
2), 0.5); if (d < dclosest) { idx = i; dclosest = d; } //the cones_ vector is iterated through and
repeatedly compared to the previous closest cone until the minimum value is found. i++; }
point.x = cones_.at(idx).first; point.y = cones_.at(idx).second; return point; } geometry_msgs::Point
LaserProcessing::detectRoadCentre(){ //This function determines the roadCentre between two
cones by splitting the distance between pairs. geometry_msgs::Point point; unsigned int count =
countSegments(); if (count == 0) { return {}; } double dclosest = laserScan_.range_max; unsigned
int idx = 0, jdx = 0; for (unsigned i = 0; i < cones_.size(); i++) { for(unsigned j = 0; j < cones_.size();
j++) { if (i == j) { continue; } double d = pow(pow(cones_.at(i).first - cones_.at(j).first, 2) +
pow(cones_.at(i).second - cones_.at(j).second, 2), 0.5); if (d < dclosest) { idx = i; jdx = j; dclosest =
d; } } } point.x = (cones_.at(idx).first + cones_.at(jdx).first) / 2; point.y = (cones_.at(idx).second +
cones_.at(jdx).second) / 2; return point; } void LaserProcessing::newScan(sensor_msgs::LaserScan
laserScan){ //The newScan function solely makes a local copy of the laserScan data.
laserScan_=laserScan; } geometry_msgs::PoseArray LaserProcessing::getCones(){ //The getCones
function individually extracts the cones from the vector and pushes them into a poseArray to be
published in Ackerman::publishCones() geometry_msgs::PoseArray conesArray;
conesArray.header.seq = 0; conesArray.header.frame_id = "world"; conesArray.header.stamp =
ros::Time::now(); for (const auto cone : cones_){ geometry_msgs::Pose pose; pose.position.x =
cone.first; pose.position.y = cone.second; //vector to posearray conversion pose.position.z = 0;
pose.orientation.w = 1.0; conesArray.poses.push_back(pose); } return conesArray; }
visualization_msgs::Marker LaserProcessing::createRoadCentreMarker(){ //The marker for the
roadCentre point is created here to be later published to the visualiser in
Ackerman::publishConess geometry_msgs::Point roadCentre = detectRoadCentre();
visualization_msgs::Marker marker; unsigned int ct=0; marker.header.frame_id = "world"; // Frame
ID "World" marker.header.stamp = ros::Time::now(); //We set lifetime (it will dissapear in this
many seconds) marker.lifetime = ros::Duration(1000.0); //zero is forever // Set the namespace and
id for this marker. This serves to create a unique ID // Any marker sent with the same namespace
and id will overwrite the old one marker.ns = "road"; //This is namespace, markers can be in
diofferent namespace marker.id = ct++; // We need to keep incrementing markers to send
others ... so THINK, where do you store a vaiable if you need to keep incrementing it marker.type
= visualization_msgs::Marker::CUBE; marker.action = visualization_msgs::Marker::ADD;
marker.pose.position.x = roadCentre.x; marker.pose.position.y = roadCentre.y;
marker.pose.position.z = 0; //Orientation, we are not going to orientate it, for a quaternion it
needs 0,0,0,1 marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0;
marker.pose.orientation.z = 0.0; marker.pose.orientation.w = 1.0; marker.scale.x = 0.5; //
Dimensions of the cubes representing the road centre marker.scale.y = 0.5; marker.scale.z =
0.5; //Let's send a marker with color (red for now) std_msgs::ColorRGBA color; color.a=1;//a is
alpha - transparency 1 is 100%; color.r=1.0; color.g=0; color.b=0; marker.color = color; return
marker; } visualization_msgs::MarkerArray LaserProcessing::createConeMarkers(){ //The markers
for the cones are created here to be later published to the visualiser in Ackerman::publishCones
visualization_msgs::MarkerArray markersArray; unsigned int ct=0; if (cones_.empty())
{ ROS_INFO("No cone data found"); } for (const auto cone : cones_){ visualization_msgs::Marker
marker; marker.header.frame_id = "world"; // Frame ID "World" marker.header.stamp =
ros::Time::now(); //We set lifetime (it will dissapear in this many seconds) marker.lifetime =
ros::Duration(1000.0); //zero is forever // Set the namespace and id for this marker. This serves to
create a unique ID // Any marker sent with the same namespace and id will overwrite the old one
marker.ns = "cones"; //This is namespace, markers can be in different namespace marker.id = ct+
+; // We need to keep incrementing markers to send others marker.type =
visualization_msgs::Marker::CYLINDER; marker.action = visualization_msgs::Marker::ADD;
marker.pose.position.x = cone.first; marker.pose.position.y = cone.second; marker.pose.position.z
= 0; //Orientation, we are not going to orientate it, for a quaternion it needs 0,0,0,1
marker.pose.orientation.x = 0.0; marker.pose.orientation.y = 0.0; marker.pose.orientation.z = 0.0;
marker.pose.orientation.w = 1.0; marker.scale.x = 0.4; // Diameter of the cylinder representing
cones marker.scale.y = 0.4; marker.scale.z = 0.5; //Let's send a marker with color (blue for now)
std_msgs::ColorRGBA color; color.a=1;//a is alpha - transparency 1 is 100%; color.r=0; color.g=0;
color.b=1.0; marker.color = color; //ROS_INFO_STREAM("Marker:" << marker.pose.position.x <<
", " << marker.pose.position.y); markersArray.markers.push_back(marker); } return markersArray; }
geometry_msgs::Point LaserProcessing::polarToCart(unsigned int index) //this function converts
the polar values of distance and angle to cartesian points { float angle = laserScan_.angle_min +
laserScan_.angle_increment*index; float range = laserScan_.ranges.at(index);
geometry_msgs::Point cart; cart.x = static_cast<double>(range*cos(angle)); cart.y =
static_cast<double>(range*sin(angle)); return cart; } double
LaserProcessing::angleConnectingPoints(geometry_msgs::Point p1, geometry_msgs::Point p2)
//this function computes the angle between two points using the atan function. { return
atan2(p2.y - p1.y, p2.x - p1.x); }
ChatGPT
The given code is a part of a larger program that processes laser scan data. Here is a summary of
each part and its expected outcome: