Skip to content

Commit 1cfc07d

Browse files
committed
add documentation for control, hardware, and robot modules
1 parent 2db45f2 commit 1cfc07d

3 files changed

Lines changed: 188 additions & 3 deletions

File tree

src/content/docs/control/index.mdx

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,144 @@ title: Control Module
33
description: PID, feedforward, geometry, and motion profiling.
44
---
55

6-
Content coming soon.
6+
import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'
7+
8+
The `control` module is a WPILib-style control theory library: feedback controllers, feedforward models,
9+
signal filters, motion profiling, typed 2D geometry, and a type-safe units system. It has no dependency on
10+
the FTC SDK, so it can be used entirely on its own, even outside of a robot project.
11+
12+
## PID control
13+
14+
`PIDController` implements a standard PID loop, with optional continuous input for wrapping angles.
15+
16+
<Tabs syncKey="language">
17+
<TabItem label="Kotlin">
18+
```kotlin
19+
val pid = PIDController(PIDCoefficients(kP = 0.01, kI = 0.0, kD = 0.001))
20+
21+
val output = pid.calculate(error = setpoint - currentPosition)
22+
```
23+
</TabItem>
24+
<TabItem label="Java">
25+
```java
26+
PIDController pid = new PIDController(new PIDCoefficients(0.01, 0.0, 0.001));
27+
28+
double output = pid.calculate(setpoint - currentPosition);
29+
```
30+
</TabItem>
31+
</Tabs>
32+
33+
## Feedforward
34+
35+
`SimpleFeedforward` models a mechanism with static friction, velocity, and acceleration terms.
36+
`ElevatorFeedforward` and `ArmFeedforward` add a gravity term for mechanisms that fight gravity.
37+
38+
<Tabs syncKey="language">
39+
<TabItem label="Kotlin">
40+
```kotlin
41+
val feedforward = ArmFeedforward(GravityFeedforwardParameters(kG = 0.3, kV = 0.01))
42+
43+
val output = feedforward.calculate(position = armAngle, velocity = targetVelocity)
44+
```
45+
</TabItem>
46+
<TabItem label="Java">
47+
```java
48+
ArmFeedforward feedforward = new ArmFeedforward(new GravityFeedforwardParameters(0.3, 0.0, 0.01, 0.0));
49+
50+
double output = feedforward.calculate(armAngle, targetVelocity, 0.0);
51+
```
52+
</TabItem>
53+
</Tabs>
54+
55+
## Geometry
56+
57+
`Pose2d`, `Vector2d`, and `Rotation2d` model robot position and orientation, adapted from RoadRunner and
58+
WPILib. They support the full range of operators you'd expect: adding a `Twist2d` to a `Pose2d`, composing
59+
rotations, taking the relative transform between two poses, and more.
60+
61+
<Tabs syncKey="language">
62+
<TabItem label="Kotlin">
63+
```kotlin
64+
val pose = Pose2d(x = 12.0, y = 24.0, heading = 90.0.degrees)
65+
val relative = otherPose.relativeTo(pose)
66+
```
67+
</TabItem>
68+
<TabItem label="Java">
69+
```java
70+
Pose2d pose = new Pose2d(12.0, 24.0, Units.Degrees.of(90.0));
71+
Transform2d relative = otherPose.relativeTo(pose);
72+
```
73+
</TabItem>
74+
</Tabs>
75+
76+
## Motion profiling
77+
78+
`TrapezoidProfile` generates a smooth acceleration/cruise/deceleration profile between two `MotionState`s,
79+
respecting maximum velocity and acceleration constraints.
80+
81+
<Tabs syncKey="language">
82+
<TabItem label="Kotlin">
83+
```kotlin
84+
val profile = TrapezoidProfile(TrapezoidProfileConstraints.linear(maxVelocity = 30.0, maxAcceleration = 60.0))
85+
86+
val state = profile.calculate(current = currentState, goal = goalState)
87+
```
88+
</TabItem>
89+
<TabItem label="Java">
90+
```java
91+
TrapezoidProfile profile = new TrapezoidProfile(TrapezoidProfileConstraints.linear(30.0, 60.0));
92+
93+
MotionState state = profile.calculate(currentState, goalState);
94+
```
95+
</TabItem>
96+
</Tabs>
97+
98+
## Drive kinematics
99+
100+
`MecanumKinematics` and `TankKinematics` convert raw driver input (forward, strafe, and rotation) into
101+
per-wheel power for their respective drivetrains.
102+
103+
<Tabs syncKey="language">
104+
<TabItem label="Kotlin">
105+
```kotlin
106+
val kinematics = MecanumKinematics()
107+
val powers = kinematics.calculate(DriveInput(x = gamepad.leftStickX.value, y = -gamepad.leftStickY.value, rx = gamepad.rightStickX.value))
108+
```
109+
</TabItem>
110+
<TabItem label="Java">
111+
```java
112+
MecanumKinematics kinematics = new MecanumKinematics();
113+
MecanumWheelPowers powers = kinematics.calculate(new DriveInput(gamepad.leftStickX().getValue(), -gamepad.leftStickY().getValue(), gamepad.rightStickX().getValue()));
114+
```
115+
</TabItem>
116+
</Tabs>
117+
118+
## Filters
119+
120+
`EMAFilter` and `SlewRateLimiter` smooth out noisy or jumpy signals, `Debouncer` filters chattery boolean
121+
input, and `KalmanFilter` fuses multiple noisy measurements into a single best estimate of state.
122+
123+
## Units
124+
125+
Every measurement in the `control` module is typed, using extension properties instead of bare doubles:
126+
127+
<Tabs syncKey="language">
128+
<TabItem label="Kotlin">
129+
```kotlin
130+
val distance = 5.0.meters
131+
val speed = distance / 2.0.seconds // a LinearVelocity, not a raw Double
132+
```
133+
</TabItem>
134+
<TabItem label="Java">
135+
```java
136+
Distance distance = Units.Meters.of(5.0);
137+
LinearVelocity speed = distance.div(Units.Seconds.of(2.0)); // a LinearVelocity, not a raw double
138+
```
139+
</TabItem>
140+
</Tabs>
141+
142+
<Aside type="tip">
143+
Dividing or multiplying two measures always produces a typed result: dividing a `Distance` by a
144+
`Time` gives you a genuine `LinearVelocity`, not a bare number, so unit mistakes get caught by the
145+
compiler instead of on the field.
146+
</Aside>

src/content/docs/hardware/index.mdx

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,42 @@ title: Hardware Module
33
description: Typed, lazy-initialized wrappers around FTC SDK hardware.
44
---
55

6-
Content coming soon.
6+
import { Tabs, TabItem, CardGrid, LinkCard } from '@astrojs/starlight/components'
7+
8+
The `hardware` module wraps the raw FTC SDK hardware classes (`DcMotorEx`, `Servo`, `IMU`, and so on) in
9+
classes that lazily resolve devices from the hardware map on first use, and give you a more convenient,
10+
consistent API across every device type.
11+
12+
## Creating hardware
13+
14+
Every device wrapper in this module can be constructed the same two ways: by its Lynx Module and port,
15+
or by its configuration name from the Driver Station.
16+
17+
<Tabs syncKey="language">
18+
<TabItem label="Kotlin">
19+
```kotlin
20+
val servo = NextServo(RobotController.controlHub, 0) // By Lynx Module and port, recommended
21+
22+
val servo = NextServo("armServo") // Using your configuration name
23+
```
24+
</TabItem>
25+
<TabItem label="Java">
26+
```java
27+
NextServo servo = new NextServo(RobotController.getControlHub(), 0); // By Lynx Module and port, recommended
28+
29+
NextServo servo = new NextServo("armServo"); // Using your configuration name
30+
```
31+
</TabItem>
32+
</Tabs>
33+
34+
Constructing by Lynx Module and port is recommended, since it skips the hardware map's name lookup and
35+
lets NextFTC talk to the module directly. Either way, the underlying device isn't actually resolved until
36+
you first use it, so it's always safe to declare hardware as fields on your `Mechanism`.
37+
38+
## What's in this module
39+
40+
<CardGrid>
41+
<LinkCard title="Actuators" href="/hardware/actuators/servos/" description="Servos, continuous-rotation servos, and feedback servos." />
42+
<LinkCard title="Sensors" href="/hardware/sensors/imu/" description="IMUs, Pinpoints, color/distance/digital sensors, and analog inputs." />
43+
<LinkCard title="Miscellaneous" href="/hardware/miscellaneous/limelights/" description="Limelights, HuskyLens, and RGB indicators." />
44+
</CardGrid>

src/content/docs/robot/index.mdx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,11 @@ title: Robot Module
33
description: NextRobot, OpModes, Mechanisms, Triggers, and the rest of the robot module.
44
---
55

6-
Content coming soon.
6+
The `robot` module is where everything comes together: your robot, your subsystems, your OpModes, and your
7+
gamepad bindings. It builds on top of `hardware` and `control`, and provides the command-based scheduling
8+
layer (via [PedroPathing Ivy](https://pedropathing.com/)) that ties them all to your gamepad.
9+
10+
- **`NextRobot`**: the root of your robot, auto-discovered and instantiated for you.
11+
- **`Mechanism`**: a subsystem, like an arm or a claw, that exposes its behavior as commands.
12+
- **`NextOpMode`**: the base class for your OpModes, paired with the `@NextTeleop`/`@NextAutonomous` annotations.
13+
- **`Trigger`, `RangeTrigger`, and `CommandGamepad`**: bind gamepad input directly to commands.

0 commit comments

Comments
 (0)