Cyclone / Code

Code

WPILib 2027 vendor library — every command the motor accepts from robot code.

NOTE:

The vendor library is under active development. Method names on this page can change. Java only. C++ and Python TBD.

Install

Put SwyftCycloneV4.json in the robot project’s vendordeps/ folder and rebuild. Year token: 2027.

Class: com.swyftrobotics.cyclone.v4.SwyftCyclone. Construct with the CAN ID you assigned in SWYFT Link (1–62). Invert is set in SWYFT Link, not in this API.

Java
import com.swyftrobotics.cyclone.v4.SwyftCyclone;

public class Intake {
    private final SwyftCyclone motor = new SwyftCyclone(5);
}

A second constructor takes a SystemCore CAN bus id. Default is CAN_S0.

Output

Four motion commands. Sign is direction. Call the command every loop (teleopPeriodic / execute). A setpoint older than 100 ms coasts. Do not send it once from initialize or from a background timer.

MethodUnitsUse
setDutyCycle(d) / set(d)−1…1, fraction of busOpen-loop bring-up. Same quantity, two names.
setCurrent(a)amperes, signedTorque mode. Bounded by the stator limit.
setVelocity(rpm)mechanical RPM, signedClosed-loop speed.
setPosition(rad)rotor radians, signed, multi-turnClosed-loop position. Long way around. Relative to power-on, not absolute.
WARNING:

setDutyCycle is bring-up. The stator limit does not govern this mode. Use setCurrent or setVelocity for a mechanism that can stall. 0.5 is half bus, not half free speed. 50 clamps to full output.

Java
@Override
public void teleopPeriodic() {
    motor.setDutyCycle(stick.getY());   // every loop
    // motor.setCurrent(20);            // A, signed
    // motor.setVelocity(2000);         // RPM
    // motor.setPosition(Math.PI);      // rotor rad
}

setPosition is rotor-side. The device has no gear ratio. Apply SensorToMechanismRatio on the host — see Mechanism units.

Stop, e-stop, faults

MethodWhat it does
disable()Coast this command path and drop the setpoint.
estop()Latching kill. Coasts. Refuses re-arm until releaseEstop().
releaseEstop()Clears the e-stop latch. Then clearFaults() if needed.
clearFaults()Request. Refused while the cause is still present, and while e-stop is latched. Re-read hasHardFault().
Java
@Override
public void disabledInit() {
    motor.disable();
}

public void panic() {
    motor.estop();
}

public void pitClear() {
    motor.releaseEstop();
    motor.clearFaults();
    if (motor.hasHardFault()) {
        // cause still present — read SWYFT Link
    }
}

E-stop coasts. Do not test it on a motor holding a load in the air. Faults

Current limits

Apply from robotInit(), not from periodic. apply blocks. Set only stator and supply. Starting points and the unsupported fields: Current limits

Java
import com.swyftrobotics.cyclone.v4.CurrentLimitsConfigs;

@Override
public void robotInit() {
    var cfg = new CurrentLimitsConfigs();
    cfg.StatorCurrentLimit = 20;   // A
    cfg.SupplyCurrentLimit = 20;   // A
    motor.getConfigurator().apply(cfg);
}
WARNING:

SupplyCurrentLowerLimit and SupplyCurrentLowerTime throw. If that throw leaves robotInit(), the Driver Station reports no robot code.

Neutral mode

V4 coasts when uncommanded. setNeutralMode(NeutralMode.COAST) succeeds. BRAKE throws — there is no brake path. isBrakeModeSupported() is false. Design the mechanism for coast (holding current, or a mechanical brake, on an elevator).

Java
motor.setNeutralMode(SwyftCyclone.NeutralMode.COAST);

Mechanism units

Gear ratio is host-side. The device never stores it. Set it every boot with configureMechanism — not through the configurator. Then use setMechanismPosition / getMechanismPosition in rotations of the mechanism. Call the position command every loop.

Java
import com.swyftrobotics.cyclone.v4.MechanismConfigs;

@Override
public void robotInit() {
    var mech = new MechanismConfigs();
    mech.SensorToMechanismRatio = 12.8;  // rotor turns per mechanism turn
    mech.ContinuousWrap = true;          // shortest path (azimuth)
    motor.configureMechanism(mech);
}

@Override
public void teleopPeriodic() {
    motor.setMechanismPosition(0.25);    // mechanism rotations
}

Position is relative to power-on. After a brownout, re-zero against a known reference. hasLikelyRebooted() flags that.

Follow

A follower copies the leader’s applied output (after the leader’s current limit), not the leader’s request. The leader is not told. Follow is a command, not flash — a battery swap or brownout on that motor clears it. Put it in robotInit() so the pair comes back every boot. If only that motor reboots and the RIO stays up, robotInit() does not run; re-issue when hasLikelyRebooted() is true. Disable, fault, and e-stop do not cancel follow; the pair resumes when the follower re-arms. Any other motion command on the follower cancels it.

Java
import com.swyftrobotics.cyclone.v4.Follower;
import com.swyftrobotics.cyclone.v4.MotorAlignmentValue;

@Override
public void robotInit() {
    left.setControl(new Follower(right.getDeviceID(), MotorAlignmentValue.Opposed));
}

@Override
public void teleopPeriodic() {
    if (left.hasLikelyRebooted()) {
        left.setControl(new Follower(right.getDeviceID(), MotorAlignmentValue.Opposed));
        left.clearRebootFlag();
    }
}
// left.stopFollowing();

Do not follow a follower. A follower still obeys its own enable gate, faults, and current limits. If the leader disappears, the follower coasts on the 100 ms deadman. Do not also setDutyCycle on the follower in a default command — that cancels follow on the first tick.

Telemetry

getLatest() is non-blocking. The returned object is reused — copy fields you need across loops. isAlive(0.1) is false if no motion frame has arrived in 100 ms; an unplugged controller otherwise looks like a stationary one.

Java
SwyftCycloneData d = motor.getLatest();
if (!motor.isAlive(0.1)) {
    return;   // no CAN frames
}
double rpm    = d.velocityRpm;
double amps   = d.supplyCurrentAmps;   // bus; regen reads ~0
double volts  = d.busVoltage;
double tempC  = d.temperatureC;
boolean fault = d.hasHardFault();
String faults = d.faultString();

There is no phase-current field. Use supplyCurrentAmps. d.mode is the law the ISR actually ran, not the command you sent.

LEDs

User lights 1–5, left to right, arc at the top. Status lights cannot be set. Status lights

Java
import com.swyftrobotics.cyclone.v4.LedAnimation;

motor.setLEDs(0, 120, 255);                          // all five
motor.setLED(3, 255, 0, 0);                          // center
motor.setLEDs(255, 40, 0, LedAnimation.ChaseForward);
motor.clearLEDs();                                   // back to status

Channels 0–255. Black on all five returns control to the controller; that is not off — use clearLEDs(). Rainbow ignores hue but must not be passed black. Colour persists until power loss; set team colour in robotInit().

Identify and calibrate

MethodWhat it does
identify()White flash ~2.5 s on the status lights.
calibrate() / calibrate(amps)Spins the shaft. Robot must be enabled. Dropped if sent while disabled, not queued.
saveConfiguration()Persist device config across power loss. Does not persist follow or mechanism ratio.
WARNING:

Calibrate spins the shaft. Area clear, robot enabled. Do not call it from robotInit().