YAMS
Yet Another Mechanism System
Loading...
Searching...
No Matches
SwerveInputStreamTelemetry.hpp
Go to the documentation of this file.
1// Copyright (c) 2026 Yet Another Software Suite
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#pragma once
5
6#include <cmath>
7#include <functional>
8#include <memory>
9#include <optional>
10#include <string>
11#include <string_view>
12#include <utility>
13#include <vector>
14#include <wpi/commands2/CommandPtr.hpp>
15#include <wpi/commands2/Commands.hpp>
16#include <wpi/nt/BooleanTopic.hpp>
17#include <wpi/nt/DoubleTopic.hpp>
18#include <wpi/nt/NetworkTable.hpp>
19#include <wpi/nt/NetworkTableInstance.hpp>
20#include <wpi/nt/StringTopic.hpp>
21#include <wpi/tunables/Tunables.hpp>
22
26
28
46template <size_t NumModules = 4>
48 public:
50
60 TelemetryVerbosity verbosity)
61 : m_stream{&stream},
62 m_liveTuningPath{"Tuning/SwerveInputStream/" + std::string{name} + "/Live Tuning"} {
63 auto instance = wpi::nt::NetworkTableInstance::GetDefault();
64 auto dataTable = instance.GetTable("SwerveInputStream")->GetSubTable(name);
65 m_modePublisher = dataTable->GetStringTopic("mode").Publish();
66
67 if (verbosity == TelemetryVerbosity::MEDIUM || verbosity == TelemetryVerbosity::HIGH) {
68 PublishConfig(*dataTable);
69 }
70 if (verbosity == TelemetryVerbosity::HIGH) {
71 AddTunableValues(
72 *instance.GetTable("Tuning")->GetSubTable("SwerveInputStream")->GetSubTable(name));
73 // No requirements, so tuning does not interrupt the command driving with the stream.
74 m_liveTuningCommand.emplace(
75 wpi::cmd::Run([this] { ApplyTuningValues(); }).WithName("Live Tuning"));
77 wpi::tunables::Publish(m_liveTuningPath, *m_liveTuningCommand->get());
78 }
80 }
81
84
87 if (m_liveTuningCommand) {
88 m_liveTuningCommand->Cancel();
89 wpi::tunables::Remove(m_liveTuningPath);
90 }
91 }
92
98 m_modePublisher.Set(m_stream->GetCurrentModeName());
99 for (auto& publish : m_configPublishers) {
100 publish();
101 }
102 }
103
109 for (auto& value : m_doubles) {
110 value.Update();
111 }
112 for (auto& value : m_booleans) {
113 value.Update();
114 }
115 }
116
123 std::optional<std::reference_wrapper<wpi::cmd::Command>> GetLiveTuningCommand() {
124 if (!m_liveTuningCommand) {
125 return std::nullopt;
126 }
127 return std::ref(*m_liveTuningCommand->get());
128 }
129
130 private:
132 template <typename T, typename Entry>
133 class TunableValue {
134 public:
144 TunableValue(wpi::nt::NetworkTable& table, std::string_view key, std::function<T()> getter,
145 std::function<void(T)> setter,
146 std::function<bool(T)> valid = [](T) { return true; })
147 : m_getter{std::move(getter)},
148 m_setter{std::move(setter)},
149 m_valid{std::move(valid)},
150 m_lastValue{m_getter()},
151 m_entry{MakeEntry(table, key, m_lastValue)} {
152 m_entry.Set(m_lastValue);
153 }
154
156 void Update() {
157 T published = m_entry.Get();
158 if (published != m_lastValue && m_valid(published)) {
159 m_setter(published);
160 }
161 T current = m_getter();
162 if (current != published) {
163 m_entry.Set(current);
164 }
165 m_lastValue = current;
166 }
167
168 private:
169 static Entry MakeEntry(wpi::nt::NetworkTable& table, std::string_view key, T defaultValue) {
170 if constexpr (std::is_same_v<T, bool>) {
171 return table.GetBooleanTopic(key).GetEntry(defaultValue);
172 } else {
173 return table.GetDoubleTopic(key).GetEntry(defaultValue);
174 }
175 }
176
177 std::function<T()> m_getter;
178 std::function<void(T)> m_setter;
179 std::function<bool(T)> m_valid;
181 T m_lastValue;
182 Entry m_entry;
183 };
184
185 void PublishConfig(wpi::nt::NetworkTable& table) {
186 PublishDouble(table, "deadband", [this] { return m_stream->GetAxisDeadband(); });
187 PublishDouble(table, "translationScale", [this] { return m_stream->GetTranslationAxisScale(); });
188 PublishDouble(table, "rotationScale", [this] { return m_stream->GetOmegaAxisScale(); });
189 PublishDouble(table, "maxLinearVelocity",
190 [this] { return m_stream->GetMaximumChassisLinearVelocity().value(); });
191 PublishDouble(table, "maxAngularVelocity",
192 [this] { return m_stream->GetMaximumChassisAngularVelocity().value(); });
193 PublishBoolean(table, "translationCube", [this] { return m_stream->IsTranslationCubeEnabled(); });
194 PublishBoolean(table, "rotationCube", [this] { return m_stream->IsOmegaCubeEnabled(); });
195 PublishBoolean(table, "allianceRelative",
196 [this] { return m_stream->IsAllianceRelativeEnabled(); });
197 PublishBoolean(table, "robotRelative", [this] { return m_stream->IsRobotRelativeEnabled(); });
198 }
199
200 void PublishDouble(wpi::nt::NetworkTable& table, std::string_view key,
201 std::function<double()> value) {
202 auto publisher =
203 std::make_shared<wpi::nt::DoublePublisher>(table.GetDoubleTopic(key).Publish());
204 m_configPublishers.emplace_back(
205 [publisher, value = std::move(value)] { publisher->Set(value()); });
206 }
207
208 void PublishBoolean(wpi::nt::NetworkTable& table, std::string_view key,
209 std::function<bool()> value) {
210 auto publisher =
211 std::make_shared<wpi::nt::BooleanPublisher>(table.GetBooleanTopic(key).Publish());
212 m_configPublishers.emplace_back(
213 [publisher, value = std::move(value)] { publisher->Set(value()); });
214 }
215
216 void AddTunableValues(wpi::nt::NetworkTable& table) {
217 m_doubles.emplace_back(
218 table, "deadband", [this] { return m_stream->GetAxisDeadband(); },
219 [this](double value) { m_stream->SetAxisDeadband(value); },
220 [](double value) { return value >= 0.0 && value < 1.0; });
221 m_doubles.emplace_back(
222 table, "translationScale", [this] { return m_stream->GetTranslationAxisScale(); },
223 [this](double value) { m_stream->SetTranslationAxisScale(value); },
224 [](double value) { return value > 0.0 && value <= 1.0; });
225 m_doubles.emplace_back(
226 table, "rotationScale", [this] { return m_stream->GetOmegaAxisScale(); },
227 [this](double value) { m_stream->SetOmegaAxisScale(value); },
228 [](double value) { return value > 0.0 && value <= 1.0; });
229 m_doubles.emplace_back(
230 table, "maxLinearVelocity",
231 [this] { return m_stream->GetMaximumChassisLinearVelocity().value(); },
232 [this](double value) {
233 m_stream->SetMaximumChassisLinearVelocity(wpi::units::meters_per_second_t{value});
234 },
235 [](double value) { return value > 0.0 && std::isfinite(value); });
236 m_doubles.emplace_back(
237 table, "maxAngularVelocity",
238 [this] { return m_stream->GetMaximumChassisAngularVelocity().value(); },
239 [this](double value) {
240 m_stream->SetMaximumChassisAngularVelocity(wpi::units::radians_per_second_t{value});
241 },
242 [](double value) { return value > 0.0 && std::isfinite(value); });
243 m_booleans.emplace_back(
244 table, "translationCube", [this] { return m_stream->IsTranslationCubeEnabled(); },
245 [this](bool value) { m_stream->SetTranslationCubeEnabled(value); });
246 m_booleans.emplace_back(
247 table, "rotationCube", [this] { return m_stream->IsOmegaCubeEnabled(); },
248 [this](bool value) { m_stream->SetOmegaCubeEnabled(value); });
249 m_booleans.emplace_back(
250 table, "allianceRelative", [this] { return m_stream->IsAllianceRelativeEnabled(); },
251 [this](bool value) { m_stream->SetAllianceRelativeEnabled(value); });
252 m_booleans.emplace_back(
253 table, "robotRelative", [this] { return m_stream->IsRobotRelativeEnabled(); },
254 [this](bool value) { m_stream->SetRobotRelativeEnabled(value); });
255 }
256
257 SwerveInputStream<NumModules>* m_stream;
258 std::string m_liveTuningPath;
259 wpi::nt::StringPublisher m_modePublisher;
261 std::vector<std::function<void()>> m_configPublishers;
263 std::vector<TunableValue<double, wpi::nt::DoubleEntry>> m_doubles;
264 std::vector<TunableValue<bool, wpi::nt::BooleanEntry>> m_booleans;
266 std::optional<wpi::cmd::CommandPtr> m_liveTuningCommand;
267};
268
269} // namespace yams::mechanisms::swerve::utility
motorcontrollers::SmartMotorControllerConfig::TelemetryVerbosity TelemetryVerbosity
Definition SwerveDriveConfig.hpp:40
Definition SwerveInputStreamTelemetry.hpp:47
~SwerveInputStreamTelemetry()
Definition SwerveInputStreamTelemetry.hpp:86
std::optional< std::reference_wrapper< wpi::cmd::Command > > GetLiveTuningCommand()
Definition SwerveInputStreamTelemetry.hpp:123
void ApplyTuningValues()
Definition SwerveInputStreamTelemetry.hpp:108
SwerveInputStreamTelemetry & operator=(const SwerveInputStreamTelemetry &)=delete
void UpdateTelemetry()
Definition SwerveInputStreamTelemetry.hpp:97
SwerveInputStreamTelemetry(SwerveInputStream< NumModules > &stream, std::string_view name, TelemetryVerbosity verbosity)
Definition SwerveInputStreamTelemetry.hpp:59
SwerveInputStreamTelemetry(const SwerveInputStreamTelemetry &)=delete
Definition SwerveInputStream.hpp:40
TelemetryVerbosity
Definition SmartMotorControllerConfig.hpp:72
Definition SwerveInputStream.hpp:34
void EnsureTuningTunableBackend()
Definition NetworkTablesBackends.hpp:57