Compare commits
15 Commits
a8833aaf5b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 013050ee19 | |||
| 07656eedc1 | |||
| eb02a28048 | |||
| 3ea469ae1c | |||
| 2b464d2f32 | |||
|
|
429fa04f99 | ||
| 80c2a4dd95 | |||
| d9c16bb05c | |||
| db4bab6e16 | |||
| cb1c7ba0e3 | |||
| b8c376499b | |||
| 7e02ec1ccc | |||
|
|
235f43fd2e | ||
| d29acde2df | |||
| 048c7158ee |
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -57,5 +57,6 @@
|
|||||||
"edu.wpi.first.math.**.proto.*",
|
"edu.wpi.first.math.**.proto.*",
|
||||||
"edu.wpi.first.math.**.struct.*",
|
"edu.wpi.first.math.**.struct.*",
|
||||||
],
|
],
|
||||||
"java.dependency.enableDependencyCheckup": false
|
"java.dependency.enableDependencyCheckup": false,
|
||||||
|
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,35 +11,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "named",
|
"type": "parallel",
|
||||||
"data": {
|
"data": {
|
||||||
"name": "spinup"
|
"commands": [
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "path",
|
"type": "path",
|
||||||
"data": {
|
"data": {
|
||||||
"pathName": "start to score left"
|
"pathName": "Start to Outpost"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "named",
|
"type": "wait",
|
||||||
"data": {
|
"data": {
|
||||||
"name": "shoot close"
|
"waitTime": 2.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "path",
|
"type": "parallel",
|
||||||
"data": {
|
"data": {
|
||||||
"pathName": "Left to Outpost"
|
"commands": [
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "named",
|
|
||||||
"data": {
|
|
||||||
"name": "stop spindexer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "path",
|
"type": "path",
|
||||||
"data": {
|
"data": {
|
||||||
@@ -51,11 +44,26 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"name": "spinup"
|
"name": "spinup"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "named",
|
"type": "named",
|
||||||
"data": {
|
"data": {
|
||||||
"name": "shoot N jimmy"
|
"name": "spinup"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "aim"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "auto shoot"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"version": "2025.0",
|
||||||
|
"command": {
|
||||||
|
"type": "sequential",
|
||||||
|
"data": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"type": "parallel",
|
||||||
|
"data": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"data": {
|
||||||
|
"pathName": "left start to center"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "intake down"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "parallel",
|
||||||
|
"data": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"data": {
|
||||||
|
"pathName": "over bump to pile move"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "spinup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "parallel",
|
||||||
|
"data": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"data": {
|
||||||
|
"pathName": "back from center"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "spinup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "aim"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "auto shoot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resetOdom": true,
|
||||||
|
"folder": null,
|
||||||
|
"choreoAuto": false
|
||||||
|
}
|
||||||
@@ -5,16 +5,73 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"type": "named",
|
"type": "parallel",
|
||||||
"data": {
|
"data": {
|
||||||
"name": "intake down"
|
"commands": [
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "path",
|
"type": "path",
|
||||||
"data": {
|
"data": {
|
||||||
"pathName": "left start to center"
|
"pathName": "left start to center"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "intake down"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "parallel",
|
||||||
|
"data": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"data": {
|
||||||
|
"pathName": "over bump to pile"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "spinup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "parallel",
|
||||||
|
"data": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"type": "path",
|
||||||
|
"data": {
|
||||||
|
"pathName": "back from center"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "spinup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "aim"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "named",
|
||||||
|
"data": {
|
||||||
|
"name": "auto shoot"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,25 +3,25 @@
|
|||||||
"waypoints": [
|
"waypoints": [
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 3.2515736040609142,
|
"x": 1.925604060913706,
|
||||||
"y": 4.914375634517767
|
"y": 5.503695431472081
|
||||||
},
|
},
|
||||||
"prevControl": null,
|
"prevControl": null,
|
||||||
"nextControl": {
|
"nextControl": {
|
||||||
"x": 2.4338749089244973,
|
"x": 1.107905365777289,
|
||||||
"y": 5.333984175443034
|
"y": 5.923303972397348
|
||||||
},
|
},
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
"linkedName": "left close"
|
"linkedName": "left close"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 0.77458883248731,
|
"x": 0.32339086294416286,
|
||||||
"y": 5.927269035532995
|
"y": 5.9825177664974625
|
||||||
},
|
},
|
||||||
"prevControl": {
|
"prevControl": {
|
||||||
"x": 2.3777086426889733,
|
"x": 1.9265106731458264,
|
||||||
"y": 6.110175322602984
|
"y": 6.165424053567452
|
||||||
},
|
},
|
||||||
"nextControl": null,
|
"nextControl": null,
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
},
|
},
|
||||||
"prevControl": {
|
"prevControl": {
|
||||||
"x": 8.08578683847011,
|
"x": 8.08578683847011,
|
||||||
"y": 0.4907704016028374
|
"y": 0.49077040160283736
|
||||||
},
|
},
|
||||||
"nextControl": {
|
"nextControl": {
|
||||||
"x": 8.318287488908608,
|
"x": 8.318287488908608,
|
||||||
|
|||||||
@@ -3,35 +3,35 @@
|
|||||||
"waypoints": [
|
"waypoints": [
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 3.6619856887266913,
|
"x": 3.5922741116751276,
|
||||||
"y": 2.2583184257605784
|
"y": 6.3692588832487305
|
||||||
},
|
},
|
||||||
"prevControl": null,
|
"prevControl": null,
|
||||||
"nextControl": {
|
"nextControl": {
|
||||||
"x": 2.4937567084046877,
|
"x": 2.956913705583757,
|
||||||
"y": 1.3172450805011864
|
"y": 6.19430456852792
|
||||||
},
|
},
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
"linkedName": null
|
"linkedName": "start left"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 0.7089624329216013,
|
"x": 0.32339086294416286,
|
||||||
"y": 0.668228980317108
|
"y": 5.9825177664974625
|
||||||
},
|
},
|
||||||
"prevControl": {
|
"prevControl": {
|
||||||
"x": 1.6987119856944104,
|
"x": 1.3270761421319812,
|
||||||
"y": 1.0414132379199703
|
"y": 5.964101522842641
|
||||||
},
|
},
|
||||||
"nextControl": null,
|
"nextControl": null,
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
"linkedName": "Outpost"
|
"linkedName": "trough"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rotationTargets": [
|
"rotationTargets": [
|
||||||
{
|
{
|
||||||
"waypointRelativePos": 0.7234468937875753,
|
"waypointRelativePos": 0.6910862504511138,
|
||||||
"rotationDegrees": 180.0
|
"rotationDegrees": -179.02889973265033
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"constraintZones": [],
|
"constraintZones": [],
|
||||||
@@ -39,14 +39,14 @@
|
|||||||
"eventMarkers": [
|
"eventMarkers": [
|
||||||
{
|
{
|
||||||
"name": "Intake Start",
|
"name": "Intake Start",
|
||||||
"waypointRelativePos": 0.4500000000000002,
|
"waypointRelativePos": 0,
|
||||||
"endWaypointRelativePos": null,
|
"endWaypointRelativePos": null,
|
||||||
"command": null
|
"command": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalConstraints": {
|
"globalConstraints": {
|
||||||
"maxVelocity": 2.0,
|
"maxVelocity": 0.75,
|
||||||
"maxAcceleration": 1.5,
|
"maxAcceleration": 2.5,
|
||||||
"maxAngularVelocity": 540.0,
|
"maxAngularVelocity": 540.0,
|
||||||
"maxAngularAcceleration": 720.0,
|
"maxAngularAcceleration": 720.0,
|
||||||
"nominalVoltage": 12.0,
|
"nominalVoltage": 12.0,
|
||||||
@@ -54,13 +54,13 @@
|
|||||||
},
|
},
|
||||||
"goalEndState": {
|
"goalEndState": {
|
||||||
"velocity": 0,
|
"velocity": 0,
|
||||||
"rotation": 180.0
|
"rotation": 178.80651057601818
|
||||||
},
|
},
|
||||||
"reversed": false,
|
"reversed": false,
|
||||||
"folder": "Right Outpost",
|
"folder": null,
|
||||||
"idealStartingState": {
|
"idealStartingState": {
|
||||||
"velocity": 0,
|
"velocity": 0,
|
||||||
"rotation": 180.0
|
"rotation": -90.0
|
||||||
},
|
},
|
||||||
"useDefaultConstraints": true
|
"useDefaultConstraints": false
|
||||||
}
|
}
|
||||||
59
src/main/deploy/pathplanner/paths/back from center.path
Normal file
59
src/main/deploy/pathplanner/paths/back from center.path
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"version": "2025.0",
|
||||||
|
"waypoints": [
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 6.742194543297748,
|
||||||
|
"y": 5.589703440094898
|
||||||
|
},
|
||||||
|
"prevControl": null,
|
||||||
|
"nextControl": {
|
||||||
|
"x": 3.68848717948718,
|
||||||
|
"y": 5.639692307692307
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": "after center grab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 2.979166666666668,
|
||||||
|
"y": 5.2327051282051285
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 3.0721923076923088,
|
||||||
|
"y": 5.721089743589744
|
||||||
|
},
|
||||||
|
"nextControl": null,
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rotationTargets": [
|
||||||
|
{
|
||||||
|
"waypointRelativePos": 0.11569148936170148,
|
||||||
|
"rotationDegrees": -34.71279786419313
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"constraintZones": [],
|
||||||
|
"pointTowardsZones": [],
|
||||||
|
"eventMarkers": [],
|
||||||
|
"globalConstraints": {
|
||||||
|
"maxVelocity": 4.0,
|
||||||
|
"maxAcceleration": 3.0,
|
||||||
|
"maxAngularVelocity": 540.0,
|
||||||
|
"maxAngularAcceleration": 720.0,
|
||||||
|
"nominalVoltage": 12.0,
|
||||||
|
"unlimited": false
|
||||||
|
},
|
||||||
|
"goalEndState": {
|
||||||
|
"velocity": 0,
|
||||||
|
"rotation": -36.158185439808385
|
||||||
|
},
|
||||||
|
"reversed": false,
|
||||||
|
"folder": null,
|
||||||
|
"idealStartingState": {
|
||||||
|
"velocity": 4.0,
|
||||||
|
"rotation": -45.365518355574764
|
||||||
|
},
|
||||||
|
"useDefaultConstraints": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"version": "2025.0",
|
||||||
|
"waypoints": [
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 3.5922741116751276,
|
||||||
|
"y": 6.3692588832487305
|
||||||
|
},
|
||||||
|
"prevControl": null,
|
||||||
|
"nextControl": {
|
||||||
|
"x": 3.9329746192893413,
|
||||||
|
"y": 6.3692588832487305
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": "start left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 4.577543147208122,
|
||||||
|
"y": 5.715482233502538
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 4.264467005076142,
|
||||||
|
"y": 5.715482233502538
|
||||||
|
},
|
||||||
|
"nextControl": {
|
||||||
|
"x": 5.120900364352579,
|
||||||
|
"y": 5.715482233502538
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 6.041634517766498,
|
||||||
|
"y": 6.3692588832487305
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 5.931137055837564,
|
||||||
|
"y": 5.65102538071066
|
||||||
|
},
|
||||||
|
"nextControl": null,
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": "over bump"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rotationTargets": [
|
||||||
|
{
|
||||||
|
"waypointRelativePos": 0.8,
|
||||||
|
"rotationDegrees": -135.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"constraintZones": [],
|
||||||
|
"pointTowardsZones": [],
|
||||||
|
"eventMarkers": [],
|
||||||
|
"globalConstraints": {
|
||||||
|
"maxVelocity": 4.0,
|
||||||
|
"maxAcceleration": 2.5,
|
||||||
|
"maxAngularVelocity": 540.0,
|
||||||
|
"maxAngularAcceleration": 720.0,
|
||||||
|
"nominalVoltage": 12.0,
|
||||||
|
"unlimited": false
|
||||||
|
},
|
||||||
|
"goalEndState": {
|
||||||
|
"velocity": 2.0,
|
||||||
|
"rotation": -129.95754893082906
|
||||||
|
},
|
||||||
|
"reversed": false,
|
||||||
|
"folder": null,
|
||||||
|
"idealStartingState": {
|
||||||
|
"velocity": 0,
|
||||||
|
"rotation": -90.0
|
||||||
|
},
|
||||||
|
"useDefaultConstraints": false
|
||||||
|
}
|
||||||
@@ -3,124 +3,67 @@
|
|||||||
"waypoints": [
|
"waypoints": [
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 3.573857868020305,
|
"x": 3.5922741116751276,
|
||||||
"y": 6.3692588832487305
|
"y": 6.3692588832487305
|
||||||
},
|
},
|
||||||
"prevControl": null,
|
"prevControl": null,
|
||||||
"nextControl": {
|
"nextControl": {
|
||||||
"x": 3.1594923857868027,
|
"x": 3.085827411167513,
|
||||||
"y": 6.424507614213196
|
"y": 6.277177664974619
|
||||||
},
|
},
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
"linkedName": "start left"
|
"linkedName": "start left"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 2.634629441624366,
|
"x": 4.577543147208122,
|
||||||
"y": 5.558944162436549
|
"y": 5.715482233502538
|
||||||
},
|
},
|
||||||
"prevControl": {
|
"prevControl": {
|
||||||
"x": 2.4136345177664977,
|
"x": 3.2884060913705584,
|
||||||
"y": 5.908852791878173
|
"y": 5.697065989847716
|
||||||
},
|
},
|
||||||
"nextControl": {
|
"nextControl": {
|
||||||
"x": 2.895419769065523,
|
"x": 5.120844928223563,
|
||||||
"y": 5.146026143988051
|
"y": 5.723243687517044
|
||||||
},
|
},
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
"linkedName": null
|
"linkedName": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 4.522294416243654,
|
"x": 6.041634517766498,
|
||||||
"y": 5.558944162436549
|
"y": 6.3692588832487305
|
||||||
},
|
},
|
||||||
"prevControl": {
|
"prevControl": {
|
||||||
"x": 3.5095162657293457,
|
"x": 5.931137055837564,
|
||||||
"y": 5.533304209258972
|
"y": 5.65102538071066
|
||||||
},
|
|
||||||
"nextControl": {
|
|
||||||
"x": 6.704619289340102,
|
|
||||||
"y": 5.614192893401015
|
|
||||||
},
|
|
||||||
"isLocked": false,
|
|
||||||
"linkedName": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anchor": {
|
|
||||||
"x": 7.478101522849547,
|
|
||||||
"y": 7.244030456855094
|
|
||||||
},
|
|
||||||
"prevControl": {
|
|
||||||
"x": 6.765542310662505,
|
|
||||||
"y": 7.465169522706244
|
|
||||||
},
|
|
||||||
"nextControl": {
|
|
||||||
"x": 8.012172588839395,
|
|
||||||
"y": 7.078284263961693
|
|
||||||
},
|
|
||||||
"isLocked": false,
|
|
||||||
"linkedName": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anchor": {
|
|
||||||
"x": 7.671472081218274,
|
|
||||||
"y": 4.7670456852791885
|
|
||||||
},
|
|
||||||
"prevControl": {
|
|
||||||
"x": 7.726720812182741,
|
|
||||||
"y": 7.639979695431472
|
|
||||||
},
|
},
|
||||||
"nextControl": null,
|
"nextControl": null,
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
"linkedName": null
|
"linkedName": "over bump"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rotationTargets": [
|
"rotationTargets": [
|
||||||
{
|
{
|
||||||
"waypointRelativePos": 1.5636363636363326,
|
"waypointRelativePos": 0.8,
|
||||||
"rotationDegrees": -45.0
|
"rotationDegrees": -135.0
|
||||||
},
|
|
||||||
{
|
|
||||||
"waypointRelativePos": 3.0318181818182266,
|
|
||||||
"rotationDegrees": -90.0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"constraintZones": [
|
|
||||||
{
|
|
||||||
"name": "Constraints Zone",
|
|
||||||
"minWaypointRelativePos": 2.6208291203235685,
|
|
||||||
"maxWaypointRelativePos": 4.0,
|
|
||||||
"constraints": {
|
|
||||||
"maxVelocity": 1.0,
|
|
||||||
"maxAcceleration": 1.5,
|
|
||||||
"maxAngularVelocity": 540.0,
|
|
||||||
"maxAngularAcceleration": 720.0,
|
|
||||||
"nominalVoltage": 12.0,
|
|
||||||
"unlimited": false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"constraintZones": [],
|
||||||
"pointTowardsZones": [],
|
"pointTowardsZones": [],
|
||||||
"eventMarkers": [
|
"eventMarkers": [],
|
||||||
{
|
|
||||||
"name": "Intake Start",
|
|
||||||
"waypointRelativePos": 0,
|
|
||||||
"endWaypointRelativePos": null,
|
|
||||||
"command": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"globalConstraints": {
|
"globalConstraints": {
|
||||||
"maxVelocity": 2.0,
|
"maxVelocity": 4.0,
|
||||||
"maxAcceleration": 1.5,
|
"maxAcceleration": 3.0,
|
||||||
"maxAngularVelocity": 540.0,
|
"maxAngularVelocity": 540.0,
|
||||||
"maxAngularAcceleration": 720.0,
|
"maxAngularAcceleration": 720.0,
|
||||||
"nominalVoltage": 12.0,
|
"nominalVoltage": 12.0,
|
||||||
"unlimited": false
|
"unlimited": false
|
||||||
},
|
},
|
||||||
"goalEndState": {
|
"goalEndState": {
|
||||||
"velocity": 0,
|
"velocity": 2.0,
|
||||||
"rotation": -89.09061955080092
|
"rotation": -129.95754893082906
|
||||||
},
|
},
|
||||||
"reversed": false,
|
"reversed": false,
|
||||||
"folder": null,
|
"folder": null,
|
||||||
@@ -128,5 +71,5 @@
|
|||||||
"velocity": 0,
|
"velocity": 0,
|
||||||
"rotation": -90.0
|
"rotation": -90.0
|
||||||
},
|
},
|
||||||
"useDefaultConstraints": true
|
"useDefaultConstraints": false
|
||||||
}
|
}
|
||||||
116
src/main/deploy/pathplanner/paths/over bump to pile move.path
Normal file
116
src/main/deploy/pathplanner/paths/over bump to pile move.path
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"version": "2025.0",
|
||||||
|
"waypoints": [
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 6.041634517766498,
|
||||||
|
"y": 6.3692588832487305
|
||||||
|
},
|
||||||
|
"prevControl": null,
|
||||||
|
"nextControl": {
|
||||||
|
"x": 6.511248730964468,
|
||||||
|
"y": 7.059868020304569
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": "over bump"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 7.2386903553299495,
|
||||||
|
"y": 7.326903553299493
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 6.2386903553299495,
|
||||||
|
"y": 7.326903553299493
|
||||||
|
},
|
||||||
|
"nextControl": {
|
||||||
|
"x": 8.238690355329947,
|
||||||
|
"y": 7.326903553299493
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 8.417329949238578,
|
||||||
|
"y": 4.831502538071066
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 8.475340101522843,
|
||||||
|
"y": 6.042370558375635
|
||||||
|
},
|
||||||
|
"nextControl": {
|
||||||
|
"x": 8.359319796954313,
|
||||||
|
"y": 3.620634517766498
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 6.742194543297748,
|
||||||
|
"y": 5.589703440094898
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 7.758358974358975,
|
||||||
|
"y": 5.616435897435898
|
||||||
|
},
|
||||||
|
"nextControl": null,
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": "after center grab"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rotationTargets": [
|
||||||
|
{
|
||||||
|
"waypointRelativePos": 1.0045454545454569,
|
||||||
|
"rotationDegrees": -115.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"waypointRelativePos": 2.348863636363685,
|
||||||
|
"rotationDegrees": -115.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"constraintZones": [
|
||||||
|
{
|
||||||
|
"name": "Constraints Zone",
|
||||||
|
"minWaypointRelativePos": 1.1243680485338854,
|
||||||
|
"maxWaypointRelativePos": 2.077102803738317,
|
||||||
|
"constraints": {
|
||||||
|
"maxVelocity": 1.0,
|
||||||
|
"maxAcceleration": 1.5,
|
||||||
|
"maxAngularVelocity": 540.0,
|
||||||
|
"maxAngularAcceleration": 720.0,
|
||||||
|
"nominalVoltage": 12.0,
|
||||||
|
"unlimited": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pointTowardsZones": [],
|
||||||
|
"eventMarkers": [
|
||||||
|
{
|
||||||
|
"name": "Intake Start",
|
||||||
|
"waypointRelativePos": 0.7886754297269942,
|
||||||
|
"endWaypointRelativePos": null,
|
||||||
|
"command": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"globalConstraints": {
|
||||||
|
"maxVelocity": 4.0,
|
||||||
|
"maxAcceleration": 2.5,
|
||||||
|
"maxAngularVelocity": 540.0,
|
||||||
|
"maxAngularAcceleration": 720.0,
|
||||||
|
"nominalVoltage": 12.0,
|
||||||
|
"unlimited": false
|
||||||
|
},
|
||||||
|
"goalEndState": {
|
||||||
|
"velocity": 4.0,
|
||||||
|
"rotation": -45.365518355574764
|
||||||
|
},
|
||||||
|
"reversed": false,
|
||||||
|
"folder": null,
|
||||||
|
"idealStartingState": {
|
||||||
|
"velocity": 0,
|
||||||
|
"rotation": -129.95754893082906
|
||||||
|
},
|
||||||
|
"useDefaultConstraints": false
|
||||||
|
}
|
||||||
116
src/main/deploy/pathplanner/paths/over bump to pile.path
Normal file
116
src/main/deploy/pathplanner/paths/over bump to pile.path
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"version": "2025.0",
|
||||||
|
"waypoints": [
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 6.041634517766498,
|
||||||
|
"y": 6.3692588832487305
|
||||||
|
},
|
||||||
|
"prevControl": null,
|
||||||
|
"nextControl": {
|
||||||
|
"x": 6.511248730964468,
|
||||||
|
"y": 7.059868020304569
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": "over bump"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 7.220274111675127,
|
||||||
|
"y": 7.299279187817259
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 6.220274111675127,
|
||||||
|
"y": 7.299279187817259
|
||||||
|
},
|
||||||
|
"nextControl": {
|
||||||
|
"x": 8.220274111675131,
|
||||||
|
"y": 7.299279187817259
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 7.883258883248731,
|
||||||
|
"y": 4.831502538071066
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 7.952417879560978,
|
||||||
|
"y": 6.041784973535379
|
||||||
|
},
|
||||||
|
"nextControl": {
|
||||||
|
"x": 7.846426395939085,
|
||||||
|
"y": 4.186934010152284
|
||||||
|
},
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anchor": {
|
||||||
|
"x": 6.742194543297748,
|
||||||
|
"y": 5.589703440094898
|
||||||
|
},
|
||||||
|
"prevControl": {
|
||||||
|
"x": 7.598549873246986,
|
||||||
|
"y": 5.589703440094898
|
||||||
|
},
|
||||||
|
"nextControl": null,
|
||||||
|
"isLocked": false,
|
||||||
|
"linkedName": "after center grab"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rotationTargets": [
|
||||||
|
{
|
||||||
|
"waypointRelativePos": 1.0045454545454569,
|
||||||
|
"rotationDegrees": -115.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"waypointRelativePos": 2.348863636363685,
|
||||||
|
"rotationDegrees": -115.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"constraintZones": [
|
||||||
|
{
|
||||||
|
"name": "Constraints Zone",
|
||||||
|
"minWaypointRelativePos": 1.3403967538322836,
|
||||||
|
"maxWaypointRelativePos": 2.0,
|
||||||
|
"constraints": {
|
||||||
|
"maxVelocity": 1.0,
|
||||||
|
"maxAcceleration": 1.5,
|
||||||
|
"maxAngularVelocity": 540.0,
|
||||||
|
"maxAngularAcceleration": 720.0,
|
||||||
|
"nominalVoltage": 12.0,
|
||||||
|
"unlimited": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pointTowardsZones": [],
|
||||||
|
"eventMarkers": [
|
||||||
|
{
|
||||||
|
"name": "Intake Start",
|
||||||
|
"waypointRelativePos": 0.7886754297269942,
|
||||||
|
"endWaypointRelativePos": null,
|
||||||
|
"command": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"globalConstraints": {
|
||||||
|
"maxVelocity": 4.0,
|
||||||
|
"maxAcceleration": 2.5,
|
||||||
|
"maxAngularVelocity": 540.0,
|
||||||
|
"maxAngularAcceleration": 720.0,
|
||||||
|
"nominalVoltage": 12.0,
|
||||||
|
"unlimited": false
|
||||||
|
},
|
||||||
|
"goalEndState": {
|
||||||
|
"velocity": 4.0,
|
||||||
|
"rotation": -45.365518355574764
|
||||||
|
},
|
||||||
|
"reversed": false,
|
||||||
|
"folder": null,
|
||||||
|
"idealStartingState": {
|
||||||
|
"velocity": 2.0,
|
||||||
|
"rotation": -129.95754893082906
|
||||||
|
},
|
||||||
|
"useDefaultConstraints": false
|
||||||
|
}
|
||||||
@@ -3,12 +3,12 @@
|
|||||||
"waypoints": [
|
"waypoints": [
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 3.573857868020305,
|
"x": 3.5922741116751276,
|
||||||
"y": 6.3692588832487305
|
"y": 6.3692588832487305
|
||||||
},
|
},
|
||||||
"prevControl": null,
|
"prevControl": null,
|
||||||
"nextControl": {
|
"nextControl": {
|
||||||
"x": 2.7991959463121194,
|
"x": 2.817612189966942,
|
||||||
"y": 6.260219737341258
|
"y": 6.260219737341258
|
||||||
},
|
},
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
@@ -16,12 +16,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 3.2515736040609142,
|
"x": 1.925604060913706,
|
||||||
"y": 4.914375634517767
|
"y": 5.503695431472081
|
||||||
},
|
},
|
||||||
"prevControl": {
|
"prevControl": {
|
||||||
"x": 3.44523908448796,
|
"x": 2.119269541340752,
|
||||||
"y": 5.430816915656558
|
"y": 6.020136712610872
|
||||||
},
|
},
|
||||||
"nextControl": null,
|
"nextControl": null,
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
|
|||||||
@@ -3,38 +3,43 @@
|
|||||||
"waypoints": [
|
"waypoints": [
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 0.77458883248731,
|
"x": 0.32339086294416286,
|
||||||
"y": 5.927269035532995
|
"y": 5.9825177664974625
|
||||||
},
|
},
|
||||||
"prevControl": null,
|
"prevControl": null,
|
||||||
"nextControl": {
|
"nextControl": {
|
||||||
"x": 1.7745888324873098,
|
"x": 0.6364670050761427,
|
||||||
"y": 5.927269035532995
|
"y": 6.03776649746193
|
||||||
},
|
},
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
"linkedName": "trough"
|
"linkedName": "trough"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"anchor": {
|
"anchor": {
|
||||||
"x": 3.2515736040609142,
|
"x": 1.925604060913706,
|
||||||
"y": 4.914375634517767
|
"y": 5.503695431472081
|
||||||
},
|
},
|
||||||
"prevControl": {
|
"prevControl": {
|
||||||
"x": 2.6254213197969554,
|
"x": 1.409949238578681,
|
||||||
"y": 5.420822335025381
|
"y": 5.844395939086294
|
||||||
},
|
},
|
||||||
"nextControl": null,
|
"nextControl": null,
|
||||||
"isLocked": false,
|
"isLocked": false,
|
||||||
"linkedName": "left close"
|
"linkedName": "left close"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rotationTargets": [],
|
"rotationTargets": [
|
||||||
|
{
|
||||||
|
"waypointRelativePos": 0.7098520389751093,
|
||||||
|
"rotationDegrees": 176.84552599629856
|
||||||
|
}
|
||||||
|
],
|
||||||
"constraintZones": [],
|
"constraintZones": [],
|
||||||
"pointTowardsZones": [],
|
"pointTowardsZones": [],
|
||||||
"eventMarkers": [],
|
"eventMarkers": [],
|
||||||
"globalConstraints": {
|
"globalConstraints": {
|
||||||
"maxVelocity": 2.0,
|
"maxVelocity": 4.0,
|
||||||
"maxAcceleration": 1.5,
|
"maxAcceleration": 2.5,
|
||||||
"maxAngularVelocity": 540.0,
|
"maxAngularVelocity": 540.0,
|
||||||
"maxAngularAcceleration": 720.0,
|
"maxAngularAcceleration": 720.0,
|
||||||
"nominalVoltage": 12.0,
|
"nominalVoltage": 12.0,
|
||||||
@@ -50,5 +55,5 @@
|
|||||||
"velocity": 0,
|
"velocity": 0,
|
||||||
"rotation": 178.80651057601818
|
"rotation": 178.80651057601818
|
||||||
},
|
},
|
||||||
"useDefaultConstraints": true
|
"useDefaultConstraints": false
|
||||||
}
|
}
|
||||||
@@ -5,23 +5,31 @@
|
|||||||
package frc.robot;
|
package frc.robot;
|
||||||
|
|
||||||
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
||||||
|
import edu.wpi.first.wpilibj.GenericHID.RumbleType;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.OptionalDouble;
|
import java.util.OptionalDouble;
|
||||||
|
|
||||||
import org.littletonrobotics.junction.Logger;
|
import org.littletonrobotics.junction.Logger;
|
||||||
|
|
||||||
import com.pathplanner.lib.auto.AutoBuilder;
|
import com.pathplanner.lib.auto.AutoBuilder;
|
||||||
import com.pathplanner.lib.auto.NamedCommands;
|
import com.pathplanner.lib.auto.NamedCommands;
|
||||||
|
import com.pathplanner.lib.commands.PathPlannerAuto;
|
||||||
import com.pathplanner.lib.events.EventTrigger;
|
import com.pathplanner.lib.events.EventTrigger;
|
||||||
import com.pathplanner.lib.path.EventMarker;
|
import com.pathplanner.lib.path.EventMarker;
|
||||||
|
|
||||||
|
import edu.wpi.first.math.MathUtil;
|
||||||
import edu.wpi.first.math.geometry.Pose2d;
|
import edu.wpi.first.math.geometry.Pose2d;
|
||||||
|
import edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap;
|
||||||
import edu.wpi.first.math.util.Units;
|
import edu.wpi.first.math.util.Units;
|
||||||
|
import edu.wpi.first.util.sendable.Sendable;
|
||||||
|
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||||
import edu.wpi.first.wpilibj.Timer;
|
import edu.wpi.first.wpilibj.Timer;
|
||||||
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
|
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
|
||||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||||
import edu.wpi.first.wpilibj2.command.Command;
|
import edu.wpi.first.wpilibj2.command.Command;
|
||||||
import edu.wpi.first.wpilibj2.command.Commands;
|
import edu.wpi.first.wpilibj2.command.Commands;
|
||||||
|
import edu.wpi.first.wpilibj2.command.FunctionalCommand;
|
||||||
import edu.wpi.first.wpilibj2.command.InstantCommand;
|
import edu.wpi.first.wpilibj2.command.InstantCommand;
|
||||||
import edu.wpi.first.wpilibj2.command.PrintCommand;
|
import edu.wpi.first.wpilibj2.command.PrintCommand;
|
||||||
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
|
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
|
||||||
@@ -62,6 +70,8 @@ public class RobotContainer {
|
|||||||
|
|
||||||
private Timer shiftTimer;
|
private Timer shiftTimer;
|
||||||
|
|
||||||
|
private boolean resetOdometryToVisualPose;
|
||||||
|
|
||||||
public RobotContainer() {
|
public RobotContainer() {
|
||||||
vision = new PhotonVision();
|
vision = new PhotonVision();
|
||||||
drivetrain = new Drivetrain(null);
|
drivetrain = new Drivetrain(null);
|
||||||
@@ -73,8 +83,9 @@ public class RobotContainer {
|
|||||||
//climber = new Climber();
|
//climber = new Climber();
|
||||||
configureNamedCommands();
|
configureNamedCommands();
|
||||||
|
|
||||||
|
resetOdometryToVisualPose = false;
|
||||||
|
|
||||||
//vision.addPoseEstimateConsumer(drivetrain::consumeVisualPose);
|
vision.addPoseEstimateConsumer(drivetrain::consumeVisualPose);
|
||||||
vision.addPoseEstimateConsumer((vp) -> {
|
vision.addPoseEstimateConsumer((vp) -> {
|
||||||
Logger.recordOutput(
|
Logger.recordOutput(
|
||||||
"Vision/" + vp.cameraName() + "/Pose",
|
"Vision/" + vp.cameraName() + "/Pose",
|
||||||
@@ -82,6 +93,12 @@ public class RobotContainer {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
vision.addPoseEstimateConsumer((vp) -> {
|
||||||
|
if(resetOdometryToVisualPose) {
|
||||||
|
drivetrain.resetOdometry(vp.visualPose());
|
||||||
|
resetOdometryToVisualPose = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
driver = new CommandXboxController(OIConstants.kDriverControllerPort);
|
driver = new CommandXboxController(OIConstants.kDriverControllerPort);
|
||||||
secondary = new CommandXboxController(OIConstants.kOperatorControllerPort);
|
secondary = new CommandXboxController(OIConstants.kOperatorControllerPort);
|
||||||
@@ -90,13 +107,23 @@ public class RobotContainer {
|
|||||||
shiftTimer.reset();
|
shiftTimer.reset();
|
||||||
|
|
||||||
configureBindings();
|
configureBindings();
|
||||||
//testConfigureBindings();
|
|
||||||
configureShiftDisplay();
|
configureShiftDisplay();
|
||||||
|
//testConfigureBindings();
|
||||||
|
|
||||||
|
|
||||||
if(AutoConstants.kAutoConfigOk) {
|
if(AutoConstants.kAutoConfigOk) {
|
||||||
autoChooser = AutoBuilder.buildAutoChooser();
|
autoChooser = AutoBuilder.buildAutoChooser();
|
||||||
SmartDashboard.putData("Auto Chooser", autoChooser);
|
SmartDashboard.putData("Auto Chooser", autoChooser);
|
||||||
|
|
||||||
|
autoChooser.addOption(
|
||||||
|
"MOVE B____ right to center",
|
||||||
|
new PathPlannerAuto("MOVE B____ left to center", true)
|
||||||
|
);
|
||||||
|
|
||||||
|
autoChooser.addOption(
|
||||||
|
"right to center",
|
||||||
|
new PathPlannerAuto("left to center", true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +254,7 @@ public class RobotContainer {
|
|||||||
|
|
||||||
// Useful for testing PID and FF responses of the shooter
|
// Useful for testing PID and FF responses of the shooter
|
||||||
// You need to have graphs up of the logged data to make sure the response is correct
|
// You need to have graphs up of the logged data to make sure the response is correct
|
||||||
secondary.a().whileTrue(shooter.maintainSpeed(ShooterSpeeds.kHubSpeed));
|
//secondary.a().whileTrue(shooter.maintainSpeed(ShooterSpeeds.kHubSpeed));
|
||||||
secondary.b().whileTrue(shooter.maintainSpeed(ShooterSpeeds.kFeedSpeed));
|
secondary.b().whileTrue(shooter.maintainSpeed(ShooterSpeeds.kFeedSpeed));
|
||||||
|
|
||||||
// Useful for testing PID and FF responses of the intake pivot
|
// Useful for testing PID and FF responses of the intake pivot
|
||||||
@@ -258,7 +285,11 @@ public class RobotContainer {
|
|||||||
|
|
||||||
intakePivot.setDefaultCommand(intakePivot.manualSpeed(() -> secondary.getLeftY()));
|
intakePivot.setDefaultCommand(intakePivot.manualSpeed(() -> secondary.getLeftY()));
|
||||||
|
|
||||||
|
// secondary.leftStick().whileTrue(intakePivot.manualSpeed(() -> secondary.getLeftY()));
|
||||||
|
|
||||||
|
driver.a().onTrue(new InstantCommand(() -> resetOdometryToVisualPose = true));
|
||||||
driver.y().whileTrue(drivetrain.zeroHeading());
|
driver.y().whileTrue(drivetrain.zeroHeading());
|
||||||
|
driver.x().whileTrue(drivetrain.setX());
|
||||||
|
|
||||||
driver.leftTrigger().whileTrue(
|
driver.leftTrigger().whileTrue(
|
||||||
drivetrain.lockRotationToHub(
|
drivetrain.lockRotationToHub(
|
||||||
@@ -271,7 +302,22 @@ public class RobotContainer {
|
|||||||
driver.leftBumper().whileTrue(intakeRoller.runOut());
|
driver.leftBumper().whileTrue(intakeRoller.runOut());
|
||||||
driver.rightBumper().whileTrue(intakeRoller.runIn());
|
driver.rightBumper().whileTrue(intakeRoller.runIn());
|
||||||
|
|
||||||
driver.rightTrigger().whileTrue(spindexer.spinToShooter());
|
driver.rightTrigger().whileTrue(
|
||||||
|
spindexer.spinToShooter(shooter::getAverageActualSpeeds, 2000).alongWith(
|
||||||
|
intakeRoller.runIn()/* ,
|
||||||
|
intakePivot.jimmy(.5)*/
|
||||||
|
)
|
||||||
|
);
|
||||||
|
driver.rightTrigger().whileTrue(
|
||||||
|
intakePivot.jimmy(.5)
|
||||||
|
);
|
||||||
|
|
||||||
|
secondary.leftBumper().onTrue(new InstantCommand(() -> {}, intakePivot));
|
||||||
|
|
||||||
|
driver.rightTrigger().onFalse(
|
||||||
|
intakePivot.manualSpeed(() -> 0.75).withTimeout(0.5)
|
||||||
|
);
|
||||||
|
|
||||||
driver.b().whileTrue(spindexer.spinToIntake());
|
driver.b().whileTrue(spindexer.spinToIntake());
|
||||||
/* driver.b().whileTrue(
|
/* driver.b().whileTrue(
|
||||||
drivetrain.lockToYaw(
|
drivetrain.lockToYaw(
|
||||||
@@ -288,36 +334,57 @@ public class RobotContainer {
|
|||||||
secondary.a().toggleOnTrue(shooter.maintainSpeed(ShooterSpeeds.kHubSpeed));
|
secondary.a().toggleOnTrue(shooter.maintainSpeed(ShooterSpeeds.kHubSpeed));
|
||||||
secondary.x().toggleOnTrue(shooter.maintainSpeed(ShooterSpeeds.kFeedSpeed));
|
secondary.x().toggleOnTrue(shooter.maintainSpeed(ShooterSpeeds.kFeedSpeed));
|
||||||
|
|
||||||
secondary.y().onTrue(hood.trackToAngle(() -> Units.degreesToRadians(40)));
|
//hood.setDefaultCommand(hood.trackToAngle(() -> Units.degreesToRadians(MathUtil.clamp(hoodAngle, 0, 40))));
|
||||||
|
//secondary.y().onTrue(hood.trackToAngle(() -> Units.degreesToRadians(40)));
|
||||||
//40 good for feeding
|
//40 good for feeding
|
||||||
secondary.b().onTrue(hood.trackToAngle(() -> Units.degreesToRadians(30)));
|
//secondary.b().onTrue(hood.trackToAngle(() -> Units.degreesToRadians(30)));
|
||||||
//30 degrees good for shooter far near outpost
|
//30 degrees good for shooter far near outpost
|
||||||
secondary.rightBumper().onTrue(hood.trackToAngle(() -> Units.degreesToRadians(10)));
|
secondary.rightBumper().whileTrue(hood.trackToAngle(() -> Units.degreesToRadians(10)));
|
||||||
//10 degrees good for shooting ~33in away from hub
|
//10 degrees good for shooting ~33in away from hub
|
||||||
|
|
||||||
/*
|
hood.setDefaultCommand(hood.trackToAnglePoseBased(drivetrain, shooter));
|
||||||
hood.setDefaultCommand(hood.trackToAngle(() -> {
|
|
||||||
|
/*hood.setDefaultCommand(hood.trackToAngle(() -> {
|
||||||
Pose2d drivetrainPose = drivetrain.getPose();
|
Pose2d drivetrainPose = drivetrain.getPose();
|
||||||
Pose2d hubPose = Utilities.getHubPose();
|
Pose2d hubPose = Utilities.getHubPose();
|
||||||
|
|
||||||
double distance = drivetrainPose.getTranslation()
|
double distance = drivetrainPose.getTranslation()
|
||||||
.plus(CompetitionConstants.kRobotToShooter.getTranslation().toTranslation2d())
|
|
||||||
.getDistance(hubPose.getTranslation());
|
.getDistance(hubPose.getTranslation());
|
||||||
|
|
||||||
if(HoodConstants.kUseInterpolatorForAngle) {
|
Logger.recordOutput("Hood/DistanceToHub", distance);
|
||||||
return HoodConstants.kDistanceToAngle.get(distance);
|
|
||||||
|
Optional<ShooterSpeeds> currentSpeeds = shooter.getTargetSpeeds();
|
||||||
|
|
||||||
|
if(currentSpeeds.isPresent()) {
|
||||||
|
InterpolatingDoubleTreeMap map = HoodConstants.kHoodInterpolators.get(currentSpeeds.get());
|
||||||
|
|
||||||
|
if(map != null) {
|
||||||
|
return MathUtil.clamp(map.get(distance), 0, 40);
|
||||||
} else {
|
} else {
|
||||||
// TODO The average actual speeds isn't <i>really</i> the exit velocity of the ball
|
return 0;
|
||||||
// on a hooded shooter, based on documentation, it's more like 30-50% depending on
|
}
|
||||||
// hood material, surface friction, etc.
|
} else {
|
||||||
return Utilities.shotAngle(
|
return 0;
|
||||||
shooter.getAverageActualSpeeds(),
|
|
||||||
distance,
|
|
||||||
CompetitionConstants.kHubGoalHeightMeters - ShooterConstants.kShooterHeightMeters,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}));*/
|
}));*/
|
||||||
|
|
||||||
|
new Trigger(() -> MathUtil.isNear(
|
||||||
|
shooter.getTargetSpeeds().isEmpty() ? 0 : shooter.getTargetSpeeds().get().getSpeedRPM(),
|
||||||
|
shooter.getAverageActualSpeeds(),
|
||||||
|
150)).onTrue(
|
||||||
|
new FunctionalCommand(
|
||||||
|
() -> {},
|
||||||
|
() -> {
|
||||||
|
driver.setRumble(RumbleType.kBothRumble, .75);
|
||||||
|
secondary.setRumble(RumbleType.kBothRumble, .75);
|
||||||
|
},
|
||||||
|
(b) -> {
|
||||||
|
driver.setRumble(RumbleType.kBothRumble, 0);
|
||||||
|
secondary.setRumble(RumbleType.kBothRumble, 0);
|
||||||
|
},
|
||||||
|
() -> false
|
||||||
|
).withTimeout(1)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureNamedCommands() {
|
private void configureNamedCommands() {
|
||||||
@@ -342,7 +409,7 @@ public class RobotContainer {
|
|||||||
|
|
||||||
NamedCommands.registerCommand("spinup",
|
NamedCommands.registerCommand("spinup",
|
||||||
shooter.maintainSpeed(ShooterSpeeds.kHubSpeed)
|
shooter.maintainSpeed(ShooterSpeeds.kHubSpeed)
|
||||||
.withTimeout(3));
|
.withTimeout(2));
|
||||||
|
|
||||||
NamedCommands.registerCommand("shoot close",
|
NamedCommands.registerCommand("shoot close",
|
||||||
spindexer.spinToShooter()
|
spindexer.spinToShooter()
|
||||||
@@ -353,28 +420,43 @@ public class RobotContainer {
|
|||||||
// NamedCommands.registerCommand("Intake Start", intakeRoller.runIn());
|
// NamedCommands.registerCommand("Intake Start", intakeRoller.runIn());
|
||||||
|
|
||||||
new EventTrigger("Intake Start")
|
new EventTrigger("Intake Start")
|
||||||
.onTrue(intakeRoller.runIn());
|
.onTrue(
|
||||||
|
intakeRoller.runIn());
|
||||||
|
|
||||||
|
new EventTrigger("windup trigger")
|
||||||
|
.onTrue(
|
||||||
|
shooter.maintainSpeed(ShooterSpeeds.kHubSpeed));
|
||||||
|
|
||||||
NamedCommands.registerCommand("stop spindexer", spindexer.instantaneousStop());
|
NamedCommands.registerCommand("stop spindexer", spindexer.instantaneousStop());
|
||||||
|
|
||||||
NamedCommands.registerCommand("jimmy",
|
NamedCommands.registerCommand("jimmy",
|
||||||
Commands.repeatingSequence(
|
intakePivot.jimmy(0.2)
|
||||||
intakePivot.manualSpeed(() -> -0.75).withTimeout(0.2)
|
|
||||||
.andThen(intakePivot.manualSpeed(() -> 0.75).withTimeout(0.2))
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
NamedCommands.registerCommand("shoot N jimmy",
|
NamedCommands.registerCommand("shoot N jimmy",
|
||||||
Commands.parallel(
|
Commands.parallel(
|
||||||
Commands.repeatingSequence(
|
intakePivot.jimmy(0.5),
|
||||||
intakePivot.manualSpeed(() -> -0.75).withTimeout(0.5),
|
|
||||||
intakePivot.manualSpeed(() -> 0.75).withTimeout(0.5)
|
|
||||||
),
|
|
||||||
spindexer.spinToShooter()
|
spindexer.spinToShooter()
|
||||||
.alongWith(shooter.maintainSpeed(ShooterSpeeds.kHubSpeed),
|
.alongWith(shooter.maintainSpeed(ShooterSpeeds.kHubSpeed),
|
||||||
hood.trackToAngle(() -> Units.degreesToRadians(10)))
|
hood.trackToAngle(() -> Units.degreesToRadians(10)))
|
||||||
|
|
||||||
).withTimeout(3).andThen(spindexer.instantaneousStop()));
|
).withTimeout(3).andThen(spindexer.instantaneousStop()));
|
||||||
|
|
||||||
|
NamedCommands.registerCommand("aim",
|
||||||
|
hood.trackToAnglePoseBased(drivetrain, shooter)
|
||||||
|
.alongWith(
|
||||||
|
shooter.maintainSpeed(ShooterSpeeds.kHubSpeed),
|
||||||
|
intakePivot.jimmy(0.5),
|
||||||
|
drivetrain.lockRotationToHub(() -> 0.0, () -> 0.0, false))
|
||||||
|
.withTimeout(0.5));
|
||||||
|
|
||||||
|
NamedCommands.registerCommand("auto shoot",
|
||||||
|
hood.trackToAnglePoseBased(drivetrain, shooter)
|
||||||
|
.alongWith(
|
||||||
|
shooter.maintainSpeed(ShooterSpeeds.kHubSpeed),
|
||||||
|
spindexer.spinToShooter(),
|
||||||
|
intakePivot.jimmy(0.5),
|
||||||
|
drivetrain.lockRotationToHub(() -> 0.0, () -> 0.0, false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command getAutonomousCommand() {
|
public Command getAutonomousCommand() {
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ public class AutoConstants {
|
|||||||
public static final double kPXYController = 3.5;
|
public static final double kPXYController = 3.5;
|
||||||
public static final double kPThetaController = 5;
|
public static final double kPThetaController = 5;
|
||||||
|
|
||||||
public static final double kYawPIDTolerance = Units.degreesToRadians(2);
|
|
||||||
|
|
||||||
public static final double kAlignPXYController = 2;
|
public static final double kAlignPXYController = 2;
|
||||||
public static final double kAlignPThetaController = 5;
|
public static final double kAlignPThetaController = 5;
|
||||||
|
|
||||||
|
|||||||
@@ -38,14 +38,15 @@ public class DrivetrainConstants {
|
|||||||
public static final boolean kGyroReversed = true;
|
public static final boolean kGyroReversed = true;
|
||||||
|
|
||||||
// TODO Hold over from 2025, adjust?
|
// TODO Hold over from 2025, adjust?
|
||||||
public static final double kHeadingP = .1;
|
public static final double kHeadingP = .65;
|
||||||
public static final double kXTranslationP = .5;
|
public static final double kXTranslationP = .5;
|
||||||
public static final double kYTranslationP = .5;
|
public static final double kYTranslationP = .5;
|
||||||
|
public static final double kYawPIDTolerance = Units.degreesToRadians(1);
|
||||||
|
|
||||||
// TODO How much do we trust gyro and encoders vs vision estimates.
|
// TODO How much do we trust gyro and encoders vs vision estimates.
|
||||||
// NOTE: Bigger values indicate LESS trust. Generally all three values for a given matrix should be the same
|
// NOTE: Bigger values indicate LESS trust. Generally all three values for a given matrix should be the same
|
||||||
public static final Matrix<N3, N1> kSensorFusionOdometryStdDevs = VecBuilder.fill(0.1, 0.1, 0.1);
|
public static final Matrix<N3, N1> kSensorFusionOdometryStdDevs = VecBuilder.fill(0.1, 0.1, 0.1);
|
||||||
public static final Matrix<N3, N1> kVisionOdometryStdDevs = VecBuilder.fill(0.9, 0.9, 0.9);
|
public static final Matrix<N3, N1> kVisionOdometryStdDevs = VecBuilder.fill(0.3, 0.3, 0.3);
|
||||||
|
|
||||||
// YOU SHOULDN'T NEED TO CHANGE ANYTHING BELOW THIS LINE UNLESS YOU'RE ADDING A NEW CONFIGURATION ITEM
|
// YOU SHOULDN'T NEED TO CHANGE ANYTHING BELOW THIS LINE UNLESS YOU'RE ADDING A NEW CONFIGURATION ITEM
|
||||||
public static final SwerveDriveKinematics kDriveKinematics = new SwerveDriveKinematics(
|
public static final SwerveDriveKinematics kDriveKinematics = new SwerveDriveKinematics(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import java.io.File;
|
|||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.revrobotics.spark.ClosedLoopSlot;
|
import com.revrobotics.spark.ClosedLoopSlot;
|
||||||
import com.revrobotics.spark.FeedbackSensor;
|
import com.revrobotics.spark.FeedbackSensor;
|
||||||
@@ -12,7 +13,9 @@ import com.revrobotics.spark.config.SparkMaxConfig;
|
|||||||
import com.revrobotics.spark.config.SparkBaseConfig.IdleMode;
|
import com.revrobotics.spark.config.SparkBaseConfig.IdleMode;
|
||||||
|
|
||||||
import edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap;
|
import edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap;
|
||||||
|
import edu.wpi.first.math.util.Units;
|
||||||
import edu.wpi.first.wpilibj.Filesystem;
|
import edu.wpi.first.wpilibj.Filesystem;
|
||||||
|
import frc.robot.constants.ShooterConstants.ShooterSpeeds;
|
||||||
|
|
||||||
public class HoodConstants {
|
public class HoodConstants {
|
||||||
// TODO Real Values
|
// TODO Real Values
|
||||||
@@ -43,9 +46,9 @@ public class HoodConstants {
|
|||||||
|
|
||||||
public static final IdleMode kIdleMode = IdleMode.kBrake;
|
public static final IdleMode kIdleMode = IdleMode.kBrake;
|
||||||
|
|
||||||
// TODO This needs to be filled in from some source
|
public static final Map<ShooterSpeeds, InterpolatingDoubleTreeMap> kHoodInterpolators = Map.of(
|
||||||
public static final InterpolatingDoubleTreeMap kDistanceToAngle = new InterpolatingDoubleTreeMap();
|
ShooterSpeeds.kHubSpeed, new InterpolatingDoubleTreeMap()
|
||||||
|
);
|
||||||
// YOU SHOULDN'T NEED TO CHANGE ANYTHING BELOW THIS LINE UNLESS YOU'RE ADDING A CONFIGURATION ITEM
|
// YOU SHOULDN'T NEED TO CHANGE ANYTHING BELOW THIS LINE UNLESS YOU'RE ADDING A CONFIGURATION ITEM
|
||||||
|
|
||||||
public static final SparkMaxConfig kConfig = new SparkMaxConfig();
|
public static final SparkMaxConfig kConfig = new SparkMaxConfig();
|
||||||
@@ -66,27 +69,24 @@ public class HoodConstants {
|
|||||||
.feedForward
|
.feedForward
|
||||||
.sva(kS, kV, kA);
|
.sva(kS, kV, kA);
|
||||||
|
|
||||||
|
kHoodInterpolators.get(ShooterSpeeds.kHubSpeed).put(
|
||||||
|
Double.valueOf(Units.inchesToMeters(22.2 + 40)),
|
||||||
|
Double.valueOf(Units.degreesToRadians(9.5)));
|
||||||
|
|
||||||
File interpolatorFile = Path.of(
|
kHoodInterpolators.get(ShooterSpeeds.kHubSpeed).put(
|
||||||
Filesystem.getDeployDirectory().getAbsolutePath().toString(),
|
Double.valueOf(Units.inchesToMeters(22.2 + 60)),
|
||||||
"interpolatorData.csv"
|
Double.valueOf(Units.degreesToRadians(12.5)));
|
||||||
).toFile();
|
|
||||||
|
|
||||||
if(interpolatorFile.exists()) {
|
kHoodInterpolators.get(ShooterSpeeds.kHubSpeed).put(
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(interpolatorFile))) {
|
Double.valueOf(Units.inchesToMeters(22.2 + 80)),
|
||||||
reader.lines().forEach((s) -> {
|
Double.valueOf(Units.degreesToRadians(16.25)));
|
||||||
if(s.trim() != "") { //Empty or whitespace line protection
|
|
||||||
String[] lineSplit = s.split(",");
|
|
||||||
|
|
||||||
kDistanceToAngle.put(
|
kHoodInterpolators.get(ShooterSpeeds.kHubSpeed).put(
|
||||||
Double.valueOf(lineSplit[0].replace("\"", "")),
|
Double.valueOf(Units.inchesToMeters(22.2 + 100)),
|
||||||
Double.valueOf(lineSplit[1].replace("\"", ""))
|
Double.valueOf(Units.degreesToRadians(20.5)));
|
||||||
);
|
|
||||||
}
|
kHoodInterpolators.get(ShooterSpeeds.kHubSpeed).put(
|
||||||
});
|
Double.valueOf(Units.inchesToMeters(22.2 + 120)),
|
||||||
} catch (IOException e) {
|
Double.valueOf(Units.degreesToRadians(23.5)));
|
||||||
// This condition is never reached because of the if exists line above
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class ModuleConstants {
|
|||||||
|
|
||||||
// TODO Hold over from 2025, adjust?
|
// TODO Hold over from 2025, adjust?
|
||||||
public static final int kDriveMotorStatorCurrentLimit = 90;
|
public static final int kDriveMotorStatorCurrentLimit = 90;
|
||||||
public static final int kDriveMotorSupplyCurrentLimit = 55;
|
public static final int kDriveMotorSupplyCurrentLimit = 40;
|
||||||
|
|
||||||
// TODO Hold over from 2025, adjust?
|
// TODO Hold over from 2025, adjust?
|
||||||
public static final InvertedValue kDriveInversionState = InvertedValue.Clockwise_Positive;
|
public static final InvertedValue kDriveInversionState = InvertedValue.Clockwise_Positive;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class PhotonConstants {
|
|||||||
Units.inchesToMeters(28.5),
|
Units.inchesToMeters(28.5),
|
||||||
new Rotation3d(
|
new Rotation3d(
|
||||||
Units.degreesToRadians(0),
|
Units.degreesToRadians(0),
|
||||||
Units.degreesToRadians(24.0),
|
Units.degreesToRadians(-24.0),
|
||||||
Units.degreesToRadians(30.0)
|
Units.degreesToRadians(30.0)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -28,7 +28,7 @@ public class PhotonConstants {
|
|||||||
Units.inchesToMeters(28.5),
|
Units.inchesToMeters(28.5),
|
||||||
new Rotation3d(
|
new Rotation3d(
|
||||||
Units.degreesToRadians(0.0),
|
Units.degreesToRadians(0.0),
|
||||||
Units.degreesToRadians(24.0),
|
Units.degreesToRadians(-24.0),
|
||||||
Units.degreesToRadians(-10.0)
|
Units.degreesToRadians(-10.0)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package frc.robot.constants;
|
package frc.robot.constants;
|
||||||
|
|
||||||
|
import com.revrobotics.spark.ClosedLoopSlot;
|
||||||
import com.revrobotics.spark.FeedbackSensor;
|
import com.revrobotics.spark.FeedbackSensor;
|
||||||
import com.revrobotics.spark.config.SparkMaxConfig;
|
import com.revrobotics.spark.config.SparkMaxConfig;
|
||||||
import com.revrobotics.spark.config.SparkBaseConfig.IdleMode;
|
import com.revrobotics.spark.config.SparkBaseConfig.IdleMode;
|
||||||
|
|
||||||
|
import edu.wpi.first.math.controller.SimpleMotorFeedforward;
|
||||||
import edu.wpi.first.math.util.Units;
|
import edu.wpi.first.math.util.Units;
|
||||||
|
|
||||||
|
|
||||||
public class ShooterConstants {
|
public class ShooterConstants {
|
||||||
public enum ShooterSpeeds {
|
public enum ShooterSpeeds {
|
||||||
kHubSpeed(3000.0),
|
kHubSpeed(3000.0),
|
||||||
@@ -40,18 +43,18 @@ public class ShooterConstants {
|
|||||||
public static final boolean kLeftShooterMotorInverted = true;
|
public static final boolean kLeftShooterMotorInverted = true;
|
||||||
public static final boolean kRightShooterMotorInverted = false;
|
public static final boolean kRightShooterMotorInverted = false;
|
||||||
|
|
||||||
public static final double kLeftP = 0.001;
|
public static final double kLeftP = 0.75;//0.01;//0.001;
|
||||||
public static final double kLeftI = 0;
|
public static final double kLeftI = 0;
|
||||||
public static final double kLeftD = 0;
|
public static final double kLeftD = 0;//0.1;//1.8;
|
||||||
public static final double kLeftS = 0;
|
public static final double kLeftS = 0;
|
||||||
public static final double kLeftV = 0.0013;
|
public static final double kLeftV = 0.00129;
|
||||||
public static final double kLeftA = 0;
|
public static final double kLeftA = 0;
|
||||||
|
|
||||||
public static final double kRightP = 0.001;
|
public static final double kRightP = 0.75;//0.001;//0.001;
|
||||||
public static final double kRightI = 0;
|
public static final double kRightI = 0;
|
||||||
public static final double kRightD = 0.000;
|
public static final double kRightD = 0;//0.1;
|
||||||
public static final double kRightS = 0;
|
public static final double kRightS = 0;
|
||||||
public static final double kRightV = 0.00121;
|
public static final double kRightV = 0.00125;
|
||||||
public static final double kRightA = 0;
|
public static final double kRightA = 0;
|
||||||
|
|
||||||
public static final double kMaxManualSpeedMultiplier = 1;
|
public static final double kMaxManualSpeedMultiplier = 1;
|
||||||
@@ -76,13 +79,15 @@ public class ShooterConstants {
|
|||||||
.inverted(kLeftShooterMotorInverted);
|
.inverted(kLeftShooterMotorInverted);
|
||||||
kLeftMotorConfig.absoluteEncoder
|
kLeftMotorConfig.absoluteEncoder
|
||||||
.positionConversionFactor(1)
|
.positionConversionFactor(1)
|
||||||
.velocityConversionFactor(60);
|
.velocityConversionFactor(60)
|
||||||
|
.averageDepth(8); // VERY IMPORTANT FOR RESPONSE OF FLYWHEEL DEFAULTS ARE DOGWATER
|
||||||
kLeftMotorConfig.closedLoop
|
kLeftMotorConfig.closedLoop
|
||||||
.feedbackSensor(FeedbackSensor.kAbsoluteEncoder)
|
.feedbackSensor(FeedbackSensor.kAbsoluteEncoder)
|
||||||
.pid(kLeftP, kLeftI, kLeftD)
|
.pid(kLeftP, kLeftI, kLeftD, ClosedLoopSlot.kSlot0)
|
||||||
.outputRange(-1, 1)
|
.outputRange(-1, 1)
|
||||||
|
.allowedClosedLoopError(25.0, ClosedLoopSlot.kSlot0)
|
||||||
.feedForward
|
.feedForward
|
||||||
.sva(kLeftS, kLeftV, kLeftA);
|
.sva(kLeftS, kLeftV, kLeftA, ClosedLoopSlot.kSlot0);
|
||||||
|
|
||||||
kRightMotorConfig
|
kRightMotorConfig
|
||||||
.idleMode(kShooterIdleMode)
|
.idleMode(kShooterIdleMode)
|
||||||
@@ -91,12 +96,14 @@ public class ShooterConstants {
|
|||||||
kRightMotorConfig.absoluteEncoder
|
kRightMotorConfig.absoluteEncoder
|
||||||
.positionConversionFactor(1)
|
.positionConversionFactor(1)
|
||||||
.velocityConversionFactor(60)
|
.velocityConversionFactor(60)
|
||||||
|
.averageDepth(8)// VERY IMPORTANT FOR RESPONSE OF FLYWHEEL DEFAULTS ARE DOGWATER
|
||||||
.inverted(true);
|
.inverted(true);
|
||||||
kRightMotorConfig.closedLoop
|
kRightMotorConfig.closedLoop
|
||||||
.feedbackSensor(FeedbackSensor.kAbsoluteEncoder)
|
.feedbackSensor(FeedbackSensor.kAbsoluteEncoder)
|
||||||
.pid(kRightP, kRightI, kRightD)
|
.pid(kRightP, kRightI, kRightD)
|
||||||
.outputRange(-1, 1)
|
.outputRange(-1, 1)
|
||||||
|
.allowedClosedLoopError(25.0, ClosedLoopSlot.kSlot0)
|
||||||
.feedForward
|
.feedForward
|
||||||
.sva(kRightS, kRightV, kRightA);
|
.sva(kRightS, kRightV, kRightA, ClosedLoopSlot.kSlot0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,12 +82,12 @@ public class Drivetrain extends SubsystemBase {
|
|||||||
gyro = new AHRS(NavXComType.kMXP_SPI);
|
gyro = new AHRS(NavXComType.kMXP_SPI);
|
||||||
|
|
||||||
yawRotationController = new PIDController(
|
yawRotationController = new PIDController(
|
||||||
AutoConstants.kPThetaController,
|
DrivetrainConstants.kHeadingP,
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
yawRotationController.enableContinuousInput(-Math.PI, Math.PI);
|
yawRotationController.enableContinuousInput(-Math.PI, Math.PI);
|
||||||
yawRotationController.setTolerance(AutoConstants.kYawPIDTolerance);
|
yawRotationController.setTolerance(DrivetrainConstants.kYawPIDTolerance);
|
||||||
|
|
||||||
// TODO 2025 used non-standard deviations for encoder/gyro inputs and vision, will need to be tuned for 2026 in the future
|
// TODO 2025 used non-standard deviations for encoder/gyro inputs and vision, will need to be tuned for 2026 in the future
|
||||||
estimator = new SwerveDrivePoseEstimator(
|
estimator = new SwerveDrivePoseEstimator(
|
||||||
@@ -262,10 +262,17 @@ public class Drivetrain extends SubsystemBase {
|
|||||||
targetRotation = targetRotation.rotateBy(Rotation2d.k180deg);
|
targetRotation = targetRotation.rotateBy(Rotation2d.k180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return yawRotationController.calculate(
|
Logger.recordOutput("/HubAutoAlign/CurrentHeader", getHeading().getRadians());
|
||||||
|
Logger.recordOutput("/HubAutoAlign/Setpoint", targetRotation.getRadians());
|
||||||
|
|
||||||
|
double outputPower = -yawRotationController.calculate(
|
||||||
getHeading().getRadians(),
|
getHeading().getRadians(),
|
||||||
targetRotation.getRadians()
|
targetRotation.getRadians()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Logger.recordOutput("/HubAutoAlign/OutputPower", outputPower);
|
||||||
|
|
||||||
|
return outputPower;
|
||||||
},
|
},
|
||||||
() -> true
|
() -> true
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package frc.robot.subsystems;
|
package frc.robot.subsystems;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.DoubleSupplier;
|
import java.util.function.DoubleSupplier;
|
||||||
|
|
||||||
import org.littletonrobotics.junction.Logger;
|
import org.littletonrobotics.junction.Logger;
|
||||||
@@ -12,12 +13,18 @@ import com.revrobotics.spark.SparkMax;
|
|||||||
import com.revrobotics.spark.SparkBase.ControlType;
|
import com.revrobotics.spark.SparkBase.ControlType;
|
||||||
import com.revrobotics.spark.SparkLowLevel.MotorType;
|
import com.revrobotics.spark.SparkLowLevel.MotorType;
|
||||||
|
|
||||||
|
import edu.wpi.first.math.MathUtil;
|
||||||
|
import edu.wpi.first.math.geometry.Pose2d;
|
||||||
|
import edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap;
|
||||||
import edu.wpi.first.wpilibj.Timer;
|
import edu.wpi.first.wpilibj.Timer;
|
||||||
|
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||||
import edu.wpi.first.wpilibj2.command.Command;
|
import edu.wpi.first.wpilibj2.command.Command;
|
||||||
import edu.wpi.first.wpilibj2.command.InstantCommand;
|
import edu.wpi.first.wpilibj2.command.InstantCommand;
|
||||||
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
||||||
import edu.wpi.first.wpilibj2.command.button.Trigger;
|
import edu.wpi.first.wpilibj2.command.button.Trigger;
|
||||||
import frc.robot.constants.HoodConstants;
|
import frc.robot.constants.HoodConstants;
|
||||||
|
import frc.robot.constants.ShooterConstants.ShooterSpeeds;
|
||||||
|
import frc.robot.utilities.Utilities;
|
||||||
|
|
||||||
public class Hood extends SubsystemBase {
|
public class Hood extends SubsystemBase {
|
||||||
private SparkMax motor;
|
private SparkMax motor;
|
||||||
@@ -68,6 +75,21 @@ public class Hood extends SubsystemBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void periodic() {
|
public void periodic() {
|
||||||
|
SmartDashboard.putNumber(
|
||||||
|
"HoodTargetDegrees",
|
||||||
|
Math.toDegrees(currentTargetDegrees)
|
||||||
|
);
|
||||||
|
|
||||||
|
SmartDashboard.putNumber(
|
||||||
|
"HoodCurrentAngle",
|
||||||
|
Math.toDegrees(encoder.getPosition())
|
||||||
|
);
|
||||||
|
|
||||||
|
SmartDashboard.putBoolean(
|
||||||
|
"HoodAtSetpoint",
|
||||||
|
controller.isAtSetpoint()
|
||||||
|
);
|
||||||
|
|
||||||
Logger.recordOutput("Hood/OutputCurrent", motor.getOutputCurrent());
|
Logger.recordOutput("Hood/OutputCurrent", motor.getOutputCurrent());
|
||||||
Logger.recordOutput("Hood/CurrentTarget", Math.toDegrees(currentTargetDegrees));
|
Logger.recordOutput("Hood/CurrentTarget", Math.toDegrees(currentTargetDegrees));
|
||||||
Logger.recordOutput("Hood/CurrentAngle", Math.toDegrees(encoder.getPosition()));
|
Logger.recordOutput("Hood/CurrentAngle", Math.toDegrees(encoder.getPosition()));
|
||||||
@@ -75,6 +97,32 @@ public class Hood extends SubsystemBase {
|
|||||||
Logger.recordOutput("Hood/VoltageOut", motor.getAppliedOutput()*motor.getBusVoltage());
|
Logger.recordOutput("Hood/VoltageOut", motor.getAppliedOutput()*motor.getBusVoltage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Command trackToAnglePoseBased(Drivetrain drivetrain, Shooter shooter) {
|
||||||
|
return trackToAngle(() -> {
|
||||||
|
Pose2d drivetrainPose = drivetrain.getPose();
|
||||||
|
Pose2d hubPose = Utilities.getHubPose();
|
||||||
|
|
||||||
|
double distance = drivetrainPose.getTranslation()
|
||||||
|
.getDistance(hubPose.getTranslation());
|
||||||
|
|
||||||
|
Logger.recordOutput("Hood/DistanceToHub", distance);
|
||||||
|
|
||||||
|
Optional<ShooterSpeeds> currentSpeeds = shooter.getTargetSpeeds();
|
||||||
|
|
||||||
|
if(currentSpeeds.isPresent()) {
|
||||||
|
InterpolatingDoubleTreeMap map = HoodConstants.kHoodInterpolators.get(currentSpeeds.get());
|
||||||
|
|
||||||
|
if(map != null) {
|
||||||
|
return MathUtil.clamp(map.get(distance), 0, 40);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public Command trackToAngle(DoubleSupplier degreeAngleSupplier) {
|
public Command trackToAngle(DoubleSupplier degreeAngleSupplier) {
|
||||||
return run(() -> {
|
return run(() -> {
|
||||||
currentTargetDegrees = degreeAngleSupplier.getAsDouble();
|
currentTargetDegrees = degreeAngleSupplier.getAsDouble();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import com.revrobotics.spark.SparkBase.ControlType;
|
|||||||
import com.revrobotics.spark.SparkLowLevel.MotorType;
|
import com.revrobotics.spark.SparkLowLevel.MotorType;
|
||||||
|
|
||||||
import edu.wpi.first.wpilibj2.command.Command;
|
import edu.wpi.first.wpilibj2.command.Command;
|
||||||
|
import edu.wpi.first.wpilibj2.command.Commands;
|
||||||
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
||||||
import frc.robot.constants.IntakePivotConstants;
|
import frc.robot.constants.IntakePivotConstants;
|
||||||
import frc.robot.constants.IntakePivotConstants.IntakePivotPosition;
|
import frc.robot.constants.IntakePivotConstants.IntakePivotPosition;
|
||||||
@@ -80,12 +81,31 @@ public class IntakePivot extends SubsystemBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// public Command jimmy(){
|
/**
|
||||||
// return run(() -> {
|
* Repeatedly moves the intake up and down. AKA "Jimmying" the intake
|
||||||
// leftMotor.set(0.5 * IntakePivotConstants.kMaxManualSpeedMultiplier);
|
*
|
||||||
// rightMotor.set(0.5 * IntakePivotConstants.kMaxManualSpeedMultiplier);
|
* @param time How long the intake will go both ways for (seconds)
|
||||||
// })
|
* @return Command that repeatedly Jimmys the intake
|
||||||
// }
|
*/
|
||||||
|
public Command jimmy(double time){
|
||||||
|
return Commands.repeatingSequence(
|
||||||
|
manualSpeed(() -> -0.75).withTimeout(time),
|
||||||
|
manualSpeed(() -> 0.75).withTimeout(time)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repeatedly moves the intake up and down. AKA "Jimmying" the intake
|
||||||
|
*
|
||||||
|
* @param time How long the intake will go both ways for (seconds)
|
||||||
|
* @return Command that repeatedly Jimmys the intake
|
||||||
|
*/
|
||||||
|
public Command jimmy(DoubleSupplier time) {
|
||||||
|
return Commands.repeatingSequence(
|
||||||
|
manualSpeed(() -> -0.75).withTimeout(time.getAsDouble()),
|
||||||
|
manualSpeed(() -> 0.75).withTimeout(time.getAsDouble())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public Command stop() {
|
public Command stop() {
|
||||||
return manualSpeed(() -> 0);
|
return manualSpeed(() -> 0);
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ public class IntakeRoller extends SubsystemBase {
|
|||||||
|
|
||||||
public Command runIn() {
|
public Command runIn() {
|
||||||
return run(() -> {
|
return run(() -> {
|
||||||
leftMotor.set(IntakeRollerConstants.kSpeed*0.8);
|
leftMotor.set(IntakeRollerConstants.kSpeed*0.9);
|
||||||
rightMotor.set(IntakeRollerConstants.kSpeed*0.8);
|
rightMotor.set(IntakeRollerConstants.kSpeed*0.9);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.photonvision.PhotonPoseEstimator.PoseStrategy;
|
|||||||
import org.photonvision.targeting.PhotonPipelineResult;
|
import org.photonvision.targeting.PhotonPipelineResult;
|
||||||
import org.photonvision.targeting.PhotonTrackedTarget;
|
import org.photonvision.targeting.PhotonTrackedTarget;
|
||||||
|
|
||||||
|
import edu.wpi.first.math.geometry.Pose2d;
|
||||||
import edu.wpi.first.math.geometry.Pose3d;
|
import edu.wpi.first.math.geometry.Pose3d;
|
||||||
import edu.wpi.first.math.geometry.Transform3d;
|
import edu.wpi.first.math.geometry.Transform3d;
|
||||||
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ import com.revrobotics.AbsoluteEncoder;
|
|||||||
import com.revrobotics.PersistMode;
|
import com.revrobotics.PersistMode;
|
||||||
import com.revrobotics.RelativeEncoder;
|
import com.revrobotics.RelativeEncoder;
|
||||||
import com.revrobotics.ResetMode;
|
import com.revrobotics.ResetMode;
|
||||||
|
import com.revrobotics.spark.ClosedLoopSlot;
|
||||||
import com.revrobotics.spark.SparkClosedLoopController;
|
import com.revrobotics.spark.SparkClosedLoopController;
|
||||||
import com.revrobotics.spark.SparkMax;
|
import com.revrobotics.spark.SparkMax;
|
||||||
import com.revrobotics.spark.SparkBase.ControlType;
|
import com.revrobotics.spark.SparkBase.ControlType;
|
||||||
import com.revrobotics.spark.SparkLowLevel.MotorType;
|
import com.revrobotics.spark.SparkLowLevel.MotorType;
|
||||||
|
|
||||||
|
import edu.wpi.first.math.controller.SimpleMotorFeedforward;
|
||||||
|
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||||
import edu.wpi.first.wpilibj2.command.Command;
|
import edu.wpi.first.wpilibj2.command.Command;
|
||||||
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
||||||
import frc.robot.constants.ShooterConstants;
|
import frc.robot.constants.ShooterConstants;
|
||||||
@@ -32,6 +35,8 @@ public class Shooter extends SubsystemBase {
|
|||||||
private SparkClosedLoopController rightClosedLoopController;
|
private SparkClosedLoopController rightClosedLoopController;
|
||||||
|
|
||||||
private ShooterSpeeds targetSpeeds;
|
private ShooterSpeeds targetSpeeds;
|
||||||
|
private SimpleMotorFeedforward shooterFFLeft;
|
||||||
|
private SimpleMotorFeedforward shooterFFRight;
|
||||||
|
|
||||||
public Shooter() {
|
public Shooter() {
|
||||||
leftMotor = new SparkMax(ShooterConstants.kLeftShooterMotorCANID, MotorType.kBrushless);
|
leftMotor = new SparkMax(ShooterConstants.kLeftShooterMotorCANID, MotorType.kBrushless);
|
||||||
@@ -59,10 +64,37 @@ public class Shooter extends SubsystemBase {
|
|||||||
targetSpeeds = null;
|
targetSpeeds = null;
|
||||||
|
|
||||||
rightRelative = rightMotor.getEncoder();
|
rightRelative = rightMotor.getEncoder();
|
||||||
|
|
||||||
|
shooterFFLeft = new SimpleMotorFeedforward(ShooterConstants.kLeftS, ShooterConstants.kLeftV, ShooterConstants.kLeftA);
|
||||||
|
shooterFFRight = new SimpleMotorFeedforward(ShooterConstants.kRightS, ShooterConstants.kRightV, ShooterConstants.kRightA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void periodic() {
|
public void periodic() {
|
||||||
|
SmartDashboard.putNumber(
|
||||||
|
"ShooterTargetRPM",
|
||||||
|
targetSpeeds == null ? 0 : targetSpeeds.getSpeedRPM());
|
||||||
|
|
||||||
|
SmartDashboard.putNumber(
|
||||||
|
"ShooterLeftSideRPM",
|
||||||
|
leftEncoder.getVelocity()
|
||||||
|
);
|
||||||
|
|
||||||
|
SmartDashboard.putNumber(
|
||||||
|
"ShooterRightSideRPM",
|
||||||
|
rightEncoder.getVelocity()
|
||||||
|
);
|
||||||
|
|
||||||
|
SmartDashboard.putBoolean(
|
||||||
|
"ShooterLeftSideAtSetpoint",
|
||||||
|
leftClosedLoopController.isAtSetpoint()
|
||||||
|
);
|
||||||
|
|
||||||
|
SmartDashboard.putBoolean(
|
||||||
|
"ShooterRightSideAtSetpoint",
|
||||||
|
rightClosedLoopController.isAtSetpoint()
|
||||||
|
);
|
||||||
|
|
||||||
Logger.recordOutput(
|
Logger.recordOutput(
|
||||||
"Shooter/TargetRPM",
|
"Shooter/TargetRPM",
|
||||||
targetSpeeds == null ? 0 : targetSpeeds.getSpeedRPM()
|
targetSpeeds == null ? 0 : targetSpeeds.getSpeedRPM()
|
||||||
@@ -73,6 +105,8 @@ public class Shooter extends SubsystemBase {
|
|||||||
|
|
||||||
Logger.recordOutput("Shooter/RightRollers/rightmotor", rightRelative.getVelocity());
|
Logger.recordOutput("Shooter/RightRollers/rightmotor", rightRelative.getVelocity());
|
||||||
|
|
||||||
|
Logger.recordOutput("Shooter/LeftRollers/OutputVoltage", leftMotor.getAppliedOutput() * leftMotor.getBusVoltage());
|
||||||
|
Logger.recordOutput("Shooter/RightRollers/OutputVoltage", rightMotor.getAppliedOutput() * rightMotor.getBusVoltage());
|
||||||
|
|
||||||
// TODO How does the SparkMAX controller determine "at setpoint"? Is there any tolerance?
|
// TODO How does the SparkMAX controller determine "at setpoint"? Is there any tolerance?
|
||||||
Logger.recordOutput("Shooter/LeftRollers/AtSetpoint", leftClosedLoopController.isAtSetpoint());
|
Logger.recordOutput("Shooter/LeftRollers/AtSetpoint", leftClosedLoopController.isAtSetpoint());
|
||||||
@@ -89,12 +123,16 @@ public class Shooter extends SubsystemBase {
|
|||||||
} else {
|
} else {
|
||||||
leftClosedLoopController.setSetpoint(
|
leftClosedLoopController.setSetpoint(
|
||||||
targetSpeeds.getSpeedRPM(),
|
targetSpeeds.getSpeedRPM(),
|
||||||
ControlType.kVelocity
|
ControlType.kVelocity,
|
||||||
|
ClosedLoopSlot.kSlot0,
|
||||||
|
shooterFFLeft.calculate(targetSpeeds.getSpeedRPM())
|
||||||
);
|
);
|
||||||
|
|
||||||
rightClosedLoopController.setSetpoint(
|
rightClosedLoopController.setSetpoint(
|
||||||
targetSpeeds.getSpeedRPM(),
|
targetSpeeds.getSpeedRPM(),
|
||||||
ControlType.kVelocity
|
ControlType.kVelocity,
|
||||||
|
ClosedLoopSlot.kSlot0,
|
||||||
|
shooterFFRight.calculate(targetSpeeds.getSpeedRPM())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package frc.robot.subsystems;
|
package frc.robot.subsystems;
|
||||||
|
|
||||||
|
import java.util.function.DoubleSupplier;
|
||||||
|
|
||||||
import com.ctre.phoenix6.controls.DutyCycleOut;
|
import com.ctre.phoenix6.controls.DutyCycleOut;
|
||||||
import com.ctre.phoenix6.hardware.TalonFX;
|
import com.ctre.phoenix6.hardware.TalonFX;
|
||||||
import com.revrobotics.PersistMode;
|
import com.revrobotics.PersistMode;
|
||||||
@@ -44,6 +46,22 @@ public class Spindexer extends SubsystemBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Command spinToShooter(DoubleSupplier shooterSpeedRPM, double cutOffRPM) {
|
||||||
|
return run(() -> {
|
||||||
|
if(shooterSpeedRPM.getAsDouble() < cutOffRPM) {
|
||||||
|
spindexerMotor.setControl(
|
||||||
|
spindexerMotorOutput.withOutput(0)
|
||||||
|
);
|
||||||
|
feederMotor.set(0);
|
||||||
|
} else {
|
||||||
|
spindexerMotor.setControl(
|
||||||
|
spindexerMotorOutput.withOutput(SpindexerConstants.kSpindexerSpeed)
|
||||||
|
);
|
||||||
|
feederMotor.set(SpindexerConstants.kFeederSpeed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public Command spinToIntake() {
|
public Command spinToIntake() {
|
||||||
return run(() -> {
|
return run(() -> {
|
||||||
spindexerMotor.setControl(
|
spindexerMotor.setControl(
|
||||||
|
|||||||
Reference in New Issue
Block a user