TinyRobotics
Loading...
Searching...
No Matches
RangeSensor.h
1#pragma once
2#include <cmath>
3
4#include "TinyRobotics/communication/Message.h"
5#include "TinyRobotics/communication/MessageSource.h"
6#include "TinyRobotics/coordinates/Coordinate.h"
7#include "TinyRobotics/coordinates/FrameMgr2D.h"
8#include "TinyRobotics/units/Distance.h"
9#include "TinyRobotics/utils/LoggerClass.h"
10
11namespace tinyrobotics {
12
13/**
14 * @class RangeSensor
15 * @ingroup sensors
16 * @brief Generic range sensor abstraction for LIDAR, ultrasonic, or similar
17 * sensors.
18 *
19 * This template class models a simple range sensor, such as a LIDAR or
20 * ultrasonic sensor, for robotics applications. It tracks the measured distance
21 * to an obstacle, the angle (bearing) of the obstacle relative to the sensor,
22 * and the transform from the sensor's local frame to the world frame. The class
23 * provides methods to set and retrieve the measured distance and bearing,
24 * update the sensor-to-world transform, and compute the world-frame coordinates
25 * of detected obstacles.
26 *
27 * ## Features
28 * - Supports any distance unit via template parameter (default: meters)
29 * - Publishes distance, angle, and obstacle position as messages (for
30 * integration with messaging framework)
31 * - Computes obstacle coordinates in the world frame using a 2D transform
32 * - Validity checks for sensor readings (distance > 0)
33 * - Can be used for navigation, mapping, and obstacle avoidance
34 *
35 * ## Usage Example
36 * @code
37 * Transform2D tf = ...; // Sensor-to-world transform
38 * RangeSensor<> sensor(tf, 0.0f); // 0 degrees = forward
39 * sensor.begin();
40 * sensor.setObstacleDistance(1.5f); // Set measured distance
41 * if (sensor) {
42 * Coordinate<DistanceM> obs;
43 * if (sensor.getObstacleCoordinate(obs)) {
44 * // Use obs for navigation
45 * }
46 * }
47 * @endcode
48 *
49 * ## Template Parameters
50 * @tparam T Distance type (default: DistanceM)
51 *
52 * ## Methods
53 * - setObstacleDirectionDegree(deg): Set obstacle bearing in degrees
54 * - setObstacleDistance(distance): Set measured distance
55 * - setObstacle(degree, distance): Set both bearing and distance
56 * - setTransform(tf): Set sensor-to-world transform
57 * - getObstacleCoordinate(result): Compute world-frame obstacle coordinate
58 * - hasObstacle(): True if a valid obstacle is detected
59 *
60 * ## Applications
61 * - LIDAR, ultrasonic, or IR range sensing
62 * - Robot navigation and mapping
63 * - Obstacle detection and avoidance
64 *
65 * @author Phil Schatzmann
66
67 */
68template <typename T = DistanceM>
69class RangeSensor : public MessageSource {
70 public:
71 RangeSensor(const Transform2D& tf, float obstacleDegree = 0) {
72 setObstacleDirectionDegree(obstacleDegree);
74 }
75 RangeSensor(float obstacleDegree = 0) {
76 setObstacleDirectionDegree(obstacleDegree);
77 }
78
79 /// Start the sensor (e.g., initialize hardware)
80 bool begin() {
81 is_active_ = true;
82 return true;
83 }
84
85 /// Update the sensor with angle (deg) and distance (m)
86 void update(float angleDeg, float distanceM) {
88 setObstacleDistance(distanceM);
89 }
90
91 /// Update the sensor with angle and distance objects
92 void update(Angle angle, Distance distance) {
94 setObstacleDistance(distance);
95 }
96
97 /// Stop the sensor
98 void end() { is_active_ = false; }
99
100 /// Defines the angle to the obstacle in degrees: 0 means forward
101 void setObstacleDirectionDegree(float deg) { obstacle_deg_ = deg; }
102
103 /// Set the obstacle direction using an Angle object
104 void setObstacleDirection(Angle angle) {
105 setObstacleDirectionDegree(angle.getValue(AngleUnit::DEG));
106 }
107
108 /// Get the angle of the obstacle relative to the sensor's forward direction
109 /// in degrees.
110 float getObstacleDirectionDegree() const { return obstacle_deg_; }
111
112 /// Set the distance measured by the sensor. Make sure that the
113 /// ObstacleDegree is defined
114 bool setObstacleDistance(Distance dist) {
115 return setObstacleDistance(dist.getValue(DistanceUnit::M));
116 }
117
118 /// Set the distance measured by the sensor. Make sure that the
119 /// ObstacleDegree is defined
120 bool setObstacleDistance(float distanceM) {
121 if (!is_active_) return false;
122 this->distanceM = distanceM;
123
124 // If an obstacle is detected (distance > alertDistance), send message
125 if (distanceM >= alertDistanceM_ &&
126 std::abs(obstacle_deg_) <= alertAngleDeg_) {
127 Message<float> msg(MessageContent::Obstacle, distanceM, Unit::Meters);
128 msg.origin = MessageOrigin::LIDAR;
129 sendMessage(msg);
130 }
131
132 // Publish messages for distance, angle, and obstacle coordinate if valid
133 Coordinate<T> obstacle;
134 if (getObstacleCoordinate(obstacle)) {
135 // publish distance
136 Message<T> msgDistance(MessageContent::Distance, distanceM, Unit::Meters);
137 msgDistance.origin = MessageOrigin::LIDAR;
138 sendMessage(msgDistance);
139
140 // publish angle to direction of movement
141 Message<T> msgAngle(MessageContent::Angle, obstacle_deg_,
143 msgAngle.origin = MessageOrigin::LIDAR;
144 sendMessage(msgAngle);
145
146 // publish obstacle coordinate
147 Message<Coordinate<T>> msgLocation(MessageContent::Position, obstacle,
149 msgLocation.origin = MessageOrigin::LIDAR;
150 sendMessage(msgLocation);
151 }
152 return true;
153 }
154
155 /// Set the alert angle threshold for obstacle detection
156 void setObstacleAlertAngle(Angle deg) {
157 alertAngleDeg_ = deg.getValue(AngleUnit::DEG);
158 }
159
160 /// Set the alert distance threshold for obstacle detection
162 alertDistanceM_ = dist.getValue(DistanceUnit::M);
163 }
164
165 /// Provide the distance measured by the sensor. In a real implementation,
166 /// this would
167 float getObstacleDistance() const { return distanceM; }
168
169 /// Convenience method to set both the obstacle bearing and distance at once.
170 void setObstacle(float degree, float distance) {
172 setObstacleDistance(distance);
173 }
174
175 /// Set the sensor-to-world transform
176 void setTransform(const Transform2D& tf) {
177 lidar_to_world_tf = tf;
178 has_transform_ = true;
179 }
180
181 /// Get the obstacle coordinate in world frame based on the current distance
182 /// and transform.
183 bool getObstacleCoordinate(Coordinate<T>& result) {
184 if (!has_transform_) {
185 // Optionally log error
186 TRLogger.error(
187 "RangeSensor: No transform set, cannot compute obstacle coordinate");
188 return false;
189 }
190 float theta = obstacle_deg_ * static_cast<float>(M_PI) / 180.0f;
191 Coordinate<T> obstacle_lidar(distanceM * std::cos(theta),
192 distanceM * std::sin(theta));
193 result = lidar_to_world_tf.apply(obstacle_lidar);
194 return true;
195 }
196
197 /// Check if the sensor reading is valid (distance > 0)
198 operator bool() const { return distanceM > 0; } // Valid if distance is set
199
200 /// Return true if there is an obstacle detected (distance > 0)
201 bool hasObstacle() const { return distanceM > 0; }
202
203 /// Compute a speed factor (0.0 to 1.0) based on the distance to the obstacle
204 float getSpeedFactor(Distance breakingDistance) const {
205 if (distanceM <= 0) return 1.0f; // No obstacle, full speed
206 if (distanceM >= breakingDistance.getValue(DistanceUnit::M))
207 return 1.0f; // Beyond breaking distance, full speed
208 // Linearly scale speed factor based on distance to obstacle
209 float factor = distanceM / breakingDistance.getValue(DistanceUnit::M);
210 return constrain(factor, 0.0f, 1.0f);
211 }
212
213 protected:
214 float obstacle_deg_ = 0;
215 float distanceM = 0;
216 Transform2D lidar_to_world_tf;
217 bool has_transform_ = false;
218 bool is_active_ = false;
219 float alertAngleDeg_ = 5; // Default to 5 degrees
220 float alertDistanceM_ = 1.0f; // Default to 1 meter
221
222};
223
224} // namespace tinyrobotics
Represents an angle with unit conversion and wrap-around support.
Definition: Angle.h:42
A generic 3D coordinate class for robotics, navigation, and spatial calculations.
Definition: Coordinate.h:57
Represents a distance measurement with unit conversion support.
Definition: Distance.h:40
Base class for message sources in the TinyRobotics communication framework.
Definition: MessageSource.h:35
Generic range sensor abstraction for LIDAR, ultrasonic, or similar sensors.
Definition: RangeSensor.h:69
void setTransform(const Transform2D &tf)
Set the sensor-to-world transform.
Definition: RangeSensor.h:176
bool setObstacleDistance(float distanceM)
Definition: RangeSensor.h:120
void update(Angle angle, Distance distance)
Update the sensor with angle and distance objects.
Definition: RangeSensor.h:92
bool begin()
Start the sensor (e.g., initialize hardware)
Definition: RangeSensor.h:80
operator bool() const
Check if the sensor reading is valid (distance > 0)
Definition: RangeSensor.h:198
bool getObstacleCoordinate(Coordinate< T > &result)
Definition: RangeSensor.h:183
void update(float angleDeg, float distanceM)
Update the sensor with angle (deg) and distance (m)
Definition: RangeSensor.h:86
void setObstacleDirectionDegree(float deg)
Defines the angle to the obstacle in degrees: 0 means forward.
Definition: RangeSensor.h:101
void setObstacleAlertAngle(Angle deg)
Set the alert angle threshold for obstacle detection.
Definition: RangeSensor.h:156
bool setObstacleDistance(Distance dist)
Definition: RangeSensor.h:114
bool hasObstacle() const
Return true if there is an obstacle detected (distance > 0)
Definition: RangeSensor.h:201
void end()
Stop the sensor.
Definition: RangeSensor.h:98
void setObstacleDirection(Angle angle)
Set the obstacle direction using an Angle object.
Definition: RangeSensor.h:104
float getObstacleDirectionDegree() const
Definition: RangeSensor.h:110
float getSpeedFactor(Distance breakingDistance) const
Compute a speed factor (0.0 to 1.0) based on the distance to the obstacle.
Definition: RangeSensor.h:204
float getObstacleDistance() const
Definition: RangeSensor.h:167
void setObstacle(float degree, float distance)
Convenience method to set both the obstacle bearing and distance at once.
Definition: RangeSensor.h:170
void setObstacleAlertDistance(Distance dist)
Set the alert distance threshold for obstacle detection.
Definition: RangeSensor.h:161
Represents a 2D rigid body transform (SE(2)): translation and rotation.
Definition: FrameMgr2D.h:42
DistanceUnit
Supported distance units for conversion and representation.
Definition: Distance.h:10
AngleUnit
Supported angle units for conversion and representation.
Definition: Angle.h:11
Unit
Units for message values.
Definition: Common.h:45
@ AngleDegree
Angle in degrees.
@ Meters
Distance in meters.
Generic message structure for communication, parameterized by value type.
Definition: Message.h:72