-
Notifications
You must be signed in to change notification settings - Fork 0
Deployable Intake Demo #93
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
base: main
Are you sure you want to change the base?
Conversation
| .with_k_s(0) | ||
| .with_k_v(0) | ||
| .with_k_a(0) | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is an arm, we'll also want a feedforward term to compensate for gravity.
I presume this has been CAD'ed by now? I'd recommend plugging it into https://www.reca.lc/arm to get some theoretical gains.
|
|
||
| @feedback | ||
| def get_absolute_deployment_encoder_position(self): | ||
| return self.deployment_encoder.get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure there won't be any offset?
Greptile Overview
|
| Filename | Overview |
|---|---|
| components/intake.py | Adds deployable intake (TalonFX + DutyCycleEncoder) and separate intake/funnel outputs; currently mixes degrees with TalonFX position units and seeds position from raw DutyCycleEncoder fraction. |
| ids.py | Adds CAN ID for intake deployer Talon and DIO channel for the deployment encoder; no functional issues spotted. |
| robot.py | Adds POV controls to deploy/retract intake in testPeriodic; uses truthiness of getPOV() leading to commands running when POV not pressed. |
Sequence Diagram
sequenceDiagram
participant Driver as Driver (XboxController)
participant Robot as MyRobot.testPeriodic
participant Intake as IntakeComponent
participant Deployer as TalonFX (deployment_motor)
participant Encoder as DutyCycleEncoder
Note over Intake: __init__ configures deployer
Intake->>Encoder: get()
Intake->>Deployer: set_position(abs_fraction)
Driver->>Robot: POV angle changes
alt POV == 0 (deploy)
Robot->>Intake: deploy_intake()
Intake-->>Intake: target_deployment_angle = DEPLOYED_INTAKE_ANGLE
else POV == 180 (retract)
Robot->>Intake: retract_intake()
Intake-->>Intake: target_deployment_angle = RETRACTED_INTAKE_ANGLE
end
Robot->>Intake: intake.execute()
Intake->>Deployer: set_position(target_deployment_angle)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 files reviewed, 3 comments
| RETRACTED_INTAKE_ANGLE = 0 | ||
| DEPLOYED_INTAKE_ANGLE = 90 | ||
|
|
||
| funnel_output = tunable(1.0) | ||
| target_deployment_angle = RETRACTED_INTAKE_ANGLE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deployment angle units mismatch
TalonFX.set_position() expects a position in mechanism rotations (after sensor_to_mechanism_ratio), but target_deployment_angle is being set to 0/90 degrees and passed directly at components/intake.py:85. Unless your mechanism is explicitly defined as “degrees as rotations” (it isn’t here), this will drive the deployer to 90 rotations instead of 90°.
| RETRACTED_INTAKE_ANGLE = 0 | |
| DEPLOYED_INTAKE_ANGLE = 90 | |
| funnel_output = tunable(1.0) | |
| target_deployment_angle = RETRACTED_INTAKE_ANGLE | |
| RETRACTED_INTAKE_ANGLE = 0.0 | |
| DEPLOYED_INTAKE_ANGLE = 0.25 # 90 deg = 0.25 rotations |
(Or rename to _ROTATIONS and convert from degrees before calling set_position().)
Prompt To Fix With AI
This is a comment left during a code review.
Path: components/intake.py
Line: 19:22
Comment:
**Deployment angle units mismatch**
`TalonFX.set_position()` expects a position in *mechanism rotations* (after `sensor_to_mechanism_ratio`), but `target_deployment_angle` is being set to `0`/`90` degrees and passed directly at `components/intake.py:85`. Unless your mechanism is explicitly defined as “degrees as rotations” (it isn’t here), this will drive the deployer to 90 rotations instead of 90°.
```suggestion
RETRACTED_INTAKE_ANGLE = 0.0
DEPLOYED_INTAKE_ANGLE = 0.25 # 90 deg = 0.25 rotations
```
(Or rename to `_ROTATIONS` and convert from degrees before calling `set_position()`.)
How can I resolve this? If you propose a fix, please make it concise.| @feedback | ||
| def get_absolute_deployment_encoder_position(self): | ||
| return self.deployment_encoder.get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DutyCycleEncoder range misuse
DutyCycleEncoder.get() returns the absolute position as a fraction of a rotation in [0.0, 1.0), not an angle/rotation value in the same units as your deployer mechanism. At components/intake.py:65-67 you seed the TalonFX integrated position with this raw fraction, which will usually mis-zero the mechanism (and it will jump at wraparound near 1.0→0.0).
You likely want to apply an offset and scale to mechanism rotations (and account for wrap) before calling set_position().
Prompt To Fix With AI
This is a comment left during a code review.
Path: components/intake.py
Line: 26:28
Comment:
**DutyCycleEncoder range misuse**
`DutyCycleEncoder.get()` returns the absolute position as a fraction of a rotation in `[0.0, 1.0)`, not an angle/rotation value in the same units as your deployer mechanism. At `components/intake.py:65-67` you seed the TalonFX integrated position with this raw fraction, which will usually mis-zero the mechanism (and it will jump at wraparound near 1.0→0.0).
You likely want to apply an offset and scale to mechanism rotations (and account for wrap) before calling `set_position()`.
How can I resolve this? If you propose a fix, please make it concise.| if self.gamepad.getPOV(0): | ||
| self.intake.deploy_intake() | ||
|
|
||
| if self.gamepad.getPOV(180): | ||
| self.intake.retract_intake() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
POV check always true
XboxController.getPOV() returns an angle in degrees (0/90/180/270) or -1 when not pressed. In Python, any non-zero int (including -1) is truthy, so if self.gamepad.getPOV(0): at robot.py:235 will run when the POV is not pressed, and if self.gamepad.getPOV(180): will also run for most angles.
Compare explicitly instead:
| if self.gamepad.getPOV(0): | |
| self.intake.deploy_intake() | |
| if self.gamepad.getPOV(180): | |
| self.intake.retract_intake() | |
| if self.gamepad.getPOV() == 0: | |
| self.intake.deploy_intake() | |
| if self.gamepad.getPOV() == 180: | |
| self.intake.retract_intake() |
Prompt To Fix With AI
This is a comment left during a code review.
Path: robot.py
Line: 235:239
Comment:
**POV check always true**
`XboxController.getPOV()` returns an angle in degrees (0/90/180/270) or `-1` when not pressed. In Python, any non-zero int (including `-1`) is truthy, so `if self.gamepad.getPOV(0):` at `robot.py:235` will run when the POV is *not pressed*, and `if self.gamepad.getPOV(180):` will also run for most angles.
Compare explicitly instead:
```suggestion
if self.gamepad.getPOV() == 0:
self.intake.deploy_intake()
if self.gamepad.getPOV() == 180:
self.intake.retract_intake()
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@greptileai you didn't explain why passing an angle as the argument to getPOV is wrong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right - I should have explained that.
getPOV() takes a POV index (which controller POV hat to read), not an angle to check against. For a standard Xbox controller, there's only one POV hat at index 0.
So getPOV(0) returns the angle of POV hat #0, while getPOV(180) is trying to read POV hat #180 (which doesn't exist - it will return -1).
The correct approach is:
| if self.gamepad.getPOV(0): | |
| self.intake.deploy_intake() | |
| if self.gamepad.getPOV(180): | |
| self.intake.retract_intake() | |
| pov = self.gamepad.getPOV(0) | |
| if pov == 0: | |
| self.intake.deploy_intake() | |
| if pov == 180: | |
| self.intake.retract_intake() |
9bd6e9c to
7f3b671
Compare
No description provided.