Skip to content

Commit cf9c5fb

Browse files
committed
Change default unit in Chrono.kt to MILLISECONDS, transfer between opmodes and ClearData opmode.
1 parent 65c0041 commit cf9c5fb

File tree

23 files changed

+255
-278
lines changed

23 files changed

+255
-278
lines changed

TeamCode/src/main/kotlin/pioneer/Bot.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ class Bot private constructor(
6161
}
6262

6363
fun updateAll(dt: Double) {
64-
hardwareComponents.values.forEach { it.update() }
65-
pinpoint?.update(dt)
66-
// TODO: Add other update methods (ie. localizer, follower)
64+
hardwareComponents.values.forEach { it.update(dt) }
6765
}
6866

6967
// Companion for builder and fromType

TeamCode/src/main/kotlin/pioneer/Constants.kt

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,22 +123,23 @@ object Constants {
123123
/** The maximum angular acceleration in rad per second squared. */
124124
const val MAX_ANGULAR_ACCELERATION = 10.0
125125

126+
// --- Standard Follower PID Tuned to Stay on the Path ---
126127
// X-axis PID coefficients for the trajectory follower
127-
@JvmField var X_KP = 7.5
128+
@JvmField var X_KP = 5.0 // was 7.0
128129
@JvmField var X_KI = 0.0
129130
@JvmField var X_KD = 0.0
130131

131132
// Y-axis PID coefficients for the trajectory follower
132-
@JvmField var Y_KP = 7.5
133+
@JvmField var Y_KP = 5.0 // was 7.0
133134
@JvmField var Y_KI = 0.0
134135
@JvmField var Y_KD = 0.0
135136

136137
// Theta PID coefficients for heading interpolation
137-
@JvmField var THETA_KP = 5.0
138+
@JvmField var THETA_KP = 3.0 // was 5.0
138139
@JvmField var THETA_KI = 0.0
139140
@JvmField var THETA_KD = 0.0
140141

141-
// Position PID coefficients for final pose correction
142+
// --- Position PID coefficients tuned for final pose correction ---
142143
@JvmField var POS_X_KP = 0.0
143144
@JvmField var POS_X_KI = 0.0
144145
@JvmField var POS_X_KD = 0.0
@@ -208,8 +209,24 @@ object Constants {
208209
}
209210

210211
object TransferData {
212+
fun reset() {
213+
allianceColor = AllianceColor.NEUTRAL
214+
pose = Pose()
215+
turretMotorTicks = 0
216+
spindexerMotorTicks = 0
217+
}
218+
211219
var allianceColor = AllianceColor.NEUTRAL
212-
var turretPositionTicks = 0
213-
var spindexerPositionTicks = 0
220+
var pose = Pose()
221+
var turretMotorTicks = 0
222+
var spindexerMotorTicks = 0
223+
}
224+
225+
@Config
226+
object Flywheel {
227+
@JvmField var KP = 0.0075
228+
@JvmField var KI = 0.0
229+
@JvmField var KD = 0.0
230+
@JvmField var KF = 0.000415
214231
}
215232
}

TeamCode/src/main/kotlin/pioneer/decode/GoalTag.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ enum class GoalTag(
4545
val height: Double
4646
get() = position[2].toDouble()
4747

48-
val shootingHeight = height + 30.0
48+
val shootingHeight = height + 50.0
4949

5050
val shootingPose: Pose
5151
get() =
5252
when (this) {
53-
BLUE -> this.pose + Pose(x = -32.0, y = 30.0) // -X +Y
54-
RED -> this.pose + Pose(x = 32.0, y = 30.0) // +X +Y
53+
BLUE -> this.pose + Pose(x = -37.5, y = 32.5) // -X +Y
54+
RED -> this.pose + Pose(x = 37.5, y = 32.5) // +X +Y
5555
}
5656
}
5757

TeamCode/src/main/kotlin/pioneer/hardware/Flywheel.kt

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@ import com.qualcomm.robotcore.hardware.DcMotor
44
import com.qualcomm.robotcore.hardware.DcMotorEx
55
import com.qualcomm.robotcore.hardware.DcMotorSimple
66
import com.qualcomm.robotcore.hardware.HardwareMap
7-
import com.qualcomm.robotcore.hardware.PIDFCoefficients
87
import org.firstinspires.ftc.robotcore.external.navigation.CurrentUnit
98
import pioneer.Constants
10-
import pioneer.decode.GoalTag
11-
import pioneer.helpers.FileLogger
9+
import pioneer.helpers.PIDController
1210
import pioneer.helpers.Pose
1311
import kotlin.math.cos
14-
import kotlin.math.pow
1512
import kotlin.math.sin
1613
import kotlin.math.sqrt
1714
import kotlin.math.tan
@@ -21,14 +18,21 @@ class Flywheel(
2118
private val motorName: String = Constants.HardwareNames.FLYWHEEL,
2219
) : HardwareComponent {
2320
private lateinit var flywheel: DcMotorEx
21+
private val motorPID = PIDController(
22+
Constants.Flywheel.KP,
23+
Constants.Flywheel.KI,
24+
Constants.Flywheel.KD,
25+
)
2426

2527
val motor: DcMotorEx
2628
get() = flywheel
2729

30+
var targetVelocity = 0.0
31+
2832
var velocity
2933
get() = flywheel.velocity
3034
set(value) {
31-
flywheel.velocity = value
35+
targetVelocity = value
3236
}
3337

3438
val current
@@ -42,16 +46,16 @@ class Flywheel(
4246
zeroPowerBehavior = DcMotor.ZeroPowerBehavior.FLOAT
4347
direction = DcMotorSimple.Direction.FORWARD
4448
}
45-
FileLogger.info(name, flywheel.getPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER).toString())
46-
flywheel.setPIDFCoefficients(
47-
DcMotor.RunMode.RUN_USING_ENCODER,
48-
PIDFCoefficients(
49-
50.0,
50-
3.0,
51-
0.0,
52-
0.0,
53-
),
54-
)
49+
}
50+
51+
override fun update(dt: Double) {
52+
if (targetVelocity == 0.0) {
53+
flywheel.power = 0.0
54+
return
55+
}
56+
val correction = motorPID.update(targetVelocity - velocity, dt)
57+
flywheel.power = Constants.Flywheel.KF * targetVelocity + correction
58+
// FileLogger.debug("Flywheel","Set Power: ${Constants.Flywheel.KF * targetVelocity + correction}")
5559
}
5660

5761
// https://www.desmos.com/calculator/uofqeqqyn1

TeamCode/src/main/kotlin/pioneer/hardware/HardwareComponent.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ interface HardwareComponent {
66

77
fun init()
88

9-
fun update() { }
9+
fun update(dt: Double) {}
1010
}

TeamCode/src/main/kotlin/pioneer/hardware/LaunchServos.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class LaunchServos(
3636
timer.reset()
3737
}
3838

39-
override fun update() {
39+
override fun update(dt: Double) {
4040
if (timer.milliseconds() < 250) {
4141
if (launch) {
4242
setPower(1.0)

TeamCode/src/main/kotlin/pioneer/hardware/Spindexer.kt

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ import com.qualcomm.robotcore.hardware.HardwareMap
66
import com.qualcomm.robotcore.util.ElapsedTime
77
import pioneer.Constants
88
import pioneer.decode.Artifact
9-
import pioneer.helpers.Chrono
9+
import pioneer.helpers.FileLogger
1010
import pioneer.helpers.PIDController
1111
import kotlin.math.PI
1212
import kotlin.math.abs
1313
import kotlin.math.sign
14-
import kotlin.time.DurationUnit
1514

1615
/*
1716
Positive ROT: CW due to under-mounted motor
@@ -79,7 +78,7 @@ class Spindexer(
7978

8079
for (position in MotorPosition.entries) {
8180
val targetTicks = (position.radians * ticksPerRadian).toInt()
82-
val error = wrapTicks(targetTicks - currentMotorPosition).toDouble()
81+
val error = wrapTicks(targetTicks - currentMotorTicks).toDouble()
8382
if (abs(error) < abs(smallestError)) {
8483
smallestError = error
8584
closestPosition = position
@@ -94,7 +93,7 @@ class Spindexer(
9493
// Check if motor position matches any outtake position
9594
for (position in outtakePositions) {
9695
val targetTicks = (position.radians * ticksPerRadian).toInt()
97-
val error = wrapTicks(targetTicks - currentMotorPosition)
96+
val error = wrapTicks(targetTicks - currentMotorTicks)
9897
if (abs(error) < 300.0) {
9998
return true
10099
}
@@ -115,7 +114,7 @@ class Spindexer(
115114
val reachedTarget: Boolean
116115
get() {
117116
// Compute circular error
118-
val error = wrapTicks(targetMotorPosition - currentMotorPosition)
117+
val error = wrapTicks(targetMotorTicks - currentMotorTicks)
119118
return abs(error) < Constants.Spindexer.POSITION_TOLERANCE_TICKS && (motor.velocity < Constants.Spindexer.VELOCITY_TOLERANCE_TPS)
120119
}
121120

@@ -130,21 +129,28 @@ class Spindexer(
130129
get() = _artifacts.count { it != null }
131130

132131
// Motor position accessors
133-
val currentMotorPosition: Int
134-
get() = motor.currentPosition - offsetTicks
132+
private val rawMotorTicks: Int
133+
get() {
134+
check(::motor.isInitialized)
135+
return motor.currentPosition
136+
}
137+
138+
val currentMotorTicks: Int
139+
get() = rawMotorTicks + offsetTicks
135140

136-
val targetMotorPosition: Int
141+
val targetMotorTicks: Int
137142
get() = (motorState.radians * ticksPerRadian).toInt()
138143

139144
val currentScannedArtifact: Artifact?
140145
get() = scanArtifact()
141146

142147
var checkingForNewArtifacts = true
143148

149+
var manualMove = false
150+
144151
// Private variables
145152
private var offsetTicks = 0
146153
private var lastPower = 0.0
147-
private val chrono = Chrono(autoUpdate = false, units = DurationUnit.MILLISECONDS)
148154
private val ticksPerRadian: Int = (Constants.Spindexer.TICKS_PER_REV / (2 * PI)).toInt()
149155
private val motorPID =
150156
PIDController(
@@ -157,7 +163,6 @@ class Spindexer(
157163
private var artifactSeen = false
158164
private var artifactWasSeenRecently = false
159165
private var lastStoredIndex = 0
160-
private var manualMove = false
161166
private val intakePositions =
162167
listOf(MotorPosition.INTAKE_1, MotorPosition.INTAKE_2, MotorPosition.INTAKE_3)
163168
private val outtakePositions =
@@ -199,9 +204,8 @@ class Spindexer(
199204
* Updates the motor position to match the desired motor state.
200205
* Checks for new artifacts if in an intake position.
201206
*/
202-
override fun update() {
203-
chrono.update()
204-
runMotorToState()
207+
override fun update(dt: Double) {
208+
runMotorToState(dt)
205209
if (checkingForNewArtifacts) checkForArtifact()
206210
}
207211

@@ -261,6 +265,7 @@ class Spindexer(
261265
_artifacts[index] = null
262266
// Automatically move to intake if empty
263267
if (isEmpty) moveToNextOpenIntake()
268+
FileLogger.info("Spindexer", "Removed $artifact")
264269
return artifact
265270
}
266271

@@ -314,17 +319,17 @@ class Spindexer(
314319
return lastPower
315320
}
316321

317-
private fun runMotorToState() {
322+
private fun runMotorToState(dt: Double) {
318323
if (manualMove) return
319324

320-
val rawError = targetMotorPosition - currentMotorPosition
325+
val rawError = targetMotorTicks - currentMotorTicks
321326
val error = wrapTicks(rawError)
322327

323328
// PID
324-
var power = motorPID.update(error.toDouble(), chrono.dt)
329+
var power = motorPID.update(error.toDouble(), dt)
325330

326331
// Ramp power to prevent sudden acceleration
327-
power = rampPower(power, chrono.dt)
332+
power = rampPower(power, dt)
328333

329334
// Static constant
330335
val adjustedKS = Constants.Spindexer.KS_START + Constants.Spindexer.KS_STEP * numStoredArtifacts
@@ -418,6 +423,9 @@ class Spindexer(
418423
if (artifactVisibleTimer.milliseconds() >= Constants.Spindexer.CONFIRM_INTAKE_MS) {
419424
storeArtifact(artifact)
420425

426+
// Log stored artifact
427+
FileLogger.info("Spindexer", "Stored $artifact")
428+
421429
// Reset state
422430
artifactSeen = false
423431
artifactWasSeenRecently = false

TeamCode/src/main/kotlin/pioneer/hardware/Turret.kt

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@ class Turret(
3434
val currentTicks: Int
3535
get() {
3636
check(::turret.isInitialized)
37-
return turret.currentPosition - offsetTicks
37+
return turret.currentPosition + offsetTicks
38+
}
39+
40+
val rawTicks: Int
41+
get() {
42+
check(::turret.isInitialized)
43+
return turret.currentPosition
3844
}
3945

4046
val reachedTarget: Boolean
@@ -61,11 +67,12 @@ class Turret(
6167
get() = currentTicks / ticksPerRadian
6268

6369
val targetAngle: Double
64-
get() = turret.targetPosition / ticksPerRadian
70+
get() = (turret.targetPosition + offsetTicks) / ticksPerRadian
6571

6672
fun resetMotorPosition(resetTicks: Int = 0) {
6773
turret.mode = DcMotor.RunMode.STOP_AND_RESET_ENCODER
6874
offsetTicks = resetTicks
75+
turret.mode = DcMotor.RunMode.RUN_USING_ENCODER
6976
}
7077

7178
fun gotoAngle(
@@ -84,13 +91,14 @@ class Turret(
8491
desiredAngle = MathUtils.normalizeRadians(angle, motorRange)
8592
}
8693

87-
val currentAngle = currentTicks / ticksPerRadian
88-
89-
val delta = desiredAngle - currentAngle
90-
val targetTicks = (currentTicks + delta * ticksPerRadian).toInt()
94+
// Logical ticks uses offset
95+
val logicalCurrentTicks = currentTicks
96+
val logicalTargetTicks =
97+
(desiredAngle * ticksPerRadian).toInt()
98+
val rawTargetTicks = logicalTargetTicks - offsetTicks
9199

92100
with(turret) {
93-
targetPosition = targetTicks
101+
targetPosition = rawTargetTicks
94102
mode = DcMotor.RunMode.RUN_TO_POSITION
95103
this.power = power
96104
}
@@ -102,7 +110,7 @@ class Turret(
102110
) {
103111
val shootPose = pose + Pose(x = Constants.Turret.OFFSET * sin(-pose.theta), y = Constants.Turret.OFFSET * cos(-pose.theta)) +
104112
Pose(pose.vx * Constants.Turret.LAUNCH_TIME, pose.vy * Constants.Turret.LAUNCH_TIME)
105-
// General Angle(From robot 0 to target):
113+
// General Angle (From robot 0 to target):
106114
val targetTheta = (shootPose angleTo target)
107115
val turretTheta = (PI / 2 + targetTheta) - shootPose.theta
108116
gotoAngle(MathUtils.normalizeRadians(turretTheta), 0.85)

TeamCode/src/main/kotlin/pioneer/helpers/Chrono.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import kotlin.time.TimeSource
1414
class Chrono(
1515
private val autoUpdate: Boolean = true,
1616
private val source: TimeSource = TimeSource.Monotonic,
17-
private val units: DurationUnit = DurationUnit.SECONDS,
17+
private val units: DurationUnit = DurationUnit.MILLISECONDS,
1818
) {
1919
private var last = source.markNow()
2020

TeamCode/src/main/kotlin/pioneer/localization/Localizer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface Localizer : HardwareComponent {
1717
* Updates the pose of the robot based on sensor data
1818
* @param dt The time since the last update in seconds
1919
*/
20-
fun update(dt: Double)
20+
override fun update(dt: Double)
2121

2222
/**
2323
* Resets the localizer to a specific pose

0 commit comments

Comments
 (0)