WPILibC++ 2024.3.2
Ultrasonic.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <atomic>
8#include <memory>
9#include <thread>
10#include <vector>
11
12#include <hal/SimDevice.h>
13#include <units/length.h>
14#include <units/time.h>
15#include <units/velocity.h>
18
19#include "frc/Counter.h"
20
21namespace frc {
22
23class DigitalInput;
24class DigitalOutput;
25
26/**
27 * Ultrasonic rangefinder class.
28 *
29 * The Ultrasonic rangefinder measures absolute distance based on the round-trip
30 * time of a ping generated by the controller. These sensors use two
31 * transducers, a speaker and a microphone both tuned to the ultrasonic range. A
32 * common ultrasonic sensor, the Daventech SRF04 requires a short pulse to be
33 * generated on a digital channel. This causes the chirp to be emitted. A second
34 * line becomes high as the ping is transmitted and goes low when the echo is
35 * received. The time that the line is high determines the round trip distance
36 * (time of flight).
37 */
39 public wpi::SendableHelper<Ultrasonic> {
40 public:
41 /**
42 * Create an instance of the Ultrasonic Sensor.
43 *
44 * This is designed to support the Daventech SRF04 and Vex ultrasonic sensors.
45 *
46 * @param pingChannel The digital output channel that sends the pulse to
47 * initiate the sensor sending the ping.
48 * @param echoChannel The digital input channel that receives the echo. The
49 * length of time that the echo is high represents the
50 * round trip time of the ping, and the distance.
51 */
52 Ultrasonic(int pingChannel, int echoChannel);
53
54 /**
55 * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo
56 * channel and a DigitalOutput for the ping channel.
57 *
58 * @param pingChannel The digital output object that starts the sensor doing a
59 * ping. Requires a 10uS pulse to start.
60 * @param echoChannel The digital input object that times the return pulse to
61 * determine the range.
62 */
63 Ultrasonic(DigitalOutput* pingChannel, DigitalInput* echoChannel);
64
65 /**
66 * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo
67 * channel and a DigitalOutput for the ping channel.
68 *
69 * @param pingChannel The digital output object that starts the sensor doing a
70 * ping. Requires a 10uS pulse to start.
71 * @param echoChannel The digital input object that times the return pulse to
72 * determine the range.
73 */
74 Ultrasonic(DigitalOutput& pingChannel, DigitalInput& echoChannel);
75
76 /**
77 * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo
78 * channel and a DigitalOutput for the ping channel.
79 *
80 * @param pingChannel The digital output object that starts the sensor doing a
81 * ping. Requires a 10uS pulse to start.
82 * @param echoChannel The digital input object that times the return pulse to
83 * determine the range.
84 */
85 Ultrasonic(std::shared_ptr<DigitalOutput> pingChannel,
86 std::shared_ptr<DigitalInput> echoChannel);
87
88 ~Ultrasonic() override;
89
90 Ultrasonic(Ultrasonic&&) = default;
92
93 /**
94 * Returns the echo channel.
95 *
96 * @return The echo channel.
97 */
98 int GetEchoChannel() const;
99
100 /**
101 * Single ping to ultrasonic sensor.
102 *
103 * Send out a single ping to the ultrasonic sensor. This only works if
104 * automatic (round robin) mode is disabled. A single ping is sent out, and
105 * the counter should count the semi-period when it comes in. The counter is
106 * reset to make the current value invalid.
107 */
108 void Ping();
109
110 /**
111 * Check if there is a valid range measurement.
112 *
113 * The ranges are accumulated in a counter that will increment on each edge of
114 * the echo (return) signal. If the count is not at least 2, then the range
115 * has not yet been measured, and is invalid.
116 */
117 bool IsRangeValid() const;
118
119 /**
120 * Turn Automatic mode on/off.
121 *
122 * When in Automatic mode, all sensors will fire in round robin, waiting a set
123 * time between each sensor.
124 *
125 * @param enabling Set to true if round robin scheduling should start for all
126 * the ultrasonic sensors. This scheduling method assures that
127 * the sensors are non-interfering because no two sensors fire
128 * at the same time. If another scheduling algorithm is
129 * preferred, it can be implemented by pinging the sensors
130 * manually and waiting for the results to come back.
131 */
132 static void SetAutomaticMode(bool enabling);
133
134 /**
135 * Get the range from the ultrasonic sensor.
136 *
137 * @return Range of the target returned from the ultrasonic sensor. If there
138 * is no valid value yet, i.e. at least one measurement hasn't
139 * completed, then return 0.
140 */
141 units::meter_t GetRange() const;
142
143 bool IsEnabled() const;
144
145 void SetEnabled(bool enable);
146
147 void InitSendable(wpi::SendableBuilder& builder) override;
148
149 private:
150 /**
151 * Initialize the Ultrasonic Sensor.
152 *
153 * This is the common code that initializes the ultrasonic sensor given that
154 * there are two digital I/O channels allocated. If the system was running in
155 * automatic mode (round robin) when the new sensor is added, it is stopped,
156 * the sensor is added, then automatic mode is restored.
157 */
158 void Initialize();
159
160 /**
161 * Background task that goes through the list of ultrasonic sensors and pings
162 * each one in turn. The counter is configured to read the timing of the
163 * returned echo pulse.
164 *
165 * DANGER WILL ROBINSON, DANGER WILL ROBINSON:
166 * This code runs as a task and assumes that none of the ultrasonic sensors
167 * will change while it's running. Make sure to disable automatic mode before
168 * touching the list.
169 */
170 static void UltrasonicChecker();
171
172 // Time (usec) for the ping trigger pulse.
173 static constexpr auto kPingTime = 10_us;
174
175 // Max time (ms) between readings.
176 static constexpr auto kMaxUltrasonicTime = 0.1_s;
177 static constexpr auto kSpeedOfSound = 1130_fps;
178
179 // Thread doing the round-robin automatic sensing
180 static std::thread m_thread;
181
182 // Ultrasonic sensors
183 static std::vector<Ultrasonic*> m_sensors;
184
185 // Automatic round-robin mode
186 static std::atomic<bool> m_automaticEnabled;
187
188 std::shared_ptr<DigitalOutput> m_pingChannel;
189 std::shared_ptr<DigitalInput> m_echoChannel;
190 bool m_enabled = false;
191 Counter m_counter;
192
193 hal::SimDevice m_simDevice;
194 hal::SimBoolean m_simRangeValid;
195 hal::SimDouble m_simRange;
196};
197
198} // namespace frc
Class for counting the number of ticks on a digital input channel.
Definition: Counter.h:35
Class to read a digital input.
Definition: DigitalInput.h:27
Class to write to digital outputs.
Definition: DigitalOutput.h:25
Ultrasonic rangefinder class.
Definition: Ultrasonic.h:39
void InitSendable(wpi::SendableBuilder &builder) override
Initializes this Sendable object.
Ultrasonic(Ultrasonic &&)=default
static void SetAutomaticMode(bool enabling)
Turn Automatic mode on/off.
Ultrasonic(std::shared_ptr< DigitalOutput > pingChannel, std::shared_ptr< DigitalInput > echoChannel)
Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo channel and a DigitalOutp...
~Ultrasonic() override
void Ping()
Single ping to ultrasonic sensor.
Ultrasonic(int pingChannel, int echoChannel)
Create an instance of the Ultrasonic Sensor.
void SetEnabled(bool enable)
int GetEchoChannel() const
Returns the echo channel.
Ultrasonic(DigitalOutput &pingChannel, DigitalInput &echoChannel)
Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo channel and a DigitalOutp...
Ultrasonic & operator=(Ultrasonic &&)=default
bool IsEnabled() const
units::meter_t GetRange() const
Get the range from the ultrasonic sensor.
Ultrasonic(DigitalOutput *pingChannel, DigitalInput *echoChannel)
Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo channel and a DigitalOutp...
bool IsRangeValid() const
Check if there is a valid range measurement.
C++ wrapper around a HAL simulator boolean value handle.
Definition: SimDevice.h:608
A move-only C++ wrapper around a HAL simulator device handle.
Definition: SimDevice.h:642
C++ wrapper around a HAL simulator double value handle.
Definition: SimDevice.h:533
Helper class for building Sendable dashboard representations.
Definition: SendableBuilder.h:21
A helper class for use with objects that add themselves to SendableRegistry.
Definition: SendableHelper.h:19
Interface for Sendable objects.
Definition: Sendable.h:16
Definition: AprilTagPoseEstimator.h:15