JSim 2026.06.01-p(1)
Loading...
Searching...
No Matches
shooter_wheel.hpp
Go to the documentation of this file.
1// Copyright (c) JSim contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the LGPLv3 license file in the root directory of this project.
4
5#pragma once
6
7#include <algorithm>
8#include <cmath>
9
10namespace frcsim {
11
15 public:
17 struct MotorConfig {
18 // Motor free speed at nominal voltage.
19 double free_speed_radps{600.0};
20
21 // Stall torque at nominal voltage.
22 double stall_torque_nm{2.0};
23
24 // Approximate stall current for simple current limiting.
25 double stall_current_a{120.0};
26
27 // Applied supply voltage for normalization.
28 double nominal_voltage_v{12.0};
29
35 static MotorConfig falcon500(int motor_count = 1) {
36 const int count = std::max(1, motor_count);
37 MotorConfig cfg{};
38 cfg.free_speed_radps = 668.0;
39 cfg.stall_torque_nm = 4.69 * static_cast<double>(count);
40 cfg.stall_current_a = 257.0 * static_cast<double>(count);
41 cfg.nominal_voltage_v = 12.0;
42 return cfg;
43 }
44
50 static MotorConfig neoV1_1(int motor_count = 1) {
51 const int count = std::max(1, motor_count);
52 MotorConfig cfg{};
53 cfg.free_speed_radps = 594.0;
54 cfg.stall_torque_nm = 3.36 * static_cast<double>(count);
55 cfg.stall_current_a = 166.0 * static_cast<double>(count);
56 cfg.nominal_voltage_v = 12.0;
57 return cfg;
58 }
59
65 static MotorConfig krakenX60(int motor_count = 1) {
66 const int count = std::max(1, motor_count);
67 MotorConfig cfg{};
68 cfg.free_speed_radps = 628.0;
69 cfg.stall_torque_nm = 7.09 * static_cast<double>(count);
70 cfg.stall_current_a = 366.0 * static_cast<double>(count);
71 cfg.nominal_voltage_v = 12.0;
72 return cfg;
73 }
74 };
75
77 struct WheelConfig {
78 double radius_m{0.05};
79 double inertia_kgm2{0.0025};
81
82 // Fraction of wheel tangential speed transferred to ball exit speed.
83 double ball_coupling{0.88};
84 };
85
88 struct ControlInput {
89 // Open-loop voltage command.
90 double command_voltage_v{0.0};
91
92 // If true, internal velocity loop maps target speed to voltage.
94 double target_speed_radps{0.0};
95 double velocity_kp{0.03};
96
97 // Optional stator current clamp, <=0 disables limiting.
98 double current_limit_a{0.0};
99
100 // Voltage needed to overcome static friction at very low speeds.
102 };
103
104 FlywheelWheelSim() = default;
105
112 FlywheelWheelSim(const MotorConfig& motor, const WheelConfig& wheel)
113 : motor_(motor), wheel_(wheel) {}
114
116 void setMotorConfig(const MotorConfig& motor) { motor_ = motor; }
118 void setWheelConfig(const WheelConfig& wheel) { wheel_ = wheel; }
119
122 const MotorConfig& motorConfig() const { return motor_; }
125 const WheelConfig& wheelConfig() const { return wheel_; }
126
129 void setAngularSpeedRadps(double omega_radps) { omega_radps_ = omega_radps; }
132 double angularSpeedRadps() const { return omega_radps_; }
133
136 double surfaceSpeedMps() const {
137 return omega_radps_ * std::max(0.0, wheel_.radius_m);
138 }
139
143 return std::max(0.0,
144 surfaceSpeedMps() * std::max(0.0, wheel_.ball_coupling));
145 }
146
152 void step(double dt_s, const ControlInput& control) {
153 if (dt_s <= 0.0) {
154 return;
155 }
156
157 const double effective_nominal_v = std::max(1e-9, motor_.nominal_voltage_v);
158 const double effective_free_speed = std::max(1e-9, motor_.free_speed_radps);
159 const double kt = motor_.stall_torque_nm / effective_nominal_v;
160
161 double voltage = control.command_voltage_v;
162 if (control.velocity_closed_loop) {
163 const double error = control.target_speed_radps - omega_radps_;
164 voltage = control.velocity_kp * error;
165 }
166 voltage = std::clamp(voltage, -effective_nominal_v, effective_nominal_v);
167
168 if (std::abs(omega_radps_) < 1e-3) {
169 const double v_deadband = std::max(0.0, control.friction_voltage_v);
170 if (std::abs(voltage) <= v_deadband) {
171 voltage = 0.0;
172 } else {
173 voltage = std::copysign(std::max(0.0, std::abs(voltage) - v_deadband),
174 voltage);
175 }
176 }
177
178 // Linearized DC motor: omega = free_speed*(1 - tau/stall_torque) for given
179 // normalized voltage.
180 const double voltage_scale = voltage / effective_nominal_v;
181 const double no_load_speed = effective_free_speed * voltage_scale;
182 const double speed_error = no_load_speed - omega_radps_;
183 double available_torque =
184 motor_.stall_torque_nm * speed_error / effective_free_speed;
185
186 if (control.current_limit_a > 0.0 && motor_.stall_current_a > 0.0) {
187 const double torque_per_amp =
188 motor_.stall_torque_nm / motor_.stall_current_a;
189 const double max_torque_from_limit =
190 torque_per_amp * control.current_limit_a;
191 available_torque = std::clamp(available_torque, -max_torque_from_limit,
192 max_torque_from_limit);
193 }
194
195 const double friction_torque =
196 wheel_.viscous_friction_nm_per_radps * omega_radps_;
197 const double net_torque = available_torque - friction_torque;
198
199 const double inertia = std::max(1e-9, wheel_.inertia_kgm2);
200 const double alpha_radps2 = net_torque / inertia;
201 omega_radps_ += alpha_radps2 * dt_s;
202 }
203
204 private:
205 MotorConfig motor_{};
206 WheelConfig wheel_{};
207 double omega_radps_{0.0};
208};
209
210} // namespace frcsim
void setMotorConfig(const MotorConfig &motor)
Sets motor constants.
Definition shooter_wheel.hpp:116
void setWheelConfig(const WheelConfig &wheel)
Sets wheel constants.
Definition shooter_wheel.hpp:118
double angularSpeedRadps() const
Returns current wheel angular speed.
Definition shooter_wheel.hpp:132
const MotorConfig & motorConfig() const
Returns motor configuration.
Definition shooter_wheel.hpp:122
double surfaceSpeedMps() const
Computes tangential speed at wheel perimeter.
Definition shooter_wheel.hpp:136
const WheelConfig & wheelConfig() const
Returns wheel configuration.
Definition shooter_wheel.hpp:125
void setAngularSpeedRadps(double omega_radps)
Forces internal angular speed state.
Definition shooter_wheel.hpp:129
void step(double dt_s, const ControlInput &control)
Advances the flywheel wheel state by one step.
Definition shooter_wheel.hpp:152
double estimatedExitVelocityMps() const
Estimates ball exit speed from current surface speed and coupling factor.
Definition shooter_wheel.hpp:142
FlywheelWheelSim(const MotorConfig &motor, const WheelConfig &wheel)
Constructs a wheel simulator with explicit motor and wheel configuration.
Definition shooter_wheel.hpp:112
Definition vector.hpp:13
Control inputs for open-loop or simple internal velocity-loop operation.
Definition shooter_wheel.hpp:88
double velocity_kp
Definition shooter_wheel.hpp:95
double friction_voltage_v
Definition shooter_wheel.hpp:101
double command_voltage_v
Definition shooter_wheel.hpp:90
double target_speed_radps
Definition shooter_wheel.hpp:94
double current_limit_a
Definition shooter_wheel.hpp:98
bool velocity_closed_loop
Definition shooter_wheel.hpp:93
DC motor approximation constants for flywheel drive.
Definition shooter_wheel.hpp:17
double stall_current_a
Definition shooter_wheel.hpp:25
double nominal_voltage_v
Definition shooter_wheel.hpp:28
static MotorConfig falcon500(int motor_count=1)
Returns Falcon 500 aggregate motor constants.
Definition shooter_wheel.hpp:35
double free_speed_radps
Definition shooter_wheel.hpp:19
static MotorConfig neoV1_1(int motor_count=1)
Returns NEO V1.1 aggregate motor constants.
Definition shooter_wheel.hpp:50
double stall_torque_nm
Definition shooter_wheel.hpp:22
static MotorConfig krakenX60(int motor_count=1)
Returns Kraken X60 aggregate motor constants.
Definition shooter_wheel.hpp:65
Flywheel wheel inertial/friction and ball-coupling parameters.
Definition shooter_wheel.hpp:77
double radius_m
Definition shooter_wheel.hpp:78
double viscous_friction_nm_per_radps
Definition shooter_wheel.hpp:80
double ball_coupling
Definition shooter_wheel.hpp:83
double inertia_kgm2
Definition shooter_wheel.hpp:79