-
Notifications
You must be signed in to change notification settings - Fork 0
/
physics.py
133 lines (111 loc) · 4.65 KB
/
physics.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from __future__ import annotations
import math
import typing
import phoenix6
import phoenix6.unmanaged
import wpilib
from pyfrc.physics.core import PhysicsInterface
from wpilib.simulation import DCMotorSim, SimDeviceSim
from wpimath.kinematics import SwerveDrive4Kinematics
from wpimath.system.plant import DCMotor, LinearSystemId
from wpimath.units import kilogram_square_meters
from photonlibpy.simulation import PhotonCameraSim, SimCameraProperties, VisionSystemSim
from components.chassis import SwerveModule
from utilities import game
if typing.TYPE_CHECKING:
from robot import MyRobot
class SimpleTalonFXMotorSim:
def __init__(
self, motor: phoenix6.hardware.TalonFX, units_per_rev: float, kV: float
) -> None:
self.sim_state = motor.sim_state
self.sim_state.set_supply_voltage(12.0)
self.kV = kV # volt seconds per unit
self.units_per_rev = units_per_rev
def update(self, dt: float) -> None:
voltage = self.sim_state.motor_voltage
velocity = voltage / self.kV # units per second
velocity_rps = velocity * self.units_per_rev
self.sim_state.set_rotor_velocity(velocity_rps)
self.sim_state.add_rotor_position(velocity_rps * dt)
class Falcon500MotorSim:
def __init__(
self,
*motors: phoenix6.hardware.TalonFX,
# Reduction between motor and encoder readings, as output over input.
# If the mechanism spins slower than the motor, this number should be greater than one.
gearing: float,
moi: kilogram_square_meters,
):
self.falcon = DCMotor.falcon500(len(motors))
self.plant = LinearSystemId.DCMotorSystem(self.falcon, moi, gearing)
self.gearing = gearing
self.sim_states = [motor.sim_state for motor in motors]
for sim_state in self.sim_states:
sim_state.set_supply_voltage(12.0)
self.motor_sim = DCMotorSim(self.plant, self.falcon)
def update(self, dt: float) -> None:
voltage = self.sim_states[0].motor_voltage
self.motor_sim.setInputVoltage(voltage)
self.motor_sim.update(dt)
motor_rev_per_mechanism_rad = self.gearing / math.tau
for sim_state in self.sim_states:
sim_state.set_raw_rotor_position(
self.motor_sim.getAngularPosition() * motor_rev_per_mechanism_rad
)
sim_state.set_rotor_velocity(
self.motor_sim.getAngularVelocity() * motor_rev_per_mechanism_rad
)
class PhysicsEngine:
def __init__(self, physics_controller: PhysicsInterface, robot: MyRobot):
self.physics_controller = physics_controller
self.kinematics: SwerveDrive4Kinematics = robot.chassis.kinematics
self.swerve_modules: tuple[
SwerveModule, SwerveModule, SwerveModule, SwerveModule
] = robot.chassis.modules
# Motors
self.wheels = [
SimpleTalonFXMotorSim(
module.drive,
units_per_rev=1 / module.DRIVE_MOTOR_REV_TO_METRES,
kV=2.7,
)
for module in robot.chassis.modules
]
self.steer = [
Falcon500MotorSim(
module.steer,
gearing=1 / module.STEER_GEAR_RATIO,
# measured from MKCad CAD
moi=0.0009972,
)
for module in robot.chassis.modules
]
self.imu = SimDeviceSim("navX-Sensor", 4)
self.imu_yaw = self.imu.getDouble("Yaw")
self.vision = VisionSystemSim("main")
self.vision.addAprilTags(game.apriltag_layout)
properties = SimCameraProperties.OV9281_1280_720()
self.camera = PhotonCameraSim(robot.vision.camera, properties)
self.camera.setMaxSightRange(5.0)
self.vision.addCamera(self.camera, robot.vision.robot_to_camera)
def update_sim(self, now: float, tm_diff: float) -> None:
# Enable the Phoenix6 simulated devices
# TODO: delete when phoenix6 integrates with wpilib
if wpilib.DriverStation.isEnabled():
phoenix6.unmanaged.feed_enable(0.1)
for wheel in self.wheels:
wheel.update(tm_diff)
for steer in self.steer:
steer.update(tm_diff)
speeds = self.kinematics.toChassisSpeeds(
(
self.swerve_modules[0].get(),
self.swerve_modules[1].get(),
self.swerve_modules[2].get(),
self.swerve_modules[3].get(),
)
)
self.imu_yaw.set(self.imu_yaw.get() - math.degrees(speeds.omega * tm_diff))
self.physics_controller.drive(speeds, tm_diff)
self.vision.update(self.physics_controller.get_pose())