Intake Example (Basic)
Template Project
Start with the Timed Robot template project. In VS Code, create a new WPILib project and select "Timed Robot" from the template list. This template provides the basic
Robot.java structure with all lifecycle methods.Overview
This lesson demonstrates building a complete intake mechanism in
Robot.java. We will configure a motor and control it with buttons (A to collect, B to eject).Requirements
The intake must:
- Run forward (collect) on 'A' press.
- Run reverse (eject) on 'B' press.
- Stop when no button is pressed.
- Be configured (Coast mode, Current Limit).
Step 1: Imports and Class Setup
We start by creating the basic structure. Import the necessary classes for robot control, motor hardware, and configuration.
package frc.robot;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.XboxController;
import com.ctre.phoenix6.hardware.TalonFX;
import com.ctre.phoenix6.configs.TalonFXConfiguration;
import com.ctre.phoenix6.signals.InvertedValue;
import com.ctre.phoenix6.signals.NeutralModeValue;
import com.ctre.phoenix6.controls.DutyCycleOut;
public class Robot extends TimedRobot {
// The template provides all lifecycle methods
// We'll add fields here next
}Step 2: Declare Hardware
Create instances for the controller and motor. The controller is on USB port 1, and the motor is on CAN ID 5.
public class Robot extends TimedRobot {
// Controller on USB port 1
private XboxController m_controller = new XboxController(1);
// Intake motor on CAN ID 5
private TalonFX m_motor = new TalonFX(5);
private DutyCycleOut m_out = new DutyCycleOut(0);
}Step 3: Configure Motor in robotInit()
In
robotInit(), we configure the motor. This runs once at startup. We set the inversion direction, idle mode to Coast (allows free spinning when stopped), and enable current limiting to protect the motor from damage.Configure the motor with proper settings:
@Override
public void robotInit() {
// Configure motor settings
TalonFXConfiguration config = new TalonFXConfiguration();
// Set motor direction (adjust if needed for your mechanism)
config.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive;
// Coast mode allows free spinning when stopped (good for intakes)
config.MotorOutput.NeutralMode = NeutralModeValue.Coast;
// Enable current limiting to protect motor (30A limit)
config.CurrentLimits.StatorCurrentLimitEnable = true;
config.CurrentLimits.StatorCurrentLimit = 30.0;
m_motor.getConfigurator().apply(config);
}Step 4: Add Button Control Logic
In
teleopPeriodic(), we read button presses and control the motor. This method runs repeatedly (every 20ms) during teleoperated mode. We check if button A is pressed to collect, button B to eject, or no button to stop.Add logic to read buttons and control the motor:
@Override
public void teleopPeriodic() {
// Button A: Run intake forward (collect)
if (m_controller.getAButton()) {
m_motor.setControl(m_out.withOutput(0.6));
}
// Button B: Run intake reverse (eject)
else if (m_controller.getBButton()) {
m_motor.setControl(m_out.withOutput(-0.4));
}
// No button: Stop motor
else {
m_motor.setControl(m_out.withOutput(0.0));
}
}Understanding the Control Logic
The
if-else if-else structure ensures only one action happens at a time. Button A runs the motor forward at 60% power to collect game pieces. Button B runs reverse at 40% power to eject. The final else ensures the motor stops when no button is pressed.Power Values
The values 0.6 (60%) forward and -0.4 (40%) reverse are starting points. 60% forward is usually enough to grab game pieces. 40% reverse is enough to eject without being too aggressive. Test and adjust these values for your specific mechanism.
Full Code
Complete implementation combining all steps:
package frc.robot;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.XboxController;
import com.ctre.phoenix6.hardware.TalonFX;
import com.ctre.phoenix6.configs.TalonFXConfiguration;
import com.ctre.phoenix6.signals.InvertedValue;
import com.ctre.phoenix6.signals.NeutralModeValue;
import com.ctre.phoenix6.controls.DutyCycleOut;
public class Robot extends TimedRobot {
// Controller on USB port 1
private XboxController m_controller = new XboxController(1);
// Intake motor on CAN ID 5
private TalonFX m_motor = new TalonFX(5);
private DutyCycleOut m_out = new DutyCycleOut(0);
// The template provides robotInit() - add your configuration here
@Override
public void robotInit() {
// Configure motor settings
TalonFXConfiguration config = new TalonFXConfiguration();
// Set motor direction (adjust if needed for your mechanism)
config.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive;
// Coast mode allows free spinning when stopped (good for intakes)
config.MotorOutput.NeutralMode = NeutralModeValue.Coast;
// Enable current limiting to protect motor (30A limit)
config.CurrentLimits.StatorCurrentLimitEnable = true;
config.CurrentLimits.StatorCurrentLimit = 30.0;
m_motor.getConfigurator().apply(config);
}
// The template provides teleopPeriodic() - add your control logic here
@Override
public void teleopPeriodic() {
// Button A: Run intake forward (collect)
if (m_controller.getAButton()) {
m_motor.setControl(m_out.withOutput(0.6));
}
// Button B: Run intake reverse (eject)
else if (m_controller.getBButton()) {
m_motor.setControl(m_out.withOutput(-0.4));
}
// No button: Stop motor
else {
m_motor.setControl(m_out.withOutput(0.0));
}
}
// The template provides other lifecycle methods (autonomousInit, disabledInit, etc.)
// You can leave them empty or add code as needed
}Troubleshooting
Wrong Direction: Change inversion setting in
No Movement: Check CAN IDs and power values.
Motor Drifts: Ensure the
robotInit().No Movement: Check CAN IDs and power values.
Motor Drifts: Ensure the
else { stop } block exists to stop the motor when no button is pressed.