12#include <unordered_map>
113 std::string name = {});
119 float mountAngleRad = 0.0f,
120 float maxRangeCm = 100.0f,
121 std::string name = {});
129 std::optional<uint16_t>
readAnalog(uint8_t analogPort)
const;
208 return idx < m_wheelOmega.size() ? m_wheelOmega[idx] : 0.0f;
211 const std::vector<Pose2D>&
trace() const noexcept {
return m_trace; }
215 static constexpr std::size_t kNumMotorPorts = 4;
216 static constexpr std::size_t kMaxWheels = 4;
217 static constexpr std::size_t kLeft = 0;
218 static constexpr std::size_t kRight = 1;
220 static constexpr std::size_t kFL = 0;
221 static constexpr std::size_t kFR = 1;
222 static constexpr std::size_t kBL = 2;
223 static constexpr std::size_t kBR = 3;
225 enum class SensorKind : uint8_t { Line, Distance };
229 SensorKind kind{SensorKind::Line};
231 float mountAngleRad{0.0f};
232 float maxRangeCm{100.0f};
235 RobotConfig m_robot{};
236 SimMotorMap m_motors{};
238 int m_currentLayer{0};
243 std::array<float, kNumMotorPorts> m_motorTargetOmega{};
244 std::array<float, kMaxWheels> m_wheelOmega{};
245 std::array<float, kMaxWheels> m_wheelAngleRad{};
246 float m_yawRateRadS{0.0f};
247 std::vector<Pose2D> m_trace;
248 std::unordered_map<uint8_t, SensorEntry> m_sensors;
252 void applyLayerTransitions(
const Pose2D& prev,
const Pose2D& cur);
254 float targetOmega(std::size_t wheelIndex)
const;
255 uint16_t sampleLineSensor(
const SensorEntry&)
const;
256 uint16_t sampleDistanceSensor(
const SensorEntry&)
const;
257 std::size_t portToWheelIndex(uint8_t port)
const;
258 bool wheelInverted(std::size_t wheelIndex)
const;
259 uint8_t wheelPort(std::size_t wheelIndex)
const;
260 std::size_t activeWheelCount() const noexcept;
264 mutable std::mt19937 m_rng{42};
265 mutable std::normal_distribution<float> m_noiseDist{0.0f, 1.0f};
Pose2D odometryPose() const noexcept
float wheelOmega(std::size_t idx) const noexcept
bool isSensorOnBlackLine(const SensorMount &mount) const
const std::vector< Pose2D > & trace() const noexcept
float wheelOmegaRight() const noexcept
int currentLayer() const noexcept
OdometryDrift odometryDrift() const noexcept
Pose2D pose() const noexcept
void setMap(WorldMap map)
std::optional< uint16_t > readAnalog(uint8_t analogPort) const
const WorldMap & map() const noexcept
void setPose(const Pose2D &pose)
void detachSensor(uint8_t analogPort)
Detach any sensor bound to analogPort.
Vec2 sensorWorldPosition(const SensorMount &mount) const
World-frame position of a sensor mount attached to this robot.
int motorPositionTicks(uint8_t port) const
void setCurrentLayer(int idx) noexcept
void setOdometryDrift(float vxBias, float vyBias, float yawBias) noexcept
void configure(const RobotConfig &robot, const SimMotorMap &motors)
void attachLineSensor(uint8_t analogPort, float forwardCm, float strafeCm, std::string name={})
void setMotorCommand(uint8_t port, int signedPercent)
float yawRateRadS() const noexcept
int motorBemf(uint8_t port) const
void setMotorVelocityCommand(uint8_t port, int bemfUnits)
float wheelOmegaLeft() const noexcept
void attachDistanceSensor(uint8_t analogPort, float forwardCm, float strafeCm, float mountAngleRad=0.0f, float maxRangeCm=100.0f, std::string name={})
libstp::map::WorldMap WorldMap
@ Differential
Two wheels (left/right). Default for legacy configs.
@ Mecanum
Four wheels (FL/FR/BL/BR) with 45° rollers.
float motorTimeConstantSec
float coulombFrictionRadSS
float maxWheelVelocityRadS