Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chassis update #5

Merged
merged 62 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
ad0fcd0
exact 2023 chassis code copied
outsidermm Jan 3, 2024
601ca5c
created motor and encoder object and reduced CAN status frame rates u…
outsidermm Jan 4, 2024
ea0fe40
Configuration of steer and drive motor updated
outsidermm Jan 4, 2024
2af6275
method get_angle_absolute updated
outsidermm Jan 4, 2024
579e119
method get_angle_integrated updated
outsidermm Jan 4, 2024
63b3d01
method get_speed updated
outsidermm Jan 4, 2024
4acfcb5
method get_distance_traveled updated
outsidermm Jan 4, 2024
30454d1
renamed controllers to componenets folder
fotnitfpro000 Jan 4, 2024
c76db59
moved chassis.py from controller to components
outsidermm Jan 4, 2024
a6c1fd7
updated feedback method get_drive_current
outsidermm Jan 5, 2024
6d062ac
updated sync_steer_encoders method
outsidermm Jan 5, 2024
539ffb6
deleted 2023 ctre import
outsidermm Jan 5, 2024
b9595a5
deleted old code
outsidermm Jan 5, 2024
e488570
deleted more old code
outsidermm Jan 5, 2024
17e4168
seperated drive and steer pid/ff constant configs
outsidermm Jan 5, 2024
ec76c26
deleted more outdated code
outsidermm Jan 5, 2024
4974ea9
updated the set method
outsidermm Jan 5, 2024
71e600c
deleted commented out code
outsidermm Jan 5, 2024
c6e6b2e
tuple for toChassisSpeed
outsidermm Jan 6, 2024
eece320
made drive pid and ff self for physic sim
outsidermm Jan 6, 2024
6223c63
rebase off main
outsidermm Jan 6, 2024
a728e34
rebase off main wut
outsidermm Jan 6, 2024
04de0c3
different method for configuring the gains
outsidermm Jan 6, 2024
80a81c1
comment
outsidermm Jan 6, 2024
e282ba2
using slot0 by default
outsidermm Jan 6, 2024
d40c025
using slot 0 by default
outsidermm Jan 6, 2024
906d5bc
convert statussignal to its value and return the rotor sensor (integr…
outsidermm Jan 6, 2024
f2a6e2a
oops
outsidermm Jan 6, 2024
dd4bab0
from bool to enum
outsidermm Jan 6, 2024
9cc1edc
ooops
outsidermm Jan 6, 2024
adea575
use the value instead of statussignal
outsidermm Jan 6, 2024
c4a8355
add position as its constructor argument
outsidermm Jan 6, 2024
13c4909
get sim-state through another method
outsidermm Jan 6, 2024
b273aff
variable not a method
outsidermm Jan 6, 2024
65d9a6a
keyword arg for updating statussignal update freq
outsidermm Jan 8, 2024
2f1eb3c
added method for module current in swervemod
outsidermm Jan 8, 2024
2fb561e
unit conversion
outsidermm Jan 8, 2024
24981dd
unit conversion
outsidermm Jan 8, 2024
e17790d
error
outsidermm Jan 8, 2024
6412529
converted previous kp to new kp
outsidermm Jan 8, 2024
827f7af
not using talon config ff and using wpimath ff
outsidermm Jan 8, 2024
f98db2e
error
outsidermm Jan 8, 2024
c6b5fc8
implemented gear ratios in config
outsidermm Jan 8, 2024
58e5454
made steer pid unit adjusted
outsidermm Jan 9, 2024
a51d18c
renamed drive pid var
outsidermm Jan 9, 2024
2bbe14e
changed p const based on diff voltage compensation value
outsidermm Jan 9, 2024
7acddca
deleted comments
outsidermm Jan 9, 2024
e559ee0
added comments
outsidermm Jan 9, 2024
cb0149d
made steer with no volt comp
outsidermm Jan 9, 2024
1f33ae8
modified the units for ff and construct with velocity
outsidermm Jan 9, 2024
25ae336
Enable phoenix6 simulation
auscompgeek Jan 9, 2024
04a6831
cleaner code
outsidermm Jan 9, 2024
cc1af4a
clean
outsidermm Jan 9, 2024
14a48d4
renamed sim_collection to sim_state to match talonfx sim object
outsidermm Jan 9, 2024
936662b
simpler
outsidermm Jan 9, 2024
fa27562
added debug
outsidermm Jan 9, 2024
e65f512
Co-authored-by: Lucien Morey <[email protected]>
outsidermm Jan 9, 2024
5a412ca
Delete applying encorder configs
DawnDroppingBears Jan 12, 2024
3b5bdd6
Fix things
DawnDroppingBears Jan 12, 2024
6c1cfa6
fix pre-commit problems
Tsunami014 Jan 13, 2024
a3b71b9
remove print statements
LucienMorey Jan 13, 2024
261f21c
rename module current getter to drive current getter
LucienMorey Jan 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 87 additions & 62 deletions components/chassis.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from logging import Logger
import math

import phoenix5
import phoenix5.sensors
from phoenix6.hardware import TalonFX, CANcoder

Check failure on line 3 in components/chassis.py

View workflow job for this annotation

GitHub Actions / mypy

Skipping analyzing "phoenix6.hardware": module is installed, but missing library stubs or py.typed marker
from phoenix6.controls import VoltageOut, VelocityVoltage, PositionDutyCycle

Check failure on line 4 in components/chassis.py

View workflow job for this annotation

GitHub Actions / mypy

Skipping analyzing "phoenix6.controls": module is installed, but missing library stubs or py.typed marker
from phoenix6.signals import NeutralModeValue

Check failure on line 5 in components/chassis.py

View workflow job for this annotation

GitHub Actions / mypy

Skipping analyzing "phoenix6.signals": module is installed, but missing library stubs or py.typed marker
from phoenix6.configs import (

Check failure on line 6 in components/chassis.py

View workflow job for this annotation

GitHub Actions / mypy

Skipping analyzing "phoenix6.configs": module is installed, but missing library stubs or py.typed marker
config_groups,
MotorOutputConfigs,
FeedbackConfigs,
Slot0Configs,
)
import magicbot
import navx
import wpilib
Expand All @@ -19,7 +25,7 @@
from magicbot import feedback

from utilities.functions import constrain_angle, rate_limit_module
from utilities.ctre import FALCON_CPR, FALCON_FREE_RPS
from utilities.ctre import FALCON_FREE_RPS
from ids import CancoderIds, TalonIds


Expand All @@ -29,14 +35,7 @@
WHEEL_CIRCUMFERENCE = 4 * 2.54 / 100 * math.pi

DRIVE_MOTOR_REV_TO_METRES = WHEEL_CIRCUMFERENCE * DRIVE_GEAR_RATIO
METRES_TO_DRIVE_COUNTS = FALCON_CPR / DRIVE_MOTOR_REV_TO_METRES
DRIVE_COUNTS_TO_METRES = DRIVE_MOTOR_REV_TO_METRES / FALCON_CPR

STEER_MOTOR_REV_TO_RAD = math.tau * STEER_GEAR_RATIO
STEER_COUNTS_TO_RAD = STEER_MOTOR_REV_TO_RAD / FALCON_CPR
STEER_RAD_TO_COUNTS = FALCON_CPR / STEER_MOTOR_REV_TO_RAD

MAX_DRIVE_VOLTS = 11.5

# limit the acceleration of the commanded speeds of the robot to what is actually
# achiveable without the wheels slipping. This is done to improve odometry
Expand All @@ -50,7 +49,7 @@
steer_id: int,
encoder_id: int,
steer_reversed=True,
drive_reversed=False,
drive_reversed=True,
):
"""
x, y: where the module is relative to the center of the robot
Expand All @@ -60,68 +59,93 @@
self.state = SwerveModuleState(0, Rotation2d(0))
self.do_smooth = True

if drive_reversed:
drive_reversed = config_groups.InvertedValue.CLOCKWISE_POSITIVE
else:
drive_reversed = config_groups.InvertedValue.COUNTER_CLOCKWISE_POSITIVE

if steer_reversed:
steer_reversed = config_groups.InvertedValue.CLOCKWISE_POSITIVE
else:
steer_reversed = config_groups.InvertedValue.COUNTER_CLOCKWISE_POSITIVE

# Create Motor and encoder objects
self.steer = phoenix5.WPI_TalonFX(steer_id)
self.drive = phoenix5.WPI_TalonFX(drive_id)
self.steer = TalonFX(steer_id)
self.drive = TalonFX(drive_id)
self.drive_id = drive_id
self.encoder = phoenix5.sensors.CANCoder(encoder_id)
self.encoder = CANcoder(encoder_id)

# Reduce CAN status frame rates before configuring
self.steer.setStatusFramePeriod(
phoenix5.StatusFrameEnhanced.Status_1_General, 250, 10
self.steer.get_fault_field().set_update_frequency(
frequency_hz=4, timeout_seconds=0.01
)
self.drive.setStatusFramePeriod(
phoenix5.StatusFrameEnhanced.Status_1_General, 250, 10
self.drive.get_fault_field().set_update_frequency(
frequency_hz=4, timeout_seconds=0.01
)

# Configure steer motor
self.steer.setNeutralMode(phoenix5.NeutralMode.Brake)
self.steer.setInverted(steer_reversed)
self.steer.config_kP(0, 0.15035, 10)
self.steer.config_kI(0, 0, 10)
self.steer.config_kD(0, 5.6805, 10)
self.steer.configAllowableClosedloopError(
0, self.STEER_RAD_TO_COUNTS * math.radians(4)
)
self.steer.configSelectedFeedbackSensor(
phoenix5.FeedbackDevice.IntegratedSensor, 0, 10
steer_config = self.steer.configurator

steer_motor_config = MotorOutputConfigs()
steer_motor_config.neutral_mode = NeutralModeValue.BRAKE
steer_motor_config.inverted = steer_reversed

steer_gear_ratio_config = FeedbackConfigs().with_sensor_to_mechanism_ratio(
1 / self.STEER_GEAR_RATIO
)

# configuration for motor pid
steer_pid = Slot0Configs().with_k_p(0.3409939393939394).with_k_i(0).with_k_d(0)

steer_config.apply(steer_motor_config)
steer_config.apply(steer_pid, 0.01)
steer_config.apply(steer_gear_ratio_config)

# Configure drive motor
self.drive.setNeutralMode(phoenix5.NeutralMode.Brake)
self.drive.setInverted(drive_reversed)
self.drive.configVoltageCompSaturation(self.MAX_DRIVE_VOLTS, timeoutMs=10)
self.drive.enableVoltageCompensation(True)
self.drive_ff = SimpleMotorFeedforwardMeters(kS=0.18877, kV=2.7713, kA=0.18824)
self.drive.configVelocityMeasurementPeriod(
phoenix5.sensors.SensorVelocityMeasPeriod.Period_5Ms
drive_config = self.drive.configurator

drive_motor_config = MotorOutputConfigs()
drive_motor_config.neutral_mode = NeutralModeValue.BRAKE
drive_motor_config.inverted = drive_reversed

drive_gear_ratio_config = FeedbackConfigs().with_sensor_to_mechanism_ratio(
1 / self.DRIVE_GEAR_RATIO
)
self.drive.configVelocityMeasurementWindow(8)
self.drive.config_kP(0, 0.011489, 10)
self.drive.config_kI(0, 0, 10)
self.drive.config_kD(0, 0, 10)

# configuration for motor pid and feedforward
self.drive_pid = (
Slot0Configs().with_k_p(0.026450530596285438).with_k_i(0).with_k_d(0)
)
self.drive_ff = SimpleMotorFeedforwardMeters(kS=0.18877, kV=2.7713, kA=0.18824)

drive_config.apply(drive_motor_config)
drive_config.apply(self.drive_pid, 0.01)
drive_config.apply(drive_gear_ratio_config)

self.central_angle = math.atan2(x, y)
self.module_locked = False

def get_angle_absolute(self) -> float:
"""Gets steer angle (radians) from absolute encoder"""
return math.radians(self.encoder.getAbsolutePosition())
"""Gets steer angle (rot) from absolute encoder"""
return self.encoder.get_absolute_position().value

def get_angle_integrated(self) -> float:
"""Gets steer angle from motor's integrated relative encoder"""
return self.steer.getSelectedSensorPosition() * self.STEER_COUNTS_TO_RAD
return self.steer.get_position().value * math.tau

def get_rotation(self) -> Rotation2d:
"""Get the steer angle as a Rotation2d"""
return Rotation2d(self.get_angle_integrated())

def get_drive_current(self) -> float:
return self.drive.get_stator_current().value

def get_speed(self) -> float:
# velocity is in counts / 100ms, return in m/s
return self.drive.getSelectedSensorVelocity() * self.DRIVE_COUNTS_TO_METRES * 10
# velocity is in rot/s, return in m/s
return self.drive.get_velocity().value * self.WHEEL_CIRCUMFERENCE

def get_distance_traveled(self) -> float:
return self.drive.getSelectedSensorPosition() * self.DRIVE_COUNTS_TO_METRES
return self.drive.get_position().value * self.WHEEL_CIRCUMFERENCE

def set(self, desired_state: SwerveModuleState):
if self.module_locked:
Expand All @@ -134,34 +158,35 @@
self.state = desired_state
self.state = SwerveModuleState.optimize(self.state, self.get_rotation())

self.drive_request = VelocityVoltage(0)
self.steer_request = VoltageOut(0)
if abs(self.state.speed) < 0.01 and not self.module_locked:
self.drive.set(phoenix5.ControlMode.Velocity, 0)
self.steer.set(phoenix5.ControlMode.PercentOutput, 0)
self.drive.set_control(self.drive_request.with_velocity(0))
self.steer.set_control(self.steer_request)
return

current_angle = self.get_angle_integrated()
target_displacement = constrain_angle(
self.state.angle.radians() - current_angle
)
target_angle = target_displacement + current_angle
self.steer.set(
phoenix5.ControlMode.Position, target_angle * self.STEER_RAD_TO_COUNTS
)
self.steer_request = PositionDutyCycle(target_angle / math.tau)
self.steer.set_control(self.steer_request)

# rescale the speed target based on how close we are to being correctly aligned
target_speed = self.state.speed * math.cos(target_displacement) ** 2
speed_volt = self.drive_ff.calculate(target_speed)
self.drive.set(
phoenix5.ControlMode.Velocity,
target_speed * self.METRES_TO_DRIVE_COUNTS / 10,
phoenix5.DemandType.ArbitraryFeedForward,
speed_volt / self.MAX_DRIVE_VOLTS,

# original position change/100ms, new m/s -> rot/s
self.drive.set_control(
self.drive_request.with_velocity(
target_speed / self.WHEEL_CIRCUMFERENCE
).with_feed_forward(speed_volt)
)

#
def sync_steer_encoders(self) -> None:
self.steer.setSelectedSensorPosition(
self.get_angle_absolute() * self.STEER_RAD_TO_COUNTS
)
self.steer.set_position(self.get_angle_absolute())

def get_position(self) -> SwerveModulePosition:
return SwerveModulePosition(self.get_distance_traveled(), self.get_rotation())
Expand All @@ -172,9 +197,9 @@

class Chassis:
# metres between centre of left and right wheels
TRACK_WIDTH = 0.54665
TRACK_WIDTH = 0.61
# metres between centre of front and back wheels
WHEEL_BASE = 0.68665
WHEEL_BASE = 0.61

# size including bumpers
LENGTH = 1.0105
Expand Down Expand Up @@ -396,7 +421,7 @@

@feedback
def get_drive_current(self) -> float:
return sum(abs(x.drive.getStatorCurrent()) for x in self.modules)
return sum(abs(x.get_drive_current()) for x in self.modules)

@feedback
def may_be_stalled(self) -> bool:
Expand Down
28 changes: 20 additions & 8 deletions physics.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,36 @@

import math
import typing
import phoenix6

Check failure on line 5 in physics.py

View workflow job for this annotation

GitHub Actions / mypy

Skipping analyzing "phoenix6": module is installed, but missing library stubs or py.typed marker
import phoenix6.unmanaged

Check failure on line 6 in physics.py

View workflow job for this annotation

GitHub Actions / mypy

Skipping analyzing "phoenix6.unmanaged": module is installed, but missing library stubs or py.typed marker
import phoenix5
import wpilib

from pyfrc.physics.core import PhysicsInterface
from wpimath.kinematics import SwerveDrive4Kinematics
from wpilib.simulation import SimDeviceSim

from components.chassis import SwerveModule
from utilities.ctre import FALCON_CPR, VERSA_ENCODER_CPR
from utilities.ctre import VERSA_ENCODER_CPR

if typing.TYPE_CHECKING:
from robot import MyRobot


class SimpleTalonFXMotorSim:
def __init__(self, motor: phoenix5.TalonFX, kV: float, rev_per_unit: float) -> None:
self.sim_collection = motor.getSimCollection()
def __init__(
self, motor: phoenix6.hardware.TalonFX, kV: float, rev_per_unit: float
) -> None:
self.sim_state = motor.sim_state
self.kV = kV # volt seconds per unit
self.rev_per_unit = rev_per_unit

def update(self, dt: float) -> None:
voltage = self.sim_collection.getMotorOutputLeadVoltage()
voltage = self.sim_state.motor_voltage
velocity = voltage / self.kV # units per second
velocity_cps = velocity * self.rev_per_unit * FALCON_CPR
self.sim_collection.setIntegratedSensorVelocity(int(velocity_cps / 10))
self.sim_collection.addIntegratedSensorPosition(int(velocity_cps * dt))
velocity_cps = velocity * self.rev_per_unit * 10
self.sim_state.set_rotor_velocity(int(velocity_cps))
self.sim_state.add_rotor_position(int(velocity_cps * dt))


class SimpleTalonSRXMotorSim:
Expand Down Expand Up @@ -55,7 +60,9 @@
# Motors
self.wheels = [
SimpleTalonFXMotorSim(
module.drive, module.drive_ff.kV, 1 / module.DRIVE_MOTOR_REV_TO_METRES
module.drive,
module.drive_ff.kV,
1 / module.DRIVE_MOTOR_REV_TO_METRES,
)
for module in robot.chassis.modules
]
Expand All @@ -72,6 +79,11 @@
self.imu_yaw = self.imu.getDouble("Yaw")

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:
Expand Down
Loading