Setup & install
Install the Java library, configure a Cyclone, and command it from your robot program.
Java 0.34.0 adds deduplicated controller stop/refusal messages to robot standard error when telemetry is polled. Existing public control APIs are retained. Rebuild and redeploy robot code after updating the vendor dependency.
Java 0.34.0 / firmware 2.7.8: zero duty coasts; brake is unsupported. Stator and supply current-limit settings are inactive compatibility fields and do not limit amperes. Supply current is observational; stator current is unavailable. The speed-based duty governor can reduce applied output.
Install the vendor library
These examples use Cyclone Java library 0.34.0 and the SystemCore WPILib 2027 API. Check the version in your project’s Cyclone vendordep before using them.
In WPILib, open Manage Vendor Libraries, choose Install new libraries (online), and enter this URL:
https://cyclone.docs.swyftrobotics.com/files/vendor-lib/2027/SwyftCycloneV4.json
You can also open the installer JSON to check its version. It selects 0.34.0 for the SystemCore WPILib 2027 API. Keep one Cyclone library version in the project and build before deploying. Java imports use com.swyftrobotics.cyclone.v4.
A complete first program
This example uses device 1 and the left stick on gamepad port 0, with output limited to 10% duty. After enabling, release the stick before requesting motion. Current-limit settings are inactive on firmware 2.6.6 and are omitted from startup. Keep the mechanism’s travel clear before enabling.
package frc.robot;
import org.wpilib.framework.TimedRobot;
import org.wpilib.driverstation.Gamepad;
import com.swyftrobotics.cyclone.v4.NeutralStartInterlock;
import com.swyftrobotics.cyclone.v4.SwyftCyclone;
public class Robot extends TimedRobot {
private final SwyftCyclone motor = new SwyftCyclone(1);
private final Gamepad pad = new Gamepad(0);
private final NeutralStartInterlock inputStart = new NeutralStartInterlock();
@Override
public void teleopPeriodic() {
double stick = -pad.getLeftY();
if (!inputStart.update(isEnabled(), pad.isConnected(), false, 0.08, stick)) {
motor.disable();
return;
}
motor.setDutyCycle(Math.abs(stick) <= 0.08 ? 0 : stick * 0.10);
}
@Override
public void disabledInit() {
inputStart.reset();
motor.disable();
}
@Override
public void close() {
motor.close();
super.close();
}
}Use a PS5 controller or another gamepad
The motor receives targets from robot code, not joystick positions. In SystemCore WPILib 2027, Gamepad uses the Driver Station mapping for recognized controllers, including PS5. For another joystick, use its GenericHID mapping and normalize each motion input so released is zero.
The complete example above uses NeutralStartInterlock from Java 0.34.0. It starts locked and locks again on disable or controller disconnection. A held stick, trigger or motion button cannot unlock it: the controls must be released during an enabled loop first. Call reset() in disabledInit(), and check the interlock before every motion request.
Pass every individual input that can request motion, including motion buttons. Do not check only the final combined target: two held inputs can cancel each other and appear to be zero. The helper works with any controller mapping; it does not discover your robot's bindings automatically.
import org.wpilib.driverstation.Gamepad;
import org.wpilib.driverstation.RobotState;
import com.swyftrobotics.cyclone.v4.NeutralStartInterlock;
// Create once as fields, not inside periodic:
Gamepad pad = new Gamepad(0);
NeutralStartInterlock inputStart = new NeutralStartInterlock();
// In teleopPeriodic, after successful motor configuration:
double stick = -pad.getLeftY();
double trigger = pad.getRightTriggerAxis();
boolean motionButton = pad.getDpadUpButton();
if (!inputStart.update(RobotState.isEnabled(), pad.isConnected(), motionButton,
0.03, stick, trigger)) {
motor.disable();
return;
}
// Example mapping: the trigger requests forward output and the stick sets direction.
// While ALL controls are released, send zero repeatedly so firmware sees neutral.
double duty = Math.abs(stick) <= 0.03 && trigger <= 0.03 && !motionButton
? 0 : Math.max(-0.10, Math.min(0.10, (trigger + stick) * 0.10));
motor.setDutyCycle(duty);
// In disabledInit: inputStart.reset(); motor.disable();Firmware 1.6.9 also rejects robot motion after a DS disable until it receives a fresh exact-zero duty or velocity command while DS and the commander heartbeat permit output. It does not count commands sent while disabled. Never insert a zero command immediately before every nonzero target to bypass this check. See restart behavior for position, followers and autonomous routines.
Create the motor once
Create one SwyftCyclone object for each motor when your robot program starts. Keep using that object; do not create a new one every time the periodic code runs. The library sends an enable heartbeat, a repeated message confirming that control is active. Your code must also repeat the intended motor command. Call close() when the object will no longer be used.
Before enabling
- Give the device a unique number and verify the CAN bus connection.
- Choose a consistent sign convention and a safe first test.
- Read configuration failures instead of assuming that a write succeeded.
- Keep the DriverStation gate in use. It cannot be disarmed through the public API.