TinyRobotics
Loading...
Searching...
No Matches
CameraLineFollower.h
1
2#pragma once
3#include <stddef.h>
4#include <stdint.h>
5#include "TinyRobotics/communication/Message.h"
6#include "TinyRobotics/communication/MessageSource.h"
7
8namespace tinyrobotics {
9
10/**
11 * @class CameraLineFollower
12 * @ingroup sensors
13 * @brief Simple line-following algorithm for grayscale camera images.
14 *
15 * This class scans a horizontal row of a grayscale image (e.g., from a camera or line sensor)
16 * to detect the center of the widest dark line (such as a tape or path on the floor).
17 * It is useful for basic line-following robots.
18 *
19 * Features:
20 * - Scans a row near the bottom of the image for the widest dark segment
21 * - Returns the x position of the detected line center and error from image center
22 * - Configurable pixel threshold and minimum line width
23 * - Remembers last seen line position for robustness
24 * - Lightweight, suitable for embedded/Arduino use
25 *
26 * @note Expected format:
27 * - The input image should be a grayscale buffer (uint8_t*)
28 * - The pixel intensity is expected to be in the range 0 (black) to 255
29 * (white).
30 * - The layout of the image buffer should be row-major (i.e., pixel at (x,y) is
31 * at index y*width + x).
32 * - on ESP32 e.g. PIXFORMAT_GRAYSCALE, FRAMESIZE_QVGA (320 x 240)
33 *
34 * Usage Example:
35 * @code
36 * CameraLineFollower follower(80, 5); // threshold=80, minWidth=5
37 * auto result = follower.process(image, width, height);
38 * if (result.found) {
39 * // Use result.position or result.error for steering
40 * }
41 * @endcode
42 */
43
44class CameraLineFollower : public MessageSource {
45 public:
46 struct Result {
47 bool found;
48 int position; // x coordinate of line center
49 int error; // deviation from image center
50 };
51
52 CameraLineFollower(uint8_t threshold = 80, // pixel threshold
53 int minWidth = 3 // minimum line width (pixels)
54 )
55 : _threshold(threshold), _minWidth(minWidth), _lastPosition(-1) {}
56
57 Result process(const uint8_t* image, size_t width, size_t height) {
58 if (!image || width == 0 || height == 0) {
59 return {false, 0, 0};
60 }
61
62 // Scan near bottom (closer to robot)
63 size_t y = (height * 3) / 4;
64
65 int bestStart = -1;
66 int bestEnd = -1;
67 int currentStart = -1;
68
69 // Find longest dark segment
70 for (size_t x = 0; x < width; x++) {
71 uint8_t pixel = image[y * width + x];
72
73 bool isLine = (pixel < _threshold); // dark line
74
75 if (isLine) {
76 if (currentStart < 0) {
77 currentStart = x;
78 }
79 } else {
80 if (currentStart >= 0) {
81 int segmentWidth = x - currentStart;
82
83 if (segmentWidth >= _minWidth) {
84 if (segmentWidth > (bestEnd - bestStart)) {
85 bestStart = currentStart;
86 bestEnd = x;
87 }
88 }
89 currentStart = -1;
90 }
91 }
92 }
93
94 // Handle line reaching end of row
95 if (currentStart >= 0) {
96 int segmentWidth = width - currentStart;
97 if (segmentWidth >= _minWidth) {
98 bestStart = currentStart;
99 bestEnd = width;
100 }
101 }
102
103 if (bestStart < 0) {
104 // fallback to last known position
105 if (_lastPosition >= 0) {
106 int error = _lastPosition - (int)(width / 2);
107 return {false, _lastPosition, error};
108 }
109 return {false, 0, 0};
110 }
111
112 int position = (bestStart + bestEnd) / 2;
113
114 // simple smoothing
115 if (_lastPosition >= 0) {
116 position = (_lastPosition * 3 + position) / 4;
117 }
118
119 _lastPosition = position;
120
121 int center = width / 2;
122 int error = position - center;
123
124 // publish angle to direction of movement
125 Message<float> msgError(MessageContent::Error, error, Unit::Pixel);
126 msgError.origin = MessageOrigin::Camera;
127 sendMessage(msgError);
128
129 return {true, position, error};
130 }
131
132 protected:
133 uint8_t _threshold;
134 int _minWidth;
135 int _lastPosition;
136};
137
138} // namespace tinyrobotics
Simple line-following algorithm for grayscale camera images.
Definition: CameraLineFollower.h:44
Base class for message sources in the TinyRobotics communication framework.
Definition: MessageSource.h:35
Definition: CameraLineFollower.h:46
Generic message structure for communication, parameterized by value type.
Definition: Message.h:72