From 2acd1158d2a9058d982a6b71e19ecd7f41be4e0e Mon Sep 17 00:00:00 2001 From: Tim Winters Date: Mon, 15 Jun 2026 21:58:51 -0400 Subject: [PATCH 1/5] Add motor control docs --- public/misc/loop_block.png | Bin 0 -> 30496 bytes src/content/docs/misc/motor_control.mdx | 99 ++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 public/misc/loop_block.png create mode 100644 src/content/docs/misc/motor_control.mdx diff --git a/public/misc/loop_block.png b/public/misc/loop_block.png new file mode 100644 index 0000000000000000000000000000000000000000..ddaf14c6993980aa3055b5c22aeb15610ba18f0a GIT binary patch literal 30496 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 literal 0 HcmV?d00001 diff --git a/src/content/docs/misc/motor_control.mdx b/src/content/docs/misc/motor_control.mdx new file mode 100644 index 0000000..5cf7eb1 --- /dev/null +++ b/src/content/docs/misc/motor_control.mdx @@ -0,0 +1,99 @@ +# Controlling mechanisms with motors + +With the introduction of the brushless era of motors in FRC, motors have become the dominant choice, compared to servos or pneumatics, when it comes to controlling robot degrees of freedom.become +Brushless motors have incredible size to performance ratios, and the smart motor controllers that accompany them make it easy to control a variety of mechanisms. +This section will cover the most common control modes seen on FRC robots: position control, velocity control, and open-loop control. + +## Open- and Closed-loop mechanisms + +The manner in which you control a mechanical mechanism can be split into two categories: open-loop, and closed-loop. +Open-loop refers to a mechanism that uses no measurement to correct the output of the motor. +Closed-loop mechanisms use measurements, such as an encoder reading, to adjust the output of a motor to get closer to a target setpoint. + +Closed-loop control is fundamental to creating fast and accurate mechansims, but requires more effort to get working properly. +Open-loop control is easy, but may lack the precision that closed-loop offers. + +Open- and closed-loop refers to the shape of the mechanism when diagrammed out. +See this image from the [WPILib Docs](https://docs.wpilib.org/en/stable/docs/software/advanced-controls/introduction/control-system-basics.html#block-diagrams): +![Closed Loop Block Diagram](/misc/loop_block.png). + +When there is no feedback, the diagram forms a straight line from input to output. +With feedback, the feedback _closes the loop_, hence closed-loop control. + +A key similarity between open- and closed-loop control is that both schemes utilize setpoints. +An open-loop controller will simply not measure the mechanisms current state and make adjustments. +While it is necessary for closed-loop mechanisms to use real-world units such as degrees for an arm, or inches for an elevator, an open-loop mechanism may use motor control units, such as voltage or duty-cycle, as its setpoint. + +Open-loop control does not inherently mean unpredictable, or uncontrolled. +Using mathematical models of your mechanism, it is possible to create a controlled output _profile_ that your mechanism can follow in order to reach its setpoint. +However, because an open-loop controller lacks any feedback, it will not adjust for an error, and is unlikely to reach the target setpoint exactly. + +## Open Loop Control + +Some mechanisms don't require the precision that is gained through closed-loop control. +Intake rollers, for example, are commonly controlled simply by running the motor at a set duty-cycle. +Even if the battery voltage is a little higher or lower from one point in time to the next, the effect on robot performance may be negligible. + +The simplest open-loop mechanisms require almost no configuration in code, since you don't need to configure gear ratios or feedback gains. + +The two most common open-loop setpoint types are duty-cycle and voltage. + +Duty-cycle is a percentage of input voltage coming from the robot's battery. +If the battery voltage is 11.8 volts, and you request a 50% duty cycle, the motor will run at 5.9 volts + +Voltage control is very similar to duty cycle, but the motor controller will automatically adjust the duty cycle based on incoming voltage. +If the battery voltage is 12.2 volts, and you request a voltage of 6 volts, the motor will output a duty-cycle of 49.2%. +If the battery voltage dips to 11.8, the duty-cycle will increase to 50.8%. + +Voltage control is recommended over duty-cycle for open loop control because of its repeatability. +When using voltage control, it is also recommended to not exceed a setpoint of 10 volts to account for voltage sag as your battery is used up throughout the match. +Voltage control can accomodate voltages _higher_ than the setpoint by reducing the duty cycle, but if the input voltage is below the setpoint, the motor controller cannot overcome the deficit. + +### Open Loop Velocity + +While open-loop position control does not work well in FRC, open-loop velocity control is very practical due to the nature of motors. +Many teams will choose to run flywheels for shooters using open-loop control, since there is a direct relationship between motor voltage and motor speed, referred to as the velocity constant _kV_. +This relationship can be found theoretically using key characteristics of the motor, or empirically by taking velocity measurements at different voltages to calculate _kV_. +See the [WPILib Docs](https://docs.wpilib.org/en/stable/docs/software/advanced-controls/introduction/introduction-to-feedforward.html#introduction-to-dc-motor-feedforward) page on DC Motor Feedforward for more info about kV. + +If you don't want to calculate kV, you can use voltage directly as your setpoint. + +It is common practice to use open-loop velocity control on swere drivetrains too, where precise velocity is not as important. +The human driver acts like a closed-loop controller, using measurements taken of robot position and speed in order to adjust its movement. + +## Closed-Loop Control + +### Closed-Loop Position Control + +Position control is the most common closed-loop control scheme in FRC. +Mechanisms that use position control include elevators, pivoting arm, slap-down intakes, climbers, and every swerve drivetrain contains four position-controlled modules. + +#### Measuring your mechanism + +The feedback sensor in position-controlled mechanisms is commonly an encoder, a small electronic device that can measure rotation. +Another option is a potentiometer, which is similar to an encoder, but analog, and may have limited travel distance. +Brushless motors all contain internal encoders, so these are a popular choice for teams. +They require no extra work to incorporate into a mechanisms design, and are guaranteed to be functioning as long as the motor is. +The downside of these internal encoders is they reset to a position of _0_ when the motor turns on, regardless of the mechansims physical location. +To counteract this, you either need to perform a homing sequence that moves your mechanism in a controlled manner to a fixed location, then reset the encoder reading to match, or to always power on the robot with the mechanisms in a known spot, such as a physical hardstop. +Using a hardstop location at power-on is recommended for its simplicity, and because you always power the robot on when it is on the field at competition, you will be able to position the mechanisms correctly before doing so. + +An alternative to a motors internal encoder is an external encoder. +External encoders can be mounted to an axle that rotates as the mechanism moves. +By attaching the encoder to the final shaft of a rotating mechanism, such as an arm, you can treat the encoder reading as _absolute_, requiring no homing sequence or specific power-on location. + + +### Closed-Loop Velocity Control + +Closed-loop velocity control relies heavily on the open-loop control discussed above, but with similar incorporation of feedback gains to account for disturbances. +An example of disturbance that you may need to account for is a game piece slowing down your shooter's flywheel. +In years when you have to shoot multiple game pieces one after another, like in 2026 Rebuilt, closed-loop control can help your flywheel recover between shots in a way that open-loop alone cannot. + + +## Choosing a control scheme + +Choosing a control scheme for a mechanism should feel straightforward. +If you need a mechanism to move to a precise position and stay there, closed-loop position is the only option. +If you need a mechanism to move at a specific speed, start with open-loop velocity control. +If you find that the mechanism still doesn't perform as well as you'd like, consider if adding feedback would improve performance. +Instead, if you only need a mechanism to move at rough speeds, open loop control is a simple way to achieve motion. \ No newline at end of file From f6ae1ae8c49190ae57983a1a2e88dc8d4b92c88c Mon Sep 17 00:00:00 2001 From: Tim Winters Date: Tue, 16 Jun 2026 09:59:08 -0400 Subject: [PATCH 2/5] Update --- src/content/docs/misc/motor_control.mdx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/content/docs/misc/motor_control.mdx b/src/content/docs/misc/motor_control.mdx index 5cf7eb1..4699317 100644 --- a/src/content/docs/misc/motor_control.mdx +++ b/src/content/docs/misc/motor_control.mdx @@ -38,15 +38,17 @@ The simplest open-loop mechanisms require almost no configuration in code, since The two most common open-loop setpoint types are duty-cycle and voltage. -Duty-cycle is a percentage of input voltage coming from the robot's battery. -If the battery voltage is 11.8 volts, and you request a 50% duty cycle, the motor will run at 5.9 volts +Duty-cycle is a percentage of input voltage coming from the robot's battery to the motor controller. +WPILib refers to this percentage as throttle. +If the battery voltage is 11.8 volts, and you request a 50% duty-cycle, or 50% throttle, the motor controller will output 5.9 volts to the motor. -Voltage control is very similar to duty cycle, but the motor controller will automatically adjust the duty cycle based on incoming voltage. -If the battery voltage is 12.2 volts, and you request a voltage of 6 volts, the motor will output a duty-cycle of 49.2%. -If the battery voltage dips to 11.8, the duty-cycle will increase to 50.8%. +Voltage control allows you to directly control the output going to the motor. +If the battery voltage is 12.2 volts, and you request a voltage of 6 volts, the motor controller will output 6 volts. +Likewise, if the battery voltage dips to 11.8 volts, the motor controller will still output 6 volts Voltage control is recommended over duty-cycle for open loop control because of its repeatability. -When using voltage control, it is also recommended to not exceed a setpoint of 10 volts to account for voltage sag as your battery is used up throughout the match. +The voltage going to the motor does not fluctuate with changes in battery voltage. +When using voltage control, it is recommended to not exceed a setpoint of 10 volts to account for voltage sag as your battery is used up throughout the match. Voltage control can accomodate voltages _higher_ than the setpoint by reducing the duty cycle, but if the input voltage is below the setpoint, the motor controller cannot overcome the deficit. ### Open Loop Velocity @@ -70,8 +72,7 @@ Mechanisms that use position control include elevators, pivoting arm, slap-down #### Measuring your mechanism -The feedback sensor in position-controlled mechanisms is commonly an encoder, a small electronic device that can measure rotation. -Another option is a potentiometer, which is similar to an encoder, but analog, and may have limited travel distance. +The most common feedback sensor in position-controlled mechanism is an encoder, a small electronic device that can measure rotation. Brushless motors all contain internal encoders, so these are a popular choice for teams. They require no extra work to incorporate into a mechanisms design, and are guaranteed to be functioning as long as the motor is. The downside of these internal encoders is they reset to a position of _0_ when the motor turns on, regardless of the mechansims physical location. From edf656ac9d4376eb7b809d715cf8225431d76201 Mon Sep 17 00:00:00 2001 From: Tim Winters Date: Thu, 18 Jun 2026 17:54:35 -0400 Subject: [PATCH 3/5] Improve introductory paragraph --- src/content/docs/misc/motor_control.mdx | 35 ++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/content/docs/misc/motor_control.mdx b/src/content/docs/misc/motor_control.mdx index 4699317..94acbb1 100644 --- a/src/content/docs/misc/motor_control.mdx +++ b/src/content/docs/misc/motor_control.mdx @@ -4,29 +4,34 @@ With the introduction of the brushless era of motors in FRC, motors have become Brushless motors have incredible size to performance ratios, and the smart motor controllers that accompany them make it easy to control a variety of mechanisms. This section will cover the most common control modes seen on FRC robots: position control, velocity control, and open-loop control. -## Open- and Closed-loop mechanisms +## Motor Controllers +Not to be confused with hardware motor controllers like the REV Spark Max or CTRE TalonFX, a software motor controller is a function that converts a setpoint input to a motor output. +In the simplest case, the input _is_ the output, such as when using voltage or throttle (duty-cycle) control. -The manner in which you control a mechanical mechanism can be split into two categories: open-loop, and closed-loop. -Open-loop refers to a mechanism that uses no measurement to correct the output of the motor. -Closed-loop mechanisms use measurements, such as an encoder reading, to adjust the output of a motor to get closer to a target setpoint. +A more complex example would multiply the setpoint, say a flywwhel rpm, by some constant to convert to volts for the motor. + +Understanding and mastering these controllers will help your robots to be fast and accurate, and help you to be succesful in FRC. + +## Open- and Closed-loop Controllers +The types of controllers that you can create can be split into two categories: open-loop, and closed-loop. +Open-loop refers to a mechanism that have only a single input, the setpoint. +Open-loop controllers will often, but not always, utilize a mathematical model of the motor and mechanism to make an educated estimate of how the motor should act in order to reach the setpoint. +However, they have no way of knowing if the motor is behaving according to the model, so open-loop control is inadequate for most FRC mechanisms. + +Closed-loop mechanisms have an additional input: a measurement of the current state of the mechanism. +A closed-loop controller will combine this measurement and setpoint to determine the output. +Using a measurement from the mechanism is beneficial because it gives your controller insight into how the mechanism is actually behaving. +This _feedback_ from the mechanism can help account for the modle being inaccurate, or disturbances which have caused the mechanism to not act exactly according to the model. Closed-loop control is fundamental to creating fast and accurate mechansims, but requires more effort to get working properly. -Open-loop control is easy, but may lack the precision that closed-loop offers. +Open-loop control is simpler, but may lack the precision that closed-loop offers. -Open- and closed-loop refers to the shape of the mechanism when diagrammed out. +Ther terms open- and closed-loop refers to the shape of the controller when diagrammed out. See this image from the [WPILib Docs](https://docs.wpilib.org/en/stable/docs/software/advanced-controls/introduction/control-system-basics.html#block-diagrams): ![Closed Loop Block Diagram](/misc/loop_block.png). When there is no feedback, the diagram forms a straight line from input to output. -With feedback, the feedback _closes the loop_, hence closed-loop control. - -A key similarity between open- and closed-loop control is that both schemes utilize setpoints. -An open-loop controller will simply not measure the mechanisms current state and make adjustments. -While it is necessary for closed-loop mechanisms to use real-world units such as degrees for an arm, or inches for an elevator, an open-loop mechanism may use motor control units, such as voltage or duty-cycle, as its setpoint. - -Open-loop control does not inherently mean unpredictable, or uncontrolled. -Using mathematical models of your mechanism, it is possible to create a controlled output _profile_ that your mechanism can follow in order to reach its setpoint. -However, because an open-loop controller lacks any feedback, it will not adjust for an error, and is unlikely to reach the target setpoint exactly. +In the closed-loop case, the input -> output -> feedback forms a loop. ## Open Loop Control From 0548f0e31464593bdeefe310c86e89e1ebce586f Mon Sep 17 00:00:00 2001 From: Tim Winters Date: Fri, 19 Jun 2026 11:35:39 -0400 Subject: [PATCH 4/5] More improvements --- src/content/docs/misc/motor_control.mdx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/content/docs/misc/motor_control.mdx b/src/content/docs/misc/motor_control.mdx index 94acbb1..948ba94 100644 --- a/src/content/docs/misc/motor_control.mdx +++ b/src/content/docs/misc/motor_control.mdx @@ -1,8 +1,8 @@ # Controlling mechanisms with motors -With the introduction of the brushless era of motors in FRC, motors have become the dominant choice, compared to servos or pneumatics, when it comes to controlling robot degrees of freedom.become +With the introduction of the brushless era of motors in FRC, motors have become the dominant choicewhen it comes to controlling robot degrees of freedom, compared to servos or pneumatics. Brushless motors have incredible size to performance ratios, and the smart motor controllers that accompany them make it easy to control a variety of mechanisms. -This section will cover the most common control modes seen on FRC robots: position control, velocity control, and open-loop control. +This section will cover the most common types of software controllers for motors in FRC. ## Motor Controllers Not to be confused with hardware motor controllers like the REV Spark Max or CTRE TalonFX, a software motor controller is a function that converts a setpoint input to a motor output. @@ -35,9 +35,10 @@ In the closed-loop case, the input -> output -> feedback forms a loop. ## Open Loop Control -Some mechanisms don't require the precision that is gained through closed-loop control. -Intake rollers, for example, are commonly controlled simply by running the motor at a set duty-cycle. -Even if the battery voltage is a little higher or lower from one point in time to the next, the effect on robot performance may be negligible. +Some mechanisms, like intake rollers, can provide successful performance even without incorporating feedback from the mechanism. +Intake rollers are commonly controlled simply by running the motor at a throttle level, which represents a percentage of the battery voltage. +A 50% throttle, set with `motor.setThrottle(0.5)` will output 50% of the battery voltage to the motor. +Even if the battery voltage is a little higher or lower from one point in time to the next, the effect on intake performance is likely to be negligible, so there is no need to account for it in your controller. The simplest open-loop mechanisms require almost no configuration in code, since you don't need to configure gear ratios or feedback gains. From 189be2826b7c95889b66d6e8c410370d0628279f Mon Sep 17 00:00:00 2001 From: Tim Winters Date: Fri, 19 Jun 2026 11:36:54 -0400 Subject: [PATCH 5/5] Update gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b74e733..d70cb99 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,7 @@ bun.lock # macOS-specific files .DS_Store -.vscode \ No newline at end of file +.vscode + +# IntelliJ +.idea/