[hal, wpilib] PWM Rewrite (#7845)

The HAL will only contain the output period and the raw microseconds. Higher level things such as SimDevice can handle everything else.
This commit is contained in:
Thad House
2025-03-20 19:23:22 -07:00
committed by GitHub
parent 2e21a41f87
commit e2cc9e0059
96 changed files with 1037 additions and 2453 deletions

View File

@@ -123,13 +123,6 @@ public class DIOJNI extends JNIWrapper {
*/
public static native boolean isAnyPulsing();
/**
* Gets the loop timing of the PWM system.
*
* @return the loop time in clock ticks
*/
public static native short getLoopTiming();
/**
* Allocates a DO PWM Generator.
*

View File

@@ -1,32 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.hal;
/** Structure for holding the config data result for PWM. */
@SuppressWarnings("MemberName")
public class PWMConfigDataResult {
PWMConfigDataResult(int max, int deadbandMax, int center, int deadbandMin, int min) {
this.max = max;
this.deadbandMax = deadbandMax;
this.center = center;
this.deadbandMin = deadbandMin;
this.min = min;
}
/** The maximum PWM value in microseconds. */
public int max;
/** The deadband maximum PWM value in microseconds. */
public int deadbandMax;
/** The center PWM value in microseconds. */
public int center;
/** The deadband minimum PWM value in microseconds. */
public int deadbandMin;
/** The minimum PWM value in microseconds. */
public int min;
}

View File

@@ -34,50 +34,13 @@ public class PWMJNI extends DIOJNI {
public static native void freePWMPort(int pwmPortHandle);
/**
* Sets the configuration settings for the PWM channel.
* Indicates the pwm is used by a simulated device.
*
* <p>All values are in microseconds.
*
* @param pwmPortHandle the PWM handle
* @param maxPwm the maximum PWM value
* @param deadbandMaxPwm the high range of the center deadband
* @param centerPwm the center PWM value
* @param deadbandMinPwm the low range of the center deadband
* @param minPwm the minimum PWM value
* @param handle the pwm handle
* @param device simulated device handle
* @see "HAL_SetPWMSimDevice"
*/
public static native void setPWMConfigMicroseconds(
int pwmPortHandle,
int maxPwm,
int deadbandMaxPwm,
int centerPwm,
int deadbandMinPwm,
int minPwm);
/**
* Gets the pwm configuration settings for the PWM channel.
*
* <p>Values are in microseconds.
*
* @param pwmPortHandle the PWM handle
* @return the pwm configuration settings
*/
public static native PWMConfigDataResult getPWMConfigMicroseconds(int pwmPortHandle);
/**
* Sets if the FPGA should output the center value if the input value is within the deadband.
*
* @param pwmPortHandle the PWM handle
* @param eliminateDeadband true to eliminate deadband, otherwise false
*/
public static native void setPWMEliminateDeadband(int pwmPortHandle, boolean eliminateDeadband);
/**
* Gets the current eliminate deadband value.
*
* @param pwmPortHandle the PWM handle
* @return true if set, otherwise false
*/
public static native boolean getPWMEliminateDeadband(int pwmPortHandle);
public static native void setPWMSimDevice(int handle, int device);
/**
* Sets a PWM channel to the desired pulse width in microseconds.
@@ -87,28 +50,6 @@ public class PWMJNI extends DIOJNI {
*/
public static native void setPulseTimeMicroseconds(int pwmPortHandle, int microsecondPulseTime);
/**
* Sets a PWM channel to the desired scaled value.
*
* <p>The values range from -1 to 1 and the period is controlled by the PWM Period and MinHigh
* registers.
*
* @param pwmPortHandle the PWM handle
* @param speed the scaled PWM value to set
*/
public static native void setPWMSpeed(int pwmPortHandle, double speed);
/**
* Sets a PWM channel to the desired position value.
*
* <p>The values range from 0 to 1 and the period is controlled by the PWM Period and MinHigh
* registers.
*
* @param pwmPortHandle the PWM handle
* @param position the positional PWM value to set
*/
public static native void setPWMPosition(int pwmPortHandle, double position);
/**
* Gets the current microsecond pulse time from a PWM channel.
*
@@ -118,56 +59,12 @@ public class PWMJNI extends DIOJNI {
public static native int getPulseTimeMicroseconds(int pwmPortHandle);
/**
* Gets a scaled value from a PWM channel.
*
* <p>The values range from -1 to 1.
*
* @param pwmPortHandle the PWM handle
* @return the current speed PWM value
*/
public static native double getPWMSpeed(int pwmPortHandle);
/**
* Gets a position value from a PWM channel.
*
* <p>The values range from 0 to 1.
*
* @param pwmPortHandle the PWM handle
* @return the current positional PWM value
*/
public static native double getPWMPosition(int pwmPortHandle);
/**
* Sets a PWM channel to be disabled.
*
* <p>The channel is disabled until the next time it is set. Note this is different from just
* setting a 0 speed, as this will actively stop all signaling on the channel.
* Sets the PWM output period.
*
* @param pwmPortHandle the PWM handle.
* @param period 0 for 5ms, 1 or 2 for 10ms, 3 for 20ms
*/
public static native void setPWMDisabled(int pwmPortHandle);
/**
* Forces a PWM signal to go to 0 temporarily.
*
* @param pwmPortHandle the PWM handle.
*/
public static native void latchPWMZero(int pwmPortHandle);
/**
* Sets the PWM output to be a continuous high signal while enabled.
*
* @param pwmPortHandle the PWM handle.
*/
public static native void setAlwaysHighMode(int pwmPortHandle);
/**
* Sets how how often the PWM signal is squelched, thus scaling the period.
*
* @param pwmPortHandle the PWM handle.
* @param squelchMask the 2-bit mask of outputs to squelch
*/
public static native void setPWMPeriodScale(int pwmPortHandle, int squelchMask);
public static native void setPWMOutputPeriod(int pwmPortHandle, int period);
/** Utility class. */
private PWMJNI() {}

View File

@@ -26,41 +26,14 @@ public class PWMDataJNI extends JNIWrapper {
public static native void setPulseMicrosecond(int index, int microsecondPulseTime);
public static native int registerSpeedCallback(
public static native int registerOutputPeriodCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelSpeedCallback(int index, int uid);
public static native void cancelOutputPeriodCallback(int index, int uid);
public static native double getSpeed(int index);
public static native int getOutputPeriod(int index);
public static native void setSpeed(int index, double speed);
public static native int registerPositionCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelPositionCallback(int index, int uid);
public static native double getPosition(int index);
public static native void setPosition(int index, double position);
public static native int registerPeriodScaleCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelPeriodScaleCallback(int index, int uid);
public static native int getPeriodScale(int index);
public static native void setPeriodScale(int index, int periodScale);
public static native int registerZeroLatchCallback(
int index, NotifyCallback callback, boolean initialNotify);
public static native void cancelZeroLatchCallback(int index, int uid);
public static native boolean getZeroLatch(int index);
public static native void setZeroLatch(int index, boolean zeroLatch);
public static native void setOutputPeriod(int index, int period);
public static native void resetData(int index);

View File

@@ -190,21 +190,6 @@ Java_edu_wpi_first_hal_DIOJNI_isAnyPulsing
return returnValue;
}
/*
* Class: edu_wpi_first_hal_DIOJNI
* Method: getLoopTiming
* Signature: ()S
*/
JNIEXPORT jshort JNICALL
Java_edu_wpi_first_hal_DIOJNI_getLoopTiming
(JNIEnv* env, jclass)
{
int32_t status = 0;
jshort returnValue = HAL_GetPWMLoopTiming(&status);
CheckStatus(env, status);
return returnValue;
}
/*
* Class: edu_wpi_first_hal_DIOJNI
* Method: allocateDigitalPWM

View File

@@ -44,7 +44,6 @@ static JException halHandleExCls;
static JException uncleanStatusExCls;
static JException nullPointerEx;
static JClass powerDistributionVersionCls;
static JClass pwmConfigDataResultCls;
static JClass canStatusCls;
static JClass matchInfoDataCls;
static JClass canReceiveMessageCls;
@@ -56,7 +55,6 @@ static JClass canStreamOverflowExCls;
static const JClassInit classes[] = {
{"edu/wpi/first/hal/PowerDistributionVersion",
&powerDistributionVersionCls},
{"edu/wpi/first/hal/PWMConfigDataResult", &pwmConfigDataResultCls},
{"edu/wpi/first/hal/can/CANStatus", &canStatusCls},
{"edu/wpi/first/hal/MatchInfoData", &matchInfoDataCls},
{"edu/wpi/first/hal/can/CANReceiveMessage", &canReceiveMessageCls},
@@ -180,17 +178,6 @@ void ThrowBoundaryException(JNIEnv* env, double value, double lower,
env->Throw(static_cast<jthrowable>(ex));
}
jobject CreatePWMConfigDataResult(JNIEnv* env, int32_t maxPwm,
int32_t deadbandMaxPwm, int32_t centerPwm,
int32_t deadbandMinPwm, int32_t minPwm) {
static jmethodID constructor =
env->GetMethodID(pwmConfigDataResultCls, "<init>", "(IIIII)V");
return env->NewObject(
pwmConfigDataResultCls, constructor, static_cast<jint>(maxPwm),
static_cast<jint>(deadbandMaxPwm), static_cast<jint>(centerPwm),
static_cast<jint>(deadbandMinPwm), static_cast<jint>(minPwm));
}
jobject CreateREVPHVersion(JNIEnv* env, uint32_t firmwareMajor,
uint32_t firmwareMinor, uint32_t firmwareFix,
uint32_t hardwareMinor, uint32_t hardwareMajor,

View File

@@ -49,10 +49,6 @@ void ThrowIllegalArgumentException(JNIEnv* env, std::string_view msg);
void ThrowBoundaryException(JNIEnv* env, double value, double lower,
double upper);
jobject CreatePWMConfigDataResult(JNIEnv* env, int32_t maxPwm,
int32_t deadbandMaxPwm, int32_t centerPwm,
int32_t deadbandMinPwm, int32_t minPwm);
jobject CreateREVPHVersion(JNIEnv* env, uint32_t firmwareMajor,
uint32_t firmwareMinor, uint32_t firmwareFix,
uint32_t hardwareMinor, uint32_t hardwareMajor,

View File

@@ -63,69 +63,14 @@ Java_edu_wpi_first_hal_PWMJNI_freePWMPort
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: setPWMConfigMicroseconds
* Signature: (IIIIII)V
* Method: setPWMSimDevice
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_PWMJNI_setPWMConfigMicroseconds
(JNIEnv* env, jclass, jint id, jint maxPwm, jint deadbandMaxPwm,
jint centerPwm, jint deadbandMinPwm, jint minPwm)
Java_edu_wpi_first_hal_PWMJNI_setPWMSimDevice
(JNIEnv* env, jclass, jint handle, jint device)
{
int32_t status = 0;
HAL_SetPWMConfigMicroseconds((HAL_DigitalHandle)id, maxPwm, deadbandMaxPwm,
centerPwm, deadbandMinPwm, minPwm, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: getPWMConfigMicroseconds
* Signature: (I)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL
Java_edu_wpi_first_hal_PWMJNI_getPWMConfigMicroseconds
(JNIEnv* env, jclass, jint id)
{
int32_t status = 0;
int32_t maxPwm = 0;
int32_t deadbandMaxPwm = 0;
int32_t centerPwm = 0;
int32_t deadbandMinPwm = 0;
int32_t minPwm = 0;
HAL_GetPWMConfigMicroseconds((HAL_DigitalHandle)id, &maxPwm, &deadbandMaxPwm,
&centerPwm, &deadbandMinPwm, &minPwm, &status);
CheckStatus(env, status);
return CreatePWMConfigDataResult(env, maxPwm, deadbandMaxPwm, centerPwm,
deadbandMinPwm, minPwm);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: setPWMEliminateDeadband
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_PWMJNI_setPWMEliminateDeadband
(JNIEnv* env, jclass, jint id, jboolean value)
{
int32_t status = 0;
HAL_SetPWMEliminateDeadband((HAL_DigitalHandle)id, value, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: getPWMEliminateDeadband
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_PWMJNI_getPWMEliminateDeadband
(JNIEnv* env, jclass, jint id)
{
int32_t status = 0;
auto val = HAL_GetPWMEliminateDeadband((HAL_DigitalHandle)id, &status);
CheckStatus(env, status);
return (jboolean)val;
HAL_SetPWMSimDevice((HAL_DigitalHandle)handle, (HAL_SimDeviceHandle)device);
}
/*
@@ -142,34 +87,6 @@ Java_edu_wpi_first_hal_PWMJNI_setPulseTimeMicroseconds
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: setPWMSpeed
* Signature: (ID)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_PWMJNI_setPWMSpeed
(JNIEnv* env, jclass, jint id, jdouble value)
{
int32_t status = 0;
HAL_SetPWMSpeed((HAL_DigitalHandle)id, value, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: setPWMPosition
* Signature: (ID)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_PWMJNI_setPWMPosition
(JNIEnv* env, jclass, jint id, jdouble value)
{
int32_t status = 0;
HAL_SetPWMPosition((HAL_DigitalHandle)id, value, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: getPulseTimeMicroseconds
@@ -188,87 +105,15 @@ Java_edu_wpi_first_hal_PWMJNI_getPulseTimeMicroseconds
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: getPWMSpeed
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_PWMJNI_getPWMSpeed
(JNIEnv* env, jclass, jint id)
{
int32_t status = 0;
jdouble returnValue = HAL_GetPWMSpeed((HAL_DigitalHandle)id, &status);
CheckStatus(env, status);
return returnValue;
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: getPWMPosition
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_PWMJNI_getPWMPosition
(JNIEnv* env, jclass, jint id)
{
int32_t status = 0;
jdouble returnValue = HAL_GetPWMPosition((HAL_DigitalHandle)id, &status);
CheckStatus(env, status);
return returnValue;
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: setPWMDisabled
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_PWMJNI_setPWMDisabled
(JNIEnv* env, jclass, jint id)
{
int32_t status = 0;
HAL_SetPWMDisabled((HAL_DigitalHandle)id, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: latchPWMZero
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_PWMJNI_latchPWMZero
(JNIEnv* env, jclass, jint id)
{
int32_t status = 0;
HAL_LatchPWMZero((HAL_DigitalHandle)id, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: setAlwaysHighMode
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_PWMJNI_setAlwaysHighMode
(JNIEnv* env, jclass, jint id)
{
int32_t status = 0;
HAL_SetPWMAlwaysHighMode((HAL_DigitalHandle)id, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_PWMJNI
* Method: setPWMPeriodScale
* Method: setPWMOutputPeriod
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_PWMJNI_setPWMPeriodScale
Java_edu_wpi_first_hal_PWMJNI_setPWMOutputPeriod
(JNIEnv* env, jclass, jint id, jint value)
{
int32_t status = 0;
HAL_SetPWMPeriodScale((HAL_DigitalHandle)id, value, &status);
HAL_SetPWMOutputPeriod((HAL_DigitalHandle)id, value, &status);
CheckStatus(env, status);
}

View File

@@ -114,201 +114,52 @@ Java_edu_wpi_first_hal_simulation_PWMDataJNI_setPulseMicrosecond
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: registerSpeedCallback
* Method: registerOutputPeriodCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_registerSpeedCallback
Java_edu_wpi_first_hal_simulation_PWMDataJNI_registerOutputPeriodCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterPWMSpeedCallback);
&HALSIM_RegisterPWMOutputPeriodCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: cancelSpeedCallback
* Method: cancelOutputPeriodCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_cancelSpeedCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index, &HALSIM_CancelPWMSpeedCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: getSpeed
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_getSpeed
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetPWMSpeed(index);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: setSpeed
* Signature: (ID)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_setSpeed
(JNIEnv*, jclass, jint index, jdouble value)
{
HALSIM_SetPWMSpeed(index, value);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: registerPositionCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_registerPositionCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterPWMPositionCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: cancelPositionCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_cancelPositionCallback
Java_edu_wpi_first_hal_simulation_PWMDataJNI_cancelOutputPeriodCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelPWMPositionCallback);
&HALSIM_CancelPWMOutputPeriodCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: getPosition
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_getPosition
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetPWMPosition(index);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: setPosition
* Signature: (ID)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_setPosition
(JNIEnv*, jclass, jint index, jdouble value)
{
HALSIM_SetPWMPosition(index, value);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: registerPeriodScaleCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_registerPeriodScaleCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterPWMPeriodScaleCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: cancelPeriodScaleCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_cancelPeriodScaleCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelPWMPeriodScaleCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: getPeriodScale
* Method: getOutputPeriod
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_getPeriodScale
Java_edu_wpi_first_hal_simulation_PWMDataJNI_getOutputPeriod
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetPWMPeriodScale(index);
return HALSIM_GetPWMOutputPeriod(index);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: setPeriodScale
* Method: setOutputPeriod
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_setPeriodScale
Java_edu_wpi_first_hal_simulation_PWMDataJNI_setOutputPeriod
(JNIEnv*, jclass, jint index, jint value)
{
HALSIM_SetPWMPeriodScale(index, value);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: registerZeroLatchCallback
* Signature: (ILjava/lang/Object;Z)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_registerZeroLatchCallback
(JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
{
return sim::AllocateCallback(env, index, callback, initialNotify,
&HALSIM_RegisterPWMZeroLatchCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: cancelZeroLatchCallback
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_cancelZeroLatchCallback
(JNIEnv* env, jclass, jint index, jint handle)
{
return sim::FreeCallback(env, handle, index,
&HALSIM_CancelPWMZeroLatchCallback);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: getZeroLatch
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_getZeroLatch
(JNIEnv*, jclass, jint index)
{
return HALSIM_GetPWMZeroLatch(index);
}
/*
* Class: edu_wpi_first_hal_simulation_PWMDataJNI
* Method: setZeroLatch
* Signature: (IZ)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_simulation_PWMDataJNI_setZeroLatch
(JNIEnv*, jclass, jint index, jboolean value)
{
HALSIM_SetPWMZeroLatch(index, value);
HALSIM_SetPWMOutputPeriod(index, value);
}
/*

View File

@@ -47,61 +47,12 @@ void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle);
HAL_Bool HAL_CheckPWMChannel(int32_t channel);
/**
* Sets the configuration settings for the PWM channel.
* Indicates the pwm is used by a simulated device.
*
* All values are in microseconds.
*
* @param[in] pwmPortHandle the PWM handle
* @param[in] maxPwm the maximum PWM value
* @param[in] deadbandMaxPwm the high range of the center deadband
* @param[in] centerPwm the center PWM value
* @param[in] deadbandMinPwm the low range of the center deadband
* @param[in] minPwm the minimum PWM value
* @param[out] status Error status variable. 0 on success.
* @param handle the pwm handle
* @param device simulated device handle
*/
void HAL_SetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle,
int32_t maxPwm, int32_t deadbandMaxPwm,
int32_t centerPwm, int32_t deadbandMinPwm,
int32_t minPwm, int32_t* status);
/**
* Gets the pwm configuration settings for the PWM channel.
*
* Values are in microseconds.
*
* @param[in] pwmPortHandle the PWM handle
* @param[in] maxPwm the maximum PWM value
* @param[in] deadbandMaxPwm the high range of the center deadband
* @param[in] centerPwm the center PWM value
* @param[in] deadbandMinPwm the low range of the center deadband
* @param[in] minPwm the minimum PWM value
* @param[out] status Error status variable. 0 on success.
*/
void HAL_GetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle,
int32_t* maxPwm, int32_t* deadbandMaxPwm,
int32_t* centerPwm, int32_t* deadbandMinPwm,
int32_t* minPwm, int32_t* status);
/**
* Sets if the FPGA should output the center value if the input value is within
* the deadband.
*
* @param[in] pwmPortHandle the PWM handle
* @param[in] eliminateDeadband true to eliminate deadband, otherwise false
* @param[out] status Error status variable. 0 on success.
*/
void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
HAL_Bool eliminateDeadband, int32_t* status);
/**
* Gets the current eliminate deadband value.
*
* @param[in] pwmPortHandle the PWM handle
* @param[out] status Error status variable. 0 on success.
* @return true if set, otherwise false
*/
HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
int32_t* status);
void HAL_SetPWMSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device);
/**
* Sets a PWM channel to the desired pulse width in microseconds.
@@ -115,44 +66,6 @@ void HAL_SetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
int32_t microsecondPulseTime,
int32_t* status);
/**
* Sets a PWM channel to the desired scaled value.
*
* The values range from -1 to 1 and the period is controlled by the PWM Period
* and MinHigh registers.
*
* @param[in] pwmPortHandle the PWM handle
* @param[in] speed the scaled PWM value to set
* @param[out] status Error status variable. 0 on success.
*/
void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
int32_t* status);
/**
* Sets a PWM channel to the desired position value.
*
* The values range from 0 to 1 and the period is controlled by the PWM Period
* and MinHigh registers.
*
* @param[in] pwmPortHandle the PWM handle
* @param[in] position the positional PWM value to set
* @param[out] status Error status variable. 0 on success.
*/
void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double position,
int32_t* status);
/**
* Sets a PWM channel to be disabled.
*
* The channel is disabled until the next time it is set. Note this is different
* from just setting a 0 speed, as this will actively stop all signaling on the
* channel.
*
* @param[in] pwmPortHandle the PWM handle.
* @param[out] status Error status variable. 0 on success.
*/
void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status);
/**
* Gets the current microsecond pulse time from a PWM channel.
*
@@ -164,70 +77,14 @@ int32_t HAL_GetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
int32_t* status);
/**
* Gets a scaled value from a PWM channel.
*
* The values range from -1 to 1.
*
* @param[in] pwmPortHandle the PWM handle
* @param[out] status Error status variable. 0 on success.
* @return the current speed PWM value
*/
double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status);
/**
* Gets a position value from a PWM channel.
*
* The values range from 0 to 1.
*
* @param[in] pwmPortHandle the PWM handle
* @param[out] status Error status variable. 0 on success.
* @return the current positional PWM value
*/
double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status);
/**
* Forces a PWM signal to go to 0 temporarily.
* Sets the PWM output period.
*
* @param[in] pwmPortHandle the PWM handle.
* @param[in] period 0 for 5ms, 1 or 2 for 10ms, 3 for 20ms
* @param[out] status Error status variable. 0 on success.
*/
void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status);
/**
* Sets how how often the PWM signal is squelched, thus scaling the period.
*
* @param[in] pwmPortHandle the PWM handle.
* @param[in] squelchMask the 2-bit mask of outputs to squelch
* @param[out] status Error status variable. 0 on success.
*/
void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
int32_t* status);
/**
* Sets the PWM output to be a continuous high signal while enabled.
*
* @param[in] pwmPortHandle the PWM handle.
* @param[out] status Error status variable. 0 on success.
*/
void HAL_SetPWMAlwaysHighMode(HAL_DigitalHandle pwmPortHandle, int32_t* status);
/**
* Gets the loop timing of the PWM system.
*
* @param[out] status Error status variable. 0 on success.
* @return the loop time in clock ticks
*/
int32_t HAL_GetPWMLoopTiming(int32_t* status);
/**
* Gets the pwm starting cycle time.
*
* This time is relative to the FPGA time.
*
* @param[out] status Error status variable. 0 on success.
* @return the pwm cycle start time
*/
uint64_t HAL_GetPWMCycleStartTime(int32_t* status);
void HAL_SetPWMOutputPeriod(HAL_DigitalHandle pwmPortHandle, int32_t period,
int32_t* status);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -20,6 +20,8 @@ void HALSIM_CancelPWMInitializedCallback(int32_t index, int32_t uid);
HAL_Bool HALSIM_GetPWMInitialized(int32_t index);
void HALSIM_SetPWMInitialized(int32_t index, HAL_Bool initialized);
HAL_SimDeviceHandle HALSIM_GetPWMSimDevice(int32_t index);
int32_t HALSIM_RegisterPWMPulseMicrosecondCallback(int32_t index,
HAL_NotifyCallback callback,
void* param,
@@ -28,35 +30,13 @@ void HALSIM_CancelPWMPulseMicrosecondCallback(int32_t index, int32_t uid);
int32_t HALSIM_GetPWMPulseMicrosecond(int32_t index);
void HALSIM_SetPWMPulseMicrosecond(int32_t index, int32_t microsecondPulseTime);
int32_t HALSIM_RegisterPWMSpeedCallback(int32_t index,
HAL_NotifyCallback callback,
void* param, HAL_Bool initialNotify);
void HALSIM_CancelPWMSpeedCallback(int32_t index, int32_t uid);
double HALSIM_GetPWMSpeed(int32_t index);
void HALSIM_SetPWMSpeed(int32_t index, double speed);
int32_t HALSIM_RegisterPWMPositionCallback(int32_t index,
HAL_NotifyCallback callback,
void* param, HAL_Bool initialNotify);
void HALSIM_CancelPWMPositionCallback(int32_t index, int32_t uid);
double HALSIM_GetPWMPosition(int32_t index);
void HALSIM_SetPWMPosition(int32_t index, double position);
int32_t HALSIM_RegisterPWMPeriodScaleCallback(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
void HALSIM_CancelPWMPeriodScaleCallback(int32_t index, int32_t uid);
int32_t HALSIM_GetPWMPeriodScale(int32_t index);
void HALSIM_SetPWMPeriodScale(int32_t index, int32_t periodScale);
int32_t HALSIM_RegisterPWMZeroLatchCallback(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
void HALSIM_CancelPWMZeroLatchCallback(int32_t index, int32_t uid);
HAL_Bool HALSIM_GetPWMZeroLatch(int32_t index);
void HALSIM_SetPWMZeroLatch(int32_t index, HAL_Bool zeroLatch);
int32_t HALSIM_RegisterPWMOutputPeriodCallback(int32_t index,
HAL_NotifyCallback callback,
void* param,
HAL_Bool initialNotify);
void HALSIM_CancelPWMOutputPeriodCallback(int32_t index, int32_t uid);
int32_t HALSIM_GetPWMOutputPeriod(int32_t index);
void HALSIM_SetPWMOutputPeriod(int32_t index, int32_t periodScale);
void HALSIM_RegisterPWMAllCallbacks(int32_t index, HAL_NotifyCallback callback,
void* param, HAL_Bool initialNotify);

View File

@@ -42,13 +42,6 @@ constexpr int32_t kPwmDisabled = 0;
struct DigitalPort {
uint8_t channel;
bool configSet = false;
bool eliminateDeadband = false;
int32_t maxPwm = 0;
int32_t deadbandMaxPwm = 0;
int32_t centerPwm = 0;
int32_t deadbandMinPwm = 0;
int32_t minPwm = 0;
int32_t filterIndex = 0;
std::string previousAllocation;
};

View File

@@ -21,46 +21,6 @@ namespace hal::init {
void InitializePWM() {}
} // namespace hal::init
static inline int32_t GetMaxPositivePwm(DigitalPort* port) {
return port->maxPwm;
}
static inline int32_t GetMinPositivePwm(DigitalPort* port) {
if (port->eliminateDeadband) {
return port->deadbandMaxPwm;
} else {
return port->centerPwm + 1;
}
}
static inline int32_t GetCenterPwm(DigitalPort* port) {
return port->centerPwm;
}
static inline int32_t GetMaxNegativePwm(DigitalPort* port) {
if (port->eliminateDeadband) {
return port->deadbandMinPwm;
} else {
return port->centerPwm - 1;
}
}
static inline int32_t GetMinNegativePwm(DigitalPort* port) {
return port->minPwm;
}
static inline int32_t GetPositiveScaleFactor(DigitalPort* port) {
return GetMaxPositivePwm(port) - GetMinPositivePwm(port);
} ///< The scale for positive speeds.
static inline int32_t GetNegativeScaleFactor(DigitalPort* port) {
return GetMaxNegativePwm(port) - GetMinNegativePwm(port);
} ///< The scale for negative speeds.
static inline int32_t GetFullRangeScaleFactor(DigitalPort* port) {
return GetMaxPositivePwm(port) - GetMinNegativePwm(port);
} ///< The scale for positions.
extern "C" {
HAL_DigitalHandle HAL_InitializePWMPort(int32_t channel,
@@ -103,8 +63,8 @@ HAL_DigitalHandle HAL_InitializePWMPort(int32_t channel,
SimPWMData[origChannel].initialized = true;
// Defaults to allow an always valid config.
HAL_SetPWMConfigMicroseconds(handle, 2000, 1501, 1500, 1499, 1000, status);
// Disable output.
HAL_SetPWMPulseTimeMicroseconds(handle, 0, status);
port->previousAllocation = allocationLocation ? allocationLocation : "";
@@ -125,58 +85,12 @@ HAL_Bool HAL_CheckPWMChannel(int32_t channel) {
return channel < kNumPWMChannels && channel >= 0;
}
void HAL_SetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle, int32_t max,
int32_t deadbandMax, int32_t center,
int32_t deadbandMin, int32_t min,
int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
void HAL_SetPWMSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
port->maxPwm = max;
port->deadbandMaxPwm = deadbandMax;
port->deadbandMinPwm = deadbandMin;
port->centerPwm = center;
port->minPwm = min;
port->configSet = true;
}
void HAL_GetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle,
int32_t* maxPwm, int32_t* deadbandMaxPwm,
int32_t* centerPwm, int32_t* deadbandMinPwm,
int32_t* minPwm, int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
*maxPwm = port->maxPwm;
*deadbandMaxPwm = port->deadbandMaxPwm;
*deadbandMinPwm = port->deadbandMinPwm;
*centerPwm = port->centerPwm;
*minPwm = port->minPwm;
}
void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
HAL_Bool eliminateDeadband, int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
port->eliminateDeadband = eliminateDeadband;
}
HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}
return port->eliminateDeadband;
SimPWMData[port->channel].simDevice = device;
}
void HAL_SetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
@@ -188,129 +102,6 @@ void HAL_SetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
}
SimPWMData[port->channel].pulseMicrosecond = value;
DigitalPort* dPort = port.get();
double speed = 0.0;
if (value == kPwmDisabled) {
speed = 0.0;
} else if (value > GetMaxPositivePwm(dPort)) {
speed = 1.0;
} else if (value < GetMinNegativePwm(dPort)) {
speed = -1.0;
} else if (value > GetMinPositivePwm(dPort)) {
speed = static_cast<double>(value - GetMinPositivePwm(dPort)) /
static_cast<double>(GetPositiveScaleFactor(dPort));
} else if (value < GetMaxNegativePwm(dPort)) {
speed = static_cast<double>(value - GetMaxNegativePwm(dPort)) /
static_cast<double>(GetNegativeScaleFactor(dPort));
} else {
speed = 0.0;
}
SimPWMData[port->channel].speed = speed;
double pos = 0.0;
if (value < GetMinNegativePwm(dPort)) {
pos = 0.0;
} else if (value > GetMaxPositivePwm(dPort)) {
pos = 1.0;
} else {
pos = static_cast<double>(value - GetMinNegativePwm(dPort)) /
static_cast<double>(GetFullRangeScaleFactor(dPort));
}
SimPWMData[port->channel].position = pos;
}
void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
if (!port->configSet) {
*status = INCOMPATIBLE_STATE;
return;
}
if (std::isfinite(speed)) {
speed = std::clamp(speed, -1.0, 1.0);
} else {
speed = 0.0;
}
DigitalPort* dPort = port.get();
// calculate the desired output pwm value by scaling the speed appropriately
int32_t rawValue;
if (speed == 0.0) {
rawValue = GetCenterPwm(dPort);
} else if (speed > 0.0) {
rawValue =
std::lround(speed * static_cast<double>(GetPositiveScaleFactor(dPort)) +
static_cast<double>(GetMinPositivePwm(dPort)));
} else {
rawValue =
std::lround(speed * static_cast<double>(GetNegativeScaleFactor(dPort)) +
static_cast<double>(GetMaxNegativePwm(dPort)));
}
if (!((rawValue >= GetMinNegativePwm(dPort)) &&
(rawValue <= GetMaxPositivePwm(dPort))) ||
rawValue == kPwmDisabled) {
*status = HAL_PWM_SCALE_ERROR;
return;
}
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, rawValue, status);
}
void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double pos,
int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
if (!port->configSet) {
*status = INCOMPATIBLE_STATE;
return;
}
if (pos < 0.0) {
pos = 0.0;
} else if (pos > 1.0) {
pos = 1.0;
}
DigitalPort* dPort = port.get();
// note, need to perform the multiplication below as floating point before
// converting to int
int32_t rawValue = static_cast<int32_t>(
(pos * static_cast<double>(GetFullRangeScaleFactor(dPort))) +
GetMinNegativePwm(dPort));
if (rawValue == kPwmDisabled) {
*status = HAL_PWM_SCALE_ERROR;
return;
}
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, rawValue, status);
}
void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
SimPWMData[port->channel].pulseMicrosecond = 0;
SimPWMData[port->channel].position = 0;
SimPWMData[port->channel].speed = 0;
}
int32_t HAL_GetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
@@ -324,88 +115,15 @@ int32_t HAL_GetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
return SimPWMData[port->channel].pulseMicrosecond;
}
double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
if (!port->configSet) {
*status = INCOMPATIBLE_STATE;
return 0;
}
double speed = SimPWMData[port->channel].speed;
if (speed > 1) {
speed = 1;
}
if (speed < -1) {
speed = -1;
}
return speed;
}
double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
if (!port->configSet) {
*status = INCOMPATIBLE_STATE;
return 0;
}
double position = SimPWMData[port->channel].position;
if (position > 1) {
position = 1;
}
if (position < 0) {
position = 0;
}
return position;
}
void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
void HAL_SetPWMOutputPeriod(HAL_DigitalHandle pwmPortHandle, int32_t period,
int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
SimPWMData[port->channel].zeroLatch = true;
SimPWMData[port->channel].zeroLatch = false;
SimPWMData[port->channel].outputPeriod = period;
}
void HAL_SetPWMAlwaysHighMode(HAL_DigitalHandle pwmPortHandle,
int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
SimPWMData[port->channel].pulseMicrosecond = 0xFFFF;
SimPWMData[port->channel].position = 0xFFFF;
SimPWMData[port->channel].speed = 0xFFFF;
}
void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
int32_t* status) {
auto port = digitalChannelHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
SimPWMData[port->channel].periodScale = squelchMask;
}
int32_t HAL_GetPWMLoopTiming(int32_t* status) {
return kExpectedLoopTiming;
}
uint64_t HAL_GetPWMCycleStartTime(int32_t* status) {
return 0;
}
} // extern "C"

View File

@@ -17,11 +17,9 @@ void InitializePWMData() {
PWMData* hal::SimPWMData;
void PWMData::ResetData() {
initialized.Reset(false);
simDevice = 0;
pulseMicrosecond.Reset(0);
speed.Reset(0);
position.Reset(0);
periodScale.Reset(0);
zeroLatch.Reset(false);
outputPeriod.Reset(0);
}
extern "C" {
@@ -29,16 +27,17 @@ void HALSIM_ResetPWMData(int32_t index) {
SimPWMData[index].ResetData();
}
HAL_SimDeviceHandle HALSIM_GetPWMSimDevice(int32_t index) {
return SimPWMData[index].simDevice;
}
#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME) \
HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PWM##CAPINAME, SimPWMData, \
LOWERNAME)
DEFINE_CAPI(HAL_Bool, Initialized, initialized)
DEFINE_CAPI(int32_t, PulseMicrosecond, pulseMicrosecond)
DEFINE_CAPI(double, Speed, speed)
DEFINE_CAPI(double, Position, position)
DEFINE_CAPI(int32_t, PeriodScale, periodScale)
DEFINE_CAPI(HAL_Bool, ZeroLatch, zeroLatch)
DEFINE_CAPI(int32_t, OutputPeriod, outputPeriod)
#define REGISTER(NAME) \
SimPWMData[index].NAME.RegisterCallback(callback, param, initialNotify)
@@ -47,9 +46,6 @@ void HALSIM_RegisterPWMAllCallbacks(int32_t index, HAL_NotifyCallback callback,
void* param, HAL_Bool initialNotify) {
REGISTER(initialized);
REGISTER(pulseMicrosecond);
REGISTER(speed);
REGISTER(position);
REGISTER(periodScale);
REGISTER(zeroLatch);
REGISTER(outputPeriod);
}
} // extern "C"

View File

@@ -11,20 +11,15 @@ namespace hal {
class PWMData {
HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
HAL_SIMDATAVALUE_DEFINE_NAME(PulseMicrosecond)
HAL_SIMDATAVALUE_DEFINE_NAME(Speed)
HAL_SIMDATAVALUE_DEFINE_NAME(Position)
HAL_SIMDATAVALUE_DEFINE_NAME(PeriodScale)
HAL_SIMDATAVALUE_DEFINE_NAME(ZeroLatch)
HAL_SIMDATAVALUE_DEFINE_NAME(OutputPeriod)
public:
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
false};
std::atomic<HAL_SimDeviceHandle> simDevice;
SimDataValue<int32_t, HAL_MakeInt, GetPulseMicrosecondName> pulseMicrosecond{
0};
SimDataValue<double, HAL_MakeDouble, GetSpeedName> speed{0};
SimDataValue<double, HAL_MakeDouble, GetPositionName> position{0};
SimDataValue<int32_t, HAL_MakeInt, GetPeriodScaleName> periodScale{0};
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetZeroLatchName> zeroLatch{false};
SimDataValue<int32_t, HAL_MakeInt, GetOutputPeriodName> outputPeriod{0};
virtual void ResetData();
};

View File

@@ -22,46 +22,6 @@
using namespace hal;
static inline int32_t GetMaxPositivePwm(SmartIo* port) {
return port->maxPwm;
}
static inline int32_t GetMinPositivePwm(SmartIo* port) {
if (port->eliminateDeadband) {
return port->deadbandMaxPwm;
} else {
return port->centerPwm + 1;
}
}
static inline int32_t GetCenterPwm(SmartIo* port) {
return port->centerPwm;
}
static inline int32_t GetMaxNegativePwm(SmartIo* port) {
if (port->eliminateDeadband) {
return port->deadbandMinPwm;
} else {
return port->centerPwm - 1;
}
}
static inline int32_t GetMinNegativePwm(SmartIo* port) {
return port->minPwm;
}
static inline int32_t GetPositiveScaleFactor(SmartIo* port) {
return GetMaxPositivePwm(port) - GetMinPositivePwm(port);
} ///< The scale for positive speeds.
static inline int32_t GetNegativeScaleFactor(SmartIo* port) {
return GetMaxNegativePwm(port) - GetMinNegativePwm(port);
} ///< The scale for negative speeds.
static inline int32_t GetFullRangeScaleFactor(SmartIo* port) {
return GetMaxPositivePwm(port) - GetMinNegativePwm(port);
} ///< The scale for positions.
namespace hal::init {
void InitializePWM() {}
} // namespace hal::init
@@ -104,8 +64,8 @@ HAL_DigitalHandle HAL_InitializePWMPort(int32_t channel,
return HAL_kInvalidHandle;
}
// Defaults to allow an always valid config.
HAL_SetPWMConfigMicroseconds(handle, 2000, 1501, 1500, 1499, 1000, status);
// Disable the PWM output.
HAL_SetPWMPulseTimeMicroseconds(handle, 0, status);
if (*status != 0) {
smartIoHandles->Free(handle, HAL_HandleEnum::PWM);
return HAL_kInvalidHandle;
@@ -137,63 +97,13 @@ void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle) {
}
}
void HAL_SetPWMSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
}
HAL_Bool HAL_CheckPWMChannel(int32_t channel) {
return channel < kNumSmartIo && channel >= 0;
}
void HAL_SetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle, int32_t max,
int32_t deadbandMax, int32_t center,
int32_t deadbandMin, int32_t min,
int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
port->maxPwm = max;
port->deadbandMaxPwm = deadbandMax;
port->deadbandMinPwm = deadbandMin;
port->centerPwm = center;
port->minPwm = min;
port->configSet = true;
}
void HAL_GetPWMConfigMicroseconds(HAL_DigitalHandle pwmPortHandle,
int32_t* maxPwm, int32_t* deadbandMaxPwm,
int32_t* centerPwm, int32_t* deadbandMinPwm,
int32_t* minPwm, int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
*maxPwm = port->maxPwm;
*deadbandMaxPwm = port->deadbandMaxPwm;
*deadbandMinPwm = port->deadbandMinPwm;
*centerPwm = port->centerPwm;
*minPwm = port->minPwm;
}
void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
HAL_Bool eliminateDeadband, int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
port->eliminateDeadband = eliminateDeadband;
}
HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return false;
}
return port->eliminateDeadband;
}
void HAL_SetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
int32_t microsecondPulseTime,
int32_t* status) {
@@ -216,87 +126,6 @@ void HAL_SetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
*status = port->SetPwmMicroseconds(microsecondPulseTime);
}
void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
if (!port->configSet) {
*status = INCOMPATIBLE_STATE;
return;
}
SmartIo* dPort = port.get();
if (std::isfinite(speed)) {
speed = std::clamp(speed, -1.0, 1.0);
} else {
speed = 0.0;
}
// calculate the desired output pwm value by scaling the speed appropriately
int32_t rawValue;
if (speed == 0.0) {
rawValue = GetCenterPwm(dPort);
} else if (speed > 0.0) {
rawValue =
std::lround(speed * static_cast<double>(GetPositiveScaleFactor(dPort)) +
static_cast<double>(GetMinPositivePwm(dPort)));
} else {
rawValue =
std::lround(speed * static_cast<double>(GetNegativeScaleFactor(dPort)) +
static_cast<double>(GetMaxNegativePwm(dPort)));
}
if (!((rawValue >= GetMinNegativePwm(dPort)) &&
(rawValue <= GetMaxPositivePwm(dPort))) ||
rawValue == kPwmDisabled) {
*status = HAL_PWM_SCALE_ERROR;
return;
}
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, rawValue, status);
}
void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double pos,
int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
if (!port->configSet) {
*status = INCOMPATIBLE_STATE;
return;
}
SmartIo* dPort = port.get();
if (pos < 0.0) {
pos = 0.0;
} else if (pos > 1.0) {
pos = 1.0;
}
// note, need to perform the multiplication below as floating point before
// converting to int
int32_t rawValue = static_cast<int32_t>(
(pos * static_cast<double>(GetFullRangeScaleFactor(dPort))) +
GetMinNegativePwm(dPort));
if (rawValue == kPwmDisabled) {
*status = HAL_PWM_SCALE_ERROR;
return;
}
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, rawValue, status);
}
void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, kPwmDisabled, status);
}
int32_t HAL_GetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
@@ -310,79 +139,15 @@ int32_t HAL_GetPWMPulseTimeMicroseconds(HAL_DigitalHandle pwmPortHandle,
return microseconds;
}
double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
if (!port->configSet) {
*status = INCOMPATIBLE_STATE;
return 0;
}
int32_t value = HAL_GetPWMPulseTimeMicroseconds(pwmPortHandle, status);
if (*status != 0) {
return 0;
}
SmartIo* dPort = port.get();
if (value == kPwmDisabled) {
return 0.0;
} else if (value > GetMaxPositivePwm(dPort)) {
return 1.0;
} else if (value < GetMinNegativePwm(dPort)) {
return -1.0;
} else if (value > GetMinPositivePwm(dPort)) {
return static_cast<double>(value - GetMinPositivePwm(dPort)) /
static_cast<double>(GetPositiveScaleFactor(dPort));
} else if (value < GetMaxNegativePwm(dPort)) {
return static_cast<double>(value - GetMaxNegativePwm(dPort)) /
static_cast<double>(GetNegativeScaleFactor(dPort));
} else {
return 0.0;
}
}
double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
if (!port->configSet) {
*status = INCOMPATIBLE_STATE;
return 0;
}
int32_t value = HAL_GetPWMPulseTimeMicroseconds(pwmPortHandle, status);
if (*status != 0) {
return 0;
}
SmartIo* dPort = port.get();
if (value < GetMinNegativePwm(dPort)) {
return 0.0;
} else if (value > GetMaxPositivePwm(dPort)) {
return 1.0;
} else {
return static_cast<double>(value - GetMinNegativePwm(dPort)) /
static_cast<double>(GetFullRangeScaleFactor(dPort));
}
}
void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, 0, status);
}
void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
int32_t* status) {
void HAL_SetPWMOutputPeriod(HAL_DigitalHandle pwmPortHandle, int32_t period,
int32_t* status) {
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
switch (squelchMask) {
switch (period) {
case 0:
*status = port->SetPwmOutputPeriod(hal::PwmOutputPeriod::k5ms);
break;
@@ -399,31 +164,4 @@ void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
}
}
void HAL_SetPWMAlwaysHighMode(HAL_DigitalHandle pwmPortHandle,
int32_t* status) {
// Always high is going to have to use a 2ms period
auto port = smartIoHandles->Get(pwmPortHandle, HAL_HandleEnum::PWM);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
*status = port->SetPwmOutputPeriod(hal::PwmOutputPeriod::k2ms);
if (*status != 0) {
return;
}
HAL_SetPWMPulseTimeMicroseconds(pwmPortHandle, kPwmAlwaysHigh, status);
}
int32_t HAL_GetPWMLoopTiming(int32_t* status) {
// TODO(thad) not currently supported
return 0;
}
uint64_t HAL_GetPWMCycleStartTime(int32_t* status) {
// TODO(thad) not currently supported
return 0;
}
} // extern "C"

View File

@@ -36,13 +36,6 @@ enum class PwmOutputPeriod {
struct SmartIo {
uint8_t channel;
bool configSet = false;
bool eliminateDeadband = false;
int32_t maxPwm = 0;
int32_t deadbandMaxPwm = 0;
int32_t centerPwm = 0;
int32_t deadbandMinPwm = 0;
int32_t minPwm = 0;
std::string previousAllocation;
SmartIoMode currentMode{SmartIoMode::DigitalInput};
nt::IntegerPublisher modePublisher;

View File

@@ -9,15 +9,16 @@
extern "C" {
void HALSIM_ResetPWMData(int32_t index) {}
HAL_SimDeviceHandle HALSIM_GetPWMSimDevice(int32_t index) {
return 0;
}
#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, PWM##CAPINAME, RETURN)
DEFINE_CAPI(HAL_Bool, Initialized, false)
DEFINE_CAPI(int32_t, PulseMicrosecond, 0)
DEFINE_CAPI(double, Speed, 0)
DEFINE_CAPI(double, Position, 0)
DEFINE_CAPI(int32_t, PeriodScale, 0)
DEFINE_CAPI(HAL_Bool, ZeroLatch, false)
DEFINE_CAPI(int32_t, OutputPeriod, 0)
void HALSIM_RegisterPWMAllCallbacks(int32_t index, HAL_NotifyCallback callback,
void* param, HAL_Bool initialNotify) {}

View File

@@ -15,9 +15,8 @@ import edu.wpi.first.wpilibj.motorcontrol.PWMMotorController;
public class RomiMotor extends PWMMotorController {
/** Common initialization code called by all constructors. */
protected final void initRomiMotor() {
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
}
/**

View File

@@ -7,7 +7,6 @@
using namespace frc;
RomiMotor::RomiMotor(int channel) : PWMMotorController("Romi Motor", channel) {
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
}

View File

@@ -4,7 +4,6 @@ nativeUtils {
groupId = "edu.wpi.first.thirdparty.frc2024.ceres"
artifactId = "ceres-cpp"
headerClassifier = "headers"
sourceClassifier = "sources"
ext = "zip"
version = '2.2-3'
targetPlatforms.addAll(nativeUtils.wpi.platforms.desktopPlatforms)

View File

@@ -18,7 +18,7 @@
using namespace halsimgui;
namespace {
HALSIMGUI_DATASOURCE_DOUBLE_INDEXED(PWMSpeed, "PWM");
HALSIMGUI_DATASOURCE_DOUBLE_INDEXED(PWMPulseMicrosecond, "PWM");
class PWMSimModel : public glass::PWMModel {
public:
@@ -33,12 +33,14 @@ class PWMSimModel : public glass::PWMModel {
glass::DoubleSource* GetSpeedData() override { return &m_speed; }
void SetSpeed(double val) override { HALSIM_SetPWMSpeed(m_index, val); }
void SetSpeed(double val) override {
HALSIM_SetPWMPulseMicrosecond(m_index, val);
}
private:
int32_t m_index;
int m_led = -1;
PWMSpeedSource m_speed;
PWMPulseMicrosecondSource m_speed;
};
class PWMsSimModel : public glass::PWMsModel {

View File

@@ -265,11 +265,8 @@ PWMs may be used to control either motor controllers or servos. Typically only
| Data Key | Type | Description |
| ------------------- | ------- | ------------------------------------------ |
| ``"<init"`` | Boolean | If PWM is initialized in the robot program |
| ``"<speed"`` | Float | Speed, -1.0 to 1.0 range |
| ``"<position"`` | Float | Servo position, 0.0 to 1.0 range |
| ``"<raw"`` | Integer | The pulse time in microseconds |
| ``"<period_scale"`` | Integer | Scales the PWM signal by squelching setting a 2-bit mask of outputs to squelch (ex. `1` -> squelch every other value; `3` -> squelch 3 of 4 values) |
| ``"<zero_latch"`` | Boolean | Whether the PWM should be latched to 0 |
| ``"<output_period"``| Integer | Scales the PWM signal by squelching setting a 2-bit mask of outputs to squelch (ex. `1` -> squelch every other value; `3` -> squelch 3 of 4 values) |
#### Solenoid Output ("Solenoid")

View File

@@ -505,25 +505,12 @@ components:
<init:
type: boolean
description: "If PWM is initialized in the robot program"
<speed:
type: number
description: "Speed"
minimum: -1.0
maximum: 1.0
<position:
type: number
description: "Servo position"
minimum: 0.0
maximum: 1.0
"<raw":
type: integer
description: "The pulse time in microseconds"
"<period_scale":
"<output_period":
type: integer
description: "Scales the PWM signal by squelching setting a 2-bit mask of outputs to squelch (ex. `1` -> squelch every other value; `3` -> squelch 3 of 4 values)"
"<zero_latch":
type: boolean
description: "Whether the PWM should be latched to 0"
solenoidData:
type: object

View File

@@ -28,11 +28,8 @@ HALSimWSProviderPWM::~HALSimWSProviderPWM() {
void HALSimWSProviderPWM::RegisterCallbacks() {
m_initCbKey = REGISTER(Initialized, "<init", bool, boolean);
m_speedCbKey = REGISTER(Speed, "<speed", double, double);
m_positionCbKey = REGISTER(Position, "<position", double, double);
m_rawCbKey = REGISTER(PulseMicrosecond, "<raw", int32_t, int);
m_periodScaleCbKey = REGISTER(PeriodScale, "<period_scale", int32_t, int);
m_zeroLatchCbKey = REGISTER(ZeroLatch, "<zero_latch", bool, boolean);
m_outputPeriodCbKey = REGISTER(OutputPeriod, "<output_period", int32_t, int);
}
void HALSimWSProviderPWM::CancelCallbacks() {
@@ -41,18 +38,12 @@ void HALSimWSProviderPWM::CancelCallbacks() {
void HALSimWSProviderPWM::DoCancelCallbacks() {
HALSIM_CancelPWMInitializedCallback(m_channel, m_initCbKey);
HALSIM_CancelPWMSpeedCallback(m_channel, m_speedCbKey);
HALSIM_CancelPWMPositionCallback(m_channel, m_positionCbKey);
HALSIM_CancelPWMPulseMicrosecondCallback(m_channel, m_rawCbKey);
HALSIM_CancelPWMPeriodScaleCallback(m_channel, m_periodScaleCbKey);
HALSIM_CancelPWMZeroLatchCallback(m_channel, m_zeroLatchCbKey);
HALSIM_CancelPWMOutputPeriodCallback(m_channel, m_outputPeriodCbKey);
m_initCbKey = 0;
m_speedCbKey = 0;
m_positionCbKey = 0;
m_rawCbKey = 0;
m_periodScaleCbKey = 0;
m_zeroLatchCbKey = 0;
m_outputPeriodCbKey = 0;
}
} // namespace wpilibws

View File

@@ -24,11 +24,8 @@ class HALSimWSProviderPWM : public HALSimWSHalChanProvider {
private:
int32_t m_initCbKey = 0;
int32_t m_speedCbKey = 0;
int32_t m_positionCbKey = 0;
int32_t m_rawCbKey = 0;
int32_t m_periodScaleCbKey = 0;
int32_t m_zeroLatchCbKey = 0;
int32_t m_outputPeriodCbKey = 0;
};
} // namespace wpilibws

View File

@@ -11,10 +11,9 @@
using namespace frc;
{{ name }}::{{ name }}(int channel) : PWMMotorController("{{ name }}", channel) {
m_pwm.SetBounds({{ pulse_width_ms.max }}_ms, {{ pulse_width_ms.deadbandMax }}_ms, {{ pulse_width_ms.center }}_ms, {{ pulse_width_ms.deadbandMin }}_ms, {{ pulse_width_ms.min }}_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_{{ PeriodMultiplier | default("1", true)}}X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds({{ pulse_width_ms.max }}_ms, {{ pulse_width_ms.deadbandMax }}_ms, {{ pulse_width_ms.center }}_ms, {{ pulse_width_ms.deadbandMin }}_ms, {{ pulse_width_ms.min }}_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_{{ OutputPeriod | default("5", true)}}Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "{{ ResourceName }}");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
DMC60::DMC60(int channel) : PWMMotorController("DMC60", channel) {
m_pwm.SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "DigilentDMC60");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
Jaguar::Jaguar(int channel) : PWMMotorController("Jaguar", channel) {
m_pwm.SetBounds(2.31_ms, 1.55_ms, 1.507_ms, 1.454_ms, 0.697_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.31_ms, 1.55_ms, 1.507_ms, 1.454_ms, 0.697_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "Jaguar");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
Koors40::Koors40(int channel) : PWMMotorController("Koors40", channel) {
m_pwm.SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_4X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_20Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "Koors40");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
PWMSparkFlex::PWMSparkFlex(int channel) : PWMMotorController("PWMSparkFlex", channel) {
m_pwm.SetBounds(2.003_ms, 1.55_ms, 1.5_ms, 1.46_ms, 0.999_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.003_ms, 1.55_ms, 1.5_ms, 1.46_ms, 0.999_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "RevSparkFlexPWM");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
PWMSparkMax::PWMSparkMax(int channel) : PWMMotorController("PWMSparkMax", channel) {
m_pwm.SetBounds(2.003_ms, 1.55_ms, 1.5_ms, 1.46_ms, 0.999_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.003_ms, 1.55_ms, 1.5_ms, 1.46_ms, 0.999_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "RevSparkMaxPWM");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
PWMTalonFX::PWMTalonFX(int channel) : PWMMotorController("PWMTalonFX", channel) {
m_pwm.SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "TalonFX");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
PWMTalonSRX::PWMTalonSRX(int channel) : PWMMotorController("PWMTalonSRX", channel) {
m_pwm.SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "PWMTalonSRX");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
PWMVenom::PWMVenom(int channel) : PWMMotorController("PWMVenom", channel) {
m_pwm.SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "FusionVenom");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
PWMVictorSPX::PWMVictorSPX(int channel) : PWMMotorController("PWMVictorSPX", channel) {
m_pwm.SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "PWMVictorSPX");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
SD540::SD540(int channel) : PWMMotorController("SD540", channel) {
m_pwm.SetBounds(2.05_ms, 1.55_ms, 1.5_ms, 1.44_ms, 0.94_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.05_ms, 1.55_ms, 1.5_ms, 1.44_ms, 0.94_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "MindsensorsSD540");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
Spark::Spark(int channel) : PWMMotorController("Spark", channel) {
m_pwm.SetBounds(2.003_ms, 1.55_ms, 1.5_ms, 1.46_ms, 0.999_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.003_ms, 1.55_ms, 1.5_ms, 1.46_ms, 0.999_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "RevSPARK");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
SparkMini::SparkMini(int channel) : PWMMotorController("SparkMini", channel) {
m_pwm.SetBounds(2.5_ms, 1.51_ms, 1.5_ms, 1.49_ms, 0.5_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.5_ms, 1.51_ms, 1.5_ms, 1.49_ms, 0.5_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "RevSPARK");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
Talon::Talon(int channel) : PWMMotorController("Talon", channel) {
m_pwm.SetBounds(2.037_ms, 1.539_ms, 1.513_ms, 1.487_ms, 0.989_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.037_ms, 1.539_ms, 1.513_ms, 1.487_ms, 0.989_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "Talon");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
Victor::Victor(int channel) : PWMMotorController("Victor", channel) {
m_pwm.SetBounds(2.027_ms, 1.525_ms, 1.507_ms, 1.49_ms, 1.026_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_2X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.027_ms, 1.525_ms, 1.507_ms, 1.49_ms, 1.026_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_10Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "Victor");
}

View File

@@ -11,10 +11,9 @@
using namespace frc;
VictorSP::VictorSP(int channel) : PWMMotorController("VictorSP", channel) {
m_pwm.SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetPeriodMultiplier(PWM::kPeriodMultiplier_1X);
m_pwm.SetSpeed(0.0);
m_pwm.SetZeroLatch();
SetBounds(2.004_ms, 1.52_ms, 1.5_ms, 1.48_ms, 0.997_ms);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_5Ms);
SetSpeed(0.0);
HAL_ReportUsage("IO", GetChannel(), "VictorSP");
}

View File

@@ -31,11 +31,7 @@ PWM::PWM(int channel, bool registerSendable) {
m_channel = channel;
HAL_SetPWMDisabled(m_handle, &status);
FRC_CheckErrorStatus(status, "Channel {}", channel);
status = 0;
HAL_SetPWMEliminateDeadband(m_handle, false, &status);
FRC_CheckErrorStatus(status, "Channel {}", channel);
SetDisabled();
HAL_ReportUsage("IO", channel, "PWM");
if (registerSendable) {
@@ -45,9 +41,7 @@ PWM::PWM(int channel, bool registerSendable) {
PWM::~PWM() {
if (m_handle != HAL_kInvalidHandle) {
int32_t status = 0;
HAL_SetPWMDisabled(m_handle, &status);
FRC_ReportError(status, "Channel {}", m_channel);
SetDisabled();
}
}
@@ -65,121 +59,48 @@ units::microsecond_t PWM::GetPulseTime() const {
return units::microsecond_t{value};
}
void PWM::SetPosition(double pos) {
int32_t status = 0;
HAL_SetPWMPosition(m_handle, pos, &status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
double PWM::GetPosition() const {
int32_t status = 0;
double position = HAL_GetPWMPosition(m_handle, &status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
return position;
}
void PWM::SetSpeed(double speed) {
int32_t status = 0;
HAL_SetPWMSpeed(m_handle, speed, &status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
double PWM::GetSpeed() const {
int32_t status = 0;
double speed = HAL_GetPWMSpeed(m_handle, &status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
return speed;
}
void PWM::SetDisabled() {
int32_t status = 0;
HAL_SetPWMDisabled(m_handle, &status);
HAL_SetPWMPulseTimeMicroseconds(m_handle, 0, &status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
void PWM::SetPeriodMultiplier(PeriodMultiplier mult) {
void PWM::SetOutputPeriod(OutputPeriod mult) {
int32_t status = 0;
switch (mult) {
case kPeriodMultiplier_4X:
HAL_SetPWMPeriodScale(m_handle, 3,
&status); // Squelch 3 out of 4 outputs
case kOutputPeriod_20Ms:
HAL_SetPWMOutputPeriod(m_handle, 3,
&status); // Squelch 3 out of 4 outputs
break;
case kPeriodMultiplier_2X:
HAL_SetPWMPeriodScale(m_handle, 1,
&status); // Squelch 1 out of 2 outputs
case kOutputPeriod_10Ms:
HAL_SetPWMOutputPeriod(m_handle, 1,
&status); // Squelch 1 out of 2 outputs
break;
case kPeriodMultiplier_1X:
HAL_SetPWMPeriodScale(m_handle, 0, &status); // Don't squelch any outputs
case kOutputPeriod_5Ms:
HAL_SetPWMOutputPeriod(m_handle, 0,
&status); // Don't squelch any outputs
break;
default:
throw FRC_MakeError(err::InvalidParameter, "PeriodMultiplier value {}",
throw FRC_MakeError(err::InvalidParameter, "OutputPeriod value {}",
static_cast<int>(mult));
}
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
void PWM::SetZeroLatch() {
int32_t status = 0;
HAL_LatchPWMZero(m_handle, &status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
void PWM::EnableDeadbandElimination(bool eliminateDeadband) {
int32_t status = 0;
HAL_SetPWMEliminateDeadband(m_handle, eliminateDeadband, &status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
void PWM::SetBounds(units::microsecond_t max, units::microsecond_t deadbandMax,
units::microsecond_t center,
units::microsecond_t deadbandMin,
units::microsecond_t min) {
int32_t status = 0;
HAL_SetPWMConfigMicroseconds(m_handle, max.value(), deadbandMax.value(),
center.value(), deadbandMin.value(), min.value(),
&status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
void PWM::GetBounds(units::microsecond_t* max,
units::microsecond_t* deadbandMax,
units::microsecond_t* center,
units::microsecond_t* deadbandMin,
units::microsecond_t* min) {
int32_t status = 0;
int32_t rawMax, rawDeadbandMax, rawCenter, rawDeadbandMin, rawMin;
HAL_GetPWMConfigMicroseconds(m_handle, &rawMax, &rawDeadbandMax, &rawCenter,
&rawDeadbandMin, &rawMin, &status);
*max = units::microsecond_t{static_cast<double>(rawMax)};
*deadbandMax = units::microsecond_t{static_cast<double>(rawDeadbandMax)};
*center = units::microsecond_t{static_cast<double>(rawCenter)};
*deadbandMin = units::microsecond_t{static_cast<double>(rawDeadbandMin)};
*min = units::microsecond_t{static_cast<double>(rawMin)};
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
void PWM::SetAlwaysHighMode() {
int32_t status = 0;
HAL_SetPWMAlwaysHighMode(m_handle, &status);
FRC_CheckErrorStatus(status, "Channel {}", m_channel);
}
int PWM::GetChannel() const {
return m_channel;
}
void PWM::SetSimDevice(HAL_SimDeviceHandle device) {
HAL_SetPWMSimDevice(m_handle, device);
}
void PWM::InitSendable(wpi::SendableBuilder& builder) {
builder.SetSmartDashboardType("PWM");
builder.SetActuator(true);
builder.AddDoubleProperty(
"Value", [=, this] { return GetPulseTime().value(); },
[=, this](double value) { SetPulseTime(units::millisecond_t{value}); });
builder.AddDoubleProperty(
"Speed", [=, this] { return GetSpeed(); },
[=, this](double value) { SetSpeed(value); });
builder.AddDoubleProperty(
"Position", [=, this] { return GetPosition(); },
[=, this](double value) { SetPosition(value); });
}

View File

@@ -10,33 +10,44 @@
using namespace frc;
constexpr double Servo::kMaxServoAngle;
constexpr double Servo::kMinServoAngle;
constexpr units::millisecond_t Servo::kDefaultMaxServoPWM;
constexpr units::millisecond_t Servo::kDefaultMinServoPWM;
Servo::Servo(int channel) : PWM(channel) {
// Set minimum and maximum PWM values supported by the servo
SetBounds(kDefaultMaxServoPWM, 0.0_ms, 0.0_ms, 0.0_ms, kDefaultMinServoPWM);
Servo::Servo(int channel) : m_pwm(channel, false) {
wpi::SendableRegistry::Add(this, "Servo", channel);
// Assign defaults for period multiplier for the servo PWM control signal
SetPeriodMultiplier(kPeriodMultiplier_4X);
m_pwm.SetOutputPeriod(PWM::kOutputPeriod_20Ms);
HAL_ReportUsage("IO", channel, "Servo");
wpi::SendableRegistry::SetName(this, "Servo", channel);
m_simDevice = hal::SimDevice{"Servo", channel};
if (m_simDevice) {
m_simPosition = m_simDevice.CreateDouble("Position", true, 0.0);
m_pwm.SetSimDevice(m_simDevice);
}
}
void Servo::Set(double value) {
SetPosition(value);
}
value = std::clamp(value, 0.0, 1.0);
if (m_simPosition) {
m_simPosition.Set(value);
}
void Servo::SetOffline() {
SetDisabled();
units::microsecond_t rawValue =
(value * GetFullRangeScaleFactor()) + m_minPwm;
m_pwm.SetPulseTime(rawValue);
}
double Servo::Get() const {
return GetPosition();
units::microsecond_t rawValue = m_pwm.GetPulseTime();
if (rawValue < m_minPwm) {
return 0.0;
} else if (rawValue > m_maxPwm) {
return 1.0;
}
return (rawValue - m_minPwm).to<double>() /
GetFullRangeScaleFactor().to<double>();
}
void Servo::SetAngle(double degrees) {
@@ -46,19 +57,11 @@ void Servo::SetAngle(double degrees) {
degrees = kMaxServoAngle;
}
SetPosition((degrees - kMinServoAngle) / GetServoAngleRange());
Set((degrees - kMinServoAngle) / GetServoAngleRange());
}
double Servo::GetAngle() const {
return GetPosition() * GetServoAngleRange() + kMinServoAngle;
}
double Servo::GetMaxAngle() const {
return kMaxServoAngle;
}
double Servo::GetMinAngle() const {
return kMinServoAngle;
return Get() * GetServoAngleRange() + kMinServoAngle;
}
void Servo::InitSendable(wpi::SendableBuilder& builder) {
@@ -68,6 +71,14 @@ void Servo::InitSendable(wpi::SendableBuilder& builder) {
[=, this](double value) { Set(value); });
}
double Servo::GetServoAngleRange() const {
double Servo::GetServoAngleRange() {
return kMaxServoAngle - kMinServoAngle;
}
units::microsecond_t Servo::GetFullRangeScaleFactor() const {
return m_maxPwm - m_minPwm;
}
int Servo::GetChannel() const {
return m_pwm.GetChannel();
}

View File

@@ -18,7 +18,7 @@ void PWMMotorController::Set(double speed) {
if (m_isInverted) {
speed = -speed;
}
m_pwm.SetSpeed(speed);
SetSpeed(speed);
for (auto& follower : m_nonowningFollowers) {
follower->Set(speed);
@@ -36,7 +36,7 @@ void PWMMotorController::SetVoltage(units::volt_t output) {
}
double PWMMotorController::Get() const {
return m_pwm.GetSpeed() * (m_isInverted ? -1.0 : 1.0);
return GetSpeed() * (m_isInverted ? -1.0 : 1.0);
}
units::volt_t PWMMotorController::GetVoltage() const {
@@ -64,7 +64,11 @@ void PWMMotorController::Disable() {
void PWMMotorController::StopMotor() {
// Don't use Set(0) as that will feed the watch kitty
m_pwm.SetSpeed(0);
m_pwm.SetPulseTime(0_us);
if (m_simSpeed) {
m_simSpeed.Set(0.0);
}
for (auto& follower : m_nonowningFollowers) {
follower->StopMotor();
@@ -83,7 +87,7 @@ int PWMMotorController::GetChannel() const {
}
void PWMMotorController::EnableDeadbandElimination(bool eliminateDeadband) {
m_pwm.EnableDeadbandElimination(eliminateDeadband);
m_eliminateDeadband = eliminateDeadband;
}
void PWMMotorController::AddFollower(PWMMotorController& follower) {
@@ -95,6 +99,12 @@ WPI_IGNORE_DEPRECATED
PWMMotorController::PWMMotorController(std::string_view name, int channel)
: m_pwm(channel, false) {
wpi::SendableRegistry::Add(this, name, channel);
m_simDevice = hal::SimDevice{"PWMMotorController", channel};
if (m_simDevice) {
m_simSpeed = m_simDevice.CreateDouble("Speed", true, 0.0);
m_pwm.SetSimDevice(m_simDevice);
}
}
WPI_UNIGNORE_DEPRECATED
@@ -106,3 +116,86 @@ void PWMMotorController::InitSendable(wpi::SendableBuilder& builder) {
"Value", [=, this] { return Get(); },
[=, this](double value) { Set(value); });
}
units::microsecond_t PWMMotorController::GetMinPositivePwm() const {
if (m_eliminateDeadband) {
return m_deadbandMaxPwm;
} else {
return m_centerPwm + 1_us;
}
}
units::microsecond_t PWMMotorController::GetMaxNegativePwm() const {
if (m_eliminateDeadband) {
return m_deadbandMinPwm;
} else {
return m_centerPwm - 1_us;
}
}
units::microsecond_t PWMMotorController::GetPositiveScaleFactor() const {
return m_maxPwm - GetMinPositivePwm();
}
units::microsecond_t PWMMotorController::GetNegativeScaleFactor() const {
return GetMaxNegativePwm() - m_minPwm;
}
void PWMMotorController::SetSpeed(double speed) {
if (std::isfinite(speed)) {
speed = std::clamp(speed, -1.0, 1.0);
} else {
speed = 0.0;
}
if (m_simSpeed) {
m_simSpeed.Set(speed);
}
units::microsecond_t rawValue;
if (speed == 0.0) {
rawValue = m_centerPwm;
} else if (speed > 0.0) {
rawValue = units::microsecond_t{static_cast<double>(std::lround(
(speed * GetPositiveScaleFactor()).to<double>()))} +
GetMinPositivePwm();
} else {
rawValue = units::microsecond_t{static_cast<double>(std::lround(
(speed * GetNegativeScaleFactor()).to<double>()))} +
GetMaxNegativePwm();
}
m_pwm.SetPulseTime(rawValue);
}
double PWMMotorController::GetSpeed() const {
units::microsecond_t rawValue = m_pwm.GetPulseTime();
if (rawValue == 0_us) {
return 0.0;
} else if (rawValue > m_maxPwm) {
return 1.0;
} else if (rawValue < m_minPwm) {
return -1.0;
} else if (rawValue > GetMinPositivePwm()) {
return ((rawValue - GetMinPositivePwm()) / GetPositiveScaleFactor())
.to<double>();
} else if (rawValue < GetMaxNegativePwm()) {
return ((rawValue - GetMaxNegativePwm()) / GetNegativeScaleFactor())
.to<double>();
} else {
return 0.0;
}
}
void PWMMotorController::SetBounds(units::microsecond_t maxPwm,
units::microsecond_t deadbandMaxPwm,
units::microsecond_t centerPwm,
units::microsecond_t deadbandMinPwm,
units::microsecond_t minPwm) {
m_maxPwm = maxPwm;
m_deadbandMaxPwm = deadbandMaxPwm;
m_centerPwm = centerPwm;
m_deadbandMinPwm = deadbandMinPwm;
m_minPwm = minPwm;
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/simulation/PWMMotorControllerSim.h"
#include <hal/SimDevice.h>
#include <units/length.h>
#include "frc/simulation/SimDeviceSim.h"
using namespace frc;
using namespace frc::sim;
PWMMotorControllerSim::PWMMotorControllerSim(
const PWMMotorController& motorctrl)
: PWMMotorControllerSim(motorctrl.GetChannel()) {}
PWMMotorControllerSim::PWMMotorControllerSim(int channel) {
frc::sim::SimDeviceSim deviceSim{"PWMMotorController", channel};
m_simSpeed = deviceSim.GetDouble("Speed");
}
double PWMMotorControllerSim::GetSpeed() const {
return m_simSpeed.Get();
}

View File

@@ -16,9 +16,6 @@ using namespace frc::sim;
PWMSim::PWMSim(const PWM& pwm) : m_index{pwm.GetChannel()} {}
PWMSim::PWMSim(const PWMMotorController& motorctrl)
: m_index{motorctrl.GetChannel()} {}
PWMSim::PWMSim(int channel) : m_index{channel} {}
std::unique_ptr<CallbackStore> PWMSim::RegisterInitializedCallback(
@@ -55,72 +52,21 @@ void PWMSim::SetPulseMicrosecond(int32_t microsecondPulseTime) {
HALSIM_SetPWMPulseMicrosecond(m_index, microsecondPulseTime);
}
std::unique_ptr<CallbackStore> PWMSim::RegisterSpeedCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(m_index, -1, callback,
&HALSIM_CancelPWMSpeedCallback);
store->SetUid(HALSIM_RegisterPWMSpeedCallback(m_index, &CallbackStoreThunk,
store.get(), initialNotify));
return store;
}
double PWMSim::GetSpeed() const {
return HALSIM_GetPWMSpeed(m_index);
}
void PWMSim::SetSpeed(double speed) {
HALSIM_SetPWMSpeed(m_index, speed);
}
std::unique_ptr<CallbackStore> PWMSim::RegisterPositionCallback(
std::unique_ptr<CallbackStore> PWMSim::RegisterOutputPeriodCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, -1, callback, &HALSIM_CancelPWMPositionCallback);
store->SetUid(HALSIM_RegisterPWMPositionCallback(m_index, &CallbackStoreThunk,
store.get(), initialNotify));
return store;
}
double PWMSim::GetPosition() const {
return HALSIM_GetPWMPosition(m_index);
}
void PWMSim::SetPosition(double position) {
HALSIM_SetPWMPosition(m_index, position);
}
std::unique_ptr<CallbackStore> PWMSim::RegisterPeriodScaleCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, -1, callback, &HALSIM_CancelPWMPeriodScaleCallback);
store->SetUid(HALSIM_RegisterPWMPeriodScaleCallback(
m_index, -1, callback, &HALSIM_CancelPWMOutputPeriodCallback);
store->SetUid(HALSIM_RegisterPWMOutputPeriodCallback(
m_index, &CallbackStoreThunk, store.get(), initialNotify));
return store;
}
int PWMSim::GetPeriodScale() const {
return HALSIM_GetPWMPeriodScale(m_index);
int PWMSim::GetOutputPeriod() const {
return HALSIM_GetPWMOutputPeriod(m_index);
}
void PWMSim::SetPeriodScale(int periodScale) {
HALSIM_SetPWMPeriodScale(m_index, periodScale);
}
std::unique_ptr<CallbackStore> PWMSim::RegisterZeroLatchCallback(
NotifyCallback callback, bool initialNotify) {
auto store = std::make_unique<CallbackStore>(
m_index, -1, callback, &HALSIM_CancelPWMZeroLatchCallback);
store->SetUid(HALSIM_RegisterPWMZeroLatchCallback(
m_index, &CallbackStoreThunk, store.get(), initialNotify));
return store;
}
bool PWMSim::GetZeroLatch() const {
return HALSIM_GetPWMZeroLatch(m_index);
}
void PWMSim::SetZeroLatch(bool zeroLatch) {
HALSIM_SetPWMZeroLatch(m_index, zeroLatch);
void PWMSim::SetOutputPeriod(int period) {
HALSIM_SetPWMOutputPeriod(m_index, period);
}
void PWMSim::ResetData() {

View File

@@ -0,0 +1,28 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/simulation/ServoSim.h"
#include <hal/SimDevice.h>
#include <units/length.h>
#include "frc/simulation/SimDeviceSim.h"
using namespace frc;
using namespace frc::sim;
ServoSim::ServoSim(const Servo& servo) : ServoSim(servo.GetChannel()) {}
ServoSim::ServoSim(int channel) {
frc::sim::SimDeviceSim deviceSim{"Servo", channel};
m_simPosition = deviceSim.GetDouble("Position");
}
double ServoSim::GetPosition() const {
return m_simPosition.Get();
}
double ServoSim::GetAngle() const {
return GetPosition() * Servo::GetServoAngleRange() + Servo::kMinServoAngle;
}

View File

@@ -27,21 +27,21 @@ class PWM : public wpi::Sendable, public wpi::SendableHelper<PWM> {
public:
friend class AddressableLED;
/**
* Represents the amount to multiply the minimum servo-pulse pwm period by.
* Represents the output period in microseconds.
*/
enum PeriodMultiplier {
enum OutputPeriod {
/**
* Don't skip pulses. PWM pulses occur every 5.05 ms
* PWM pulses occur every 5 ms
*/
kPeriodMultiplier_1X = 1,
kOutputPeriod_5Ms = 1,
/**
* Skip every other pulse. PWM pulses occur every 10.10 ms
* PWM pulses occur every 10 ms
*/
kPeriodMultiplier_2X = 2,
kOutputPeriod_10Ms = 2,
/**
* Skip three out of four pulses. PWM pulses occur every 20.20 ms
* PWM pulses occur every 20 ms
*/
kPeriodMultiplier_4X = 4
kOutputPeriod_20Ms = 4
};
/**
@@ -74,7 +74,7 @@ class PWM : public wpi::Sendable, public wpi::SendableHelper<PWM> {
*
* @param time Microsecond PWM value.
*/
virtual void SetPulseTime(units::microsecond_t time);
void SetPulseTime(units::microsecond_t time);
/**
* Get the PWM pulse time directly from the hardware.
@@ -83,122 +83,30 @@ class PWM : public wpi::Sendable, public wpi::SendableHelper<PWM> {
*
* @return Microsecond PWM control value.
*/
virtual units::microsecond_t GetPulseTime() const;
/**
* Set the PWM value based on a position.
*
* This is intended to be used by servos.
*
* @pre SetBounds() called.
*
* @param pos The position to set the servo between 0.0 and 1.0.
*/
virtual void SetPosition(double pos);
/**
* Get the PWM value in terms of a position.
*
* This is intended to be used by servos.
*
* @pre SetBounds() called.
*
* @return The position the servo is set to between 0.0 and 1.0.
*/
virtual double GetPosition() const;
/**
* Set the PWM value based on a speed.
*
* This is intended to be used by motor controllers.
*
* @pre SetBounds() called.
*
* @param speed The speed to set the motor controller between -1.0 and 1.0.
*/
virtual void SetSpeed(double speed);
/**
* Get the PWM value in terms of speed.
*
* This is intended to be used by motor controllers.
*
* @pre SetBounds() called.
*
* @return The most recently set speed between -1.0 and 1.0.
*/
virtual double GetSpeed() const;
units::microsecond_t GetPulseTime() const;
/**
* Temporarily disables the PWM output. The next set call will re-enable
* the output.
*/
virtual void SetDisabled();
void SetDisabled();
/**
* Slow down the PWM signal for old devices.
* Sets the PWM output period.
*
* @param mult The period multiplier to apply to this channel
* @param mult The output period to apply to this channel
*/
void SetPeriodMultiplier(PeriodMultiplier mult);
/**
* Latches PWM to zero.
*/
void SetZeroLatch();
/**
* Optionally eliminate the deadband from a motor controller.
*
* @param eliminateDeadband If true, set the motor curve on the motor
* controller to eliminate the deadband in the middle
* of the range. Otherwise, keep the full range
* without modifying any values.
*/
void EnableDeadbandElimination(bool eliminateDeadband);
/**
* Set the bounds on the PWM pulse widths.
*
* This sets the bounds on the PWM values for a particular type of controller.
* The values determine the upper and lower speeds as well as the deadband
* bracket.
*
* @param max The max PWM pulse width in us
* @param deadbandMax The high end of the deadband range pulse width in us
* @param center The center (off) pulse width in us
* @param deadbandMin The low end of the deadband pulse width in us
* @param min The minimum pulse width in us
*/
void SetBounds(units::microsecond_t max, units::microsecond_t deadbandMax,
units::microsecond_t center, units::microsecond_t deadbandMin,
units::microsecond_t min);
/**
* Get the bounds on the PWM values.
*
* This gets the bounds on the PWM values for a particular each type of
* controller. The values determine the upper and lower speeds as well as the
* deadband bracket.
*
* @param max The maximum pwm value
* @param deadbandMax The high end of the deadband range
* @param center The center speed (off)
* @param deadbandMin The low end of the deadband range
* @param min The minimum pwm value
*/
void GetBounds(units::microsecond_t* max, units::microsecond_t* deadbandMax,
units::microsecond_t* center,
units::microsecond_t* deadbandMin, units::microsecond_t* min);
/**
* Sets the PWM output to be a continuous high signal while enabled.
*
*/
void SetAlwaysHighMode();
void SetOutputPeriod(OutputPeriod mult);
int GetChannel() const;
/**
* Indicates this input is used by a simulated device.
*
* @param device simulated device handle
*/
void SetSimDevice(HAL_SimDeviceHandle device);
protected:
void InitSendable(wpi::SendableBuilder& builder) override;

View File

@@ -4,20 +4,27 @@
#pragma once
#include <hal/SimDevice.h>
#include <units/angle.h>
#include "frc/PWM.h"
namespace frc {
namespace sim {
class ServoSim;
} // namespace sim
/**
* Standard hobby style servo.
*
* The range parameters default to the appropriate values for the Hitec HS-322HD
* servo provided in the FIRST Kit of Parts in 2008.
*/
class Servo : public PWM {
class Servo : public wpi::Sendable, public wpi::SendableHelper<Servo> {
public:
friend class frc::sim::ServoSim;
/**
* Constructor.
*
@@ -42,13 +49,6 @@ class Servo : public PWM {
*/
void Set(double value);
/**
* Set the servo to offline.
*
* Set the servo raw value to 0 (undriven)
*/
void SetOffline();
/**
* Get the servo position.
*
@@ -86,30 +86,27 @@ class Servo : public PWM {
*/
double GetAngle() const;
/**
* Get the maximum angle of the servo.
*
* @return The maximum angle of the servo in degrees.
*/
double GetMaxAngle() const;
/**
* Get the minimum angle of the servo.
*
* @return The minimum angle of the servo in degrees.
*/
double GetMinAngle() const;
int GetChannel() const;
void InitSendable(wpi::SendableBuilder& builder) override;
private:
double GetServoAngleRange() const;
static double GetServoAngleRange();
units::microsecond_t GetFullRangeScaleFactor() const;
static constexpr double kMaxServoAngle = 180.;
static constexpr double kMaxServoAngle = 180.0;
static constexpr double kMinServoAngle = 0.0;
static constexpr units::millisecond_t kDefaultMaxServoPWM = 2.4_ms;
static constexpr units::millisecond_t kDefaultMinServoPWM = 0.6_ms;
units::millisecond_t m_maxPwm = kDefaultMaxServoPWM;
units::millisecond_t m_minPwm = kDefaultMinServoPWM;
hal::SimDevice m_simDevice;
hal::SimDouble m_simPosition;
PWM m_pwm;
};
} // namespace frc

View File

@@ -12,6 +12,7 @@
#include <utility>
#include <vector>
#include <hal/SimDevice.h>
#include <units/voltage.h>
#include <wpi/deprecated.h>
#include <wpi/sendable/Sendable.h>
@@ -133,11 +134,35 @@ class PWMMotorController : public MotorController,
/// PWM instances for motor controller.
PWM m_pwm;
void SetSpeed(double speed);
double GetSpeed() const;
void SetBounds(units::microsecond_t maxPwm,
units::microsecond_t deadbandMaxPwm,
units::microsecond_t centerPwm,
units::microsecond_t deadbandMinPwm,
units::microsecond_t minPwm);
private:
bool m_isInverted = false;
std::vector<PWMMotorController*> m_nonowningFollowers;
std::vector<std::unique_ptr<PWMMotorController>> m_owningFollowers;
hal::SimDevice m_simDevice;
hal::SimDouble m_simSpeed;
bool m_eliminateDeadband{0};
units::microsecond_t m_minPwm{0};
units::microsecond_t m_deadbandMinPwm{0};
units::microsecond_t m_centerPwm{0};
units::microsecond_t m_deadbandMaxPwm{0};
units::microsecond_t m_maxPwm{0};
units::microsecond_t GetMinPositivePwm() const;
units::microsecond_t GetMaxNegativePwm() const;
units::microsecond_t GetPositiveScaleFactor() const;
units::microsecond_t GetNegativeScaleFactor() const;
PWM* GetPwm() { return &m_pwm; }
};

View File

@@ -0,0 +1,30 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <hal/SimDevice.h>
#include <units/length.h>
#include "frc/motorcontrol/PWMMotorController.h"
namespace frc {
class PWMMotorController;
namespace sim {
class PWMMotorControllerSim {
public:
explicit PWMMotorControllerSim(const PWMMotorController& motorctrl);
explicit PWMMotorControllerSim(int channel);
double GetSpeed() const;
private:
hal::SimDouble m_simSpeed;
};
} // namespace sim
} // namespace frc

View File

@@ -27,13 +27,6 @@ class PWMSim {
*/
explicit PWMSim(const PWM& pwm);
/**
* Constructs from a PWMMotorController object.
*
* @param motorctrl PWMMotorController to simulate
*/
explicit PWMSim(const PWMMotorController& motorctrl);
/**
* Constructs from a PWM channel number.
*
@@ -91,56 +84,6 @@ class PWMSim {
*/
void SetPulseMicrosecond(int32_t microsecondPulseTime);
/**
* Register a callback to be run when the PWM speed changes.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial value
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]]
std::unique_ptr<CallbackStore> RegisterSpeedCallback(NotifyCallback callback,
bool initialNotify);
/**
* Get the PWM speed.
*
* @return the PWM speed (-1.0 to 1.0)
*/
double GetSpeed() const;
/**
* Set the PWM speed.
*
* @param speed the PWM speed (-1.0 to 1.0)
*/
void SetSpeed(double speed);
/**
* Register a callback to be run when the PWM position changes.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial value
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]]
std::unique_ptr<CallbackStore> RegisterPositionCallback(
NotifyCallback callback, bool initialNotify);
/**
* Get the PWM position.
*
* @return the PWM position (0.0 to 1.0)
*/
double GetPosition() const;
/**
* Set the PWM position.
*
* @param position the PWM position (0.0 to 1.0)
*/
void SetPosition(double position);
/**
* Register a callback to be run when the PWM period scale changes.
*
@@ -149,7 +92,7 @@ class PWMSim {
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]]
std::unique_ptr<CallbackStore> RegisterPeriodScaleCallback(
std::unique_ptr<CallbackStore> RegisterOutputPeriodCallback(
NotifyCallback callback, bool initialNotify);
/**
@@ -157,39 +100,14 @@ class PWMSim {
*
* @return the PWM period scale
*/
int GetPeriodScale() const;
int GetOutputPeriod() const;
/**
* Set the PWM period scale.
*
* @param periodScale the PWM period scale
* @param period the PWM period scale
*/
void SetPeriodScale(int periodScale);
/**
* Register a callback to be run when the PWM zero latch state changes.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial state
* @return the CallbackStore object associated with this callback
*/
[[nodiscard]]
std::unique_ptr<CallbackStore> RegisterZeroLatchCallback(
NotifyCallback callback, bool initialNotify);
/**
* Check whether the PWM is zero latched.
*
* @return true if zero latched
*/
bool GetZeroLatch() const;
/**
* Define whether the PWM has been zero latched.
*
* @param zeroLatch true to indicate zero latched
*/
void SetZeroLatch(bool zeroLatch);
void SetOutputPeriod(int period);
/**
* Reset all simulation data.

View File

@@ -0,0 +1,31 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <hal/SimDevice.h>
#include <units/length.h>
#include "frc/Servo.h"
namespace frc {
class Servo;
namespace sim {
class ServoSim {
public:
explicit ServoSim(const Servo& servo);
explicit ServoSim(int channel);
double GetPosition() const;
double GetAngle() const;
private:
hal::SimDouble m_simPosition;
};
} // namespace sim
} // namespace frc

View File

@@ -0,0 +1,26 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/simulation/PWMMotorControllerSim.h" // NOLINT(build/include_order)
#include <gtest/gtest.h>
#include <hal/HAL.h>
#include "frc/motorcontrol/Spark.h"
namespace frc::sim {
TEST(PWMMotorControllerSimTest, TestMotor) {
frc::Spark spark{0};
frc::sim::PWMMotorControllerSim sim{spark};
spark.Set(0);
EXPECT_EQ(0, sim.GetSpeed());
spark.Set(0.354);
EXPECT_EQ(0.354, sim.GetSpeed());
spark.Set(-0.785);
EXPECT_EQ(-0.785, sim.GetSpeed());
}
} // namespace frc::sim

View File

@@ -12,8 +12,6 @@
namespace frc::sim {
constexpr double kPWMStepSize = 1.0 / 2000.0;
TEST(PWMSimTest, Initialize) {
HAL_Initialize(500, 0);
@@ -46,115 +44,7 @@ TEST(PWMSimTest, SetPulseTime) {
EXPECT_EQ(2290, callback.GetLastValue());
}
TEST(PWMSimTest, SetSpeed) {
HAL_Initialize(500, 0);
PWMSim sim{0};
sim.ResetData();
EXPECT_FALSE(sim.GetInitialized());
DoubleCallback callback;
auto cb = sim.RegisterSpeedCallback(callback.GetCallback(), false);
PWM pwm{0};
double kTestValue = 0.3504;
pwm.SetSpeed(kTestValue);
EXPECT_NEAR(kTestValue, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetSpeed(), kPWMStepSize);
EXPECT_TRUE(callback.WasTriggered());
EXPECT_NEAR(kTestValue, callback.GetLastValue(), kPWMStepSize);
EXPECT_NEAR(kTestValue / 2 + 0.5, sim.GetPosition(), kPWMStepSize * 2);
EXPECT_NEAR(kTestValue / 2 + 0.5, pwm.GetPosition(), kPWMStepSize * 2);
kTestValue = -1.0;
pwm.SetSpeed(kTestValue);
EXPECT_NEAR(kTestValue, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(0.0, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(0.0, pwm.GetPosition(), kPWMStepSize);
kTestValue = 0.0;
pwm.SetSpeed(kTestValue);
EXPECT_NEAR(kTestValue, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(0.5, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(0.5, pwm.GetPosition(), kPWMStepSize);
kTestValue = 1.0;
pwm.SetSpeed(kTestValue);
EXPECT_NEAR(kTestValue, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(kTestValue, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetPosition(), kPWMStepSize);
kTestValue = 1.1;
pwm.SetSpeed(kTestValue);
EXPECT_NEAR(1.0, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(1.0, pwm.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(1.0, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(1.0, pwm.GetPosition(), kPWMStepSize);
}
TEST(PWMSimTest, SetPosition) {
HAL_Initialize(500, 0);
PWMSim sim{0};
sim.ResetData();
EXPECT_FALSE(sim.GetInitialized());
DoubleCallback callback;
auto cb = sim.RegisterPositionCallback(callback.GetCallback(), false);
PWM pwm{0};
double kTestValue = 0.3504;
pwm.SetPosition(kTestValue);
EXPECT_NEAR(kTestValue, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetPosition(), kPWMStepSize);
EXPECT_TRUE(callback.WasTriggered());
EXPECT_NEAR(kTestValue, callback.GetLastValue(), kPWMStepSize);
EXPECT_NEAR(kTestValue * 2 - 1.0, sim.GetSpeed(), kPWMStepSize * 2);
EXPECT_NEAR(kTestValue * 2 - 1.0, pwm.GetSpeed(), kPWMStepSize * 2);
kTestValue = -1.0;
pwm.SetPosition(kTestValue);
EXPECT_NEAR(0.0, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(0.0, pwm.GetPosition(), kPWMStepSize);
EXPECT_NEAR(kTestValue, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetSpeed(), kPWMStepSize);
kTestValue = 0.0;
pwm.SetPosition(kTestValue);
EXPECT_NEAR(kTestValue, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetPosition(), kPWMStepSize);
EXPECT_NEAR(-1.0, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(-1.0, pwm.GetSpeed(), kPWMStepSize);
kTestValue = 1.0;
pwm.SetPosition(kTestValue);
EXPECT_NEAR(kTestValue, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetPosition(), kPWMStepSize);
EXPECT_NEAR(kTestValue, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(kTestValue, pwm.GetSpeed(), kPWMStepSize);
kTestValue = 1.1;
pwm.SetPosition(kTestValue);
EXPECT_NEAR(1.0, sim.GetPosition(), kPWMStepSize);
EXPECT_NEAR(1.0, pwm.GetPosition(), kPWMStepSize);
EXPECT_NEAR(1.0, sim.GetSpeed(), kPWMStepSize);
EXPECT_NEAR(1.0, pwm.GetSpeed(), kPWMStepSize);
}
TEST(PWMSimTest, SetPeriodScale) {
TEST(PWMSimTest, SetOutputPeriod) {
HAL_Initialize(500, 0);
PWMSim sim{0};
@@ -163,28 +53,12 @@ TEST(PWMSimTest, SetPeriodScale) {
IntCallback callback;
auto cb = sim.RegisterPeriodScaleCallback(callback.GetCallback(), false);
auto cb = sim.RegisterOutputPeriodCallback(callback.GetCallback(), false);
PWM pwm{0};
sim.SetPeriodScale(3504);
EXPECT_EQ(3504, sim.GetPeriodScale());
sim.SetOutputPeriod(3504);
EXPECT_EQ(3504, sim.GetOutputPeriod());
EXPECT_TRUE(callback.WasTriggered());
EXPECT_EQ(3504, callback.GetLastValue());
}
TEST(PWMSimTest, SetZeroLatch) {
HAL_Initialize(500, 0);
PWMSim sim{0};
sim.ResetData();
EXPECT_FALSE(sim.GetInitialized());
BooleanCallback callback;
auto cb = sim.RegisterZeroLatchCallback(callback.GetCallback(), false);
PWM pwm{0};
pwm.SetZeroLatch();
EXPECT_TRUE(callback.WasTriggered());
}
} // namespace frc::sim

View File

@@ -0,0 +1,32 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "frc/simulation/ServoSim.h" // NOLINT(build/include_order)
#include <gtest/gtest.h>
#include <hal/HAL.h>
#include "frc/Servo.h"
namespace frc::sim {
TEST(ServoSimTest, TestServo) {
frc::Servo servo{0};
frc::sim::ServoSim sim{servo};
servo.Set(0);
EXPECT_EQ(0, sim.GetPosition());
servo.Set(0.354);
EXPECT_EQ(0.354, sim.GetPosition());
servo.SetAngle(10);
EXPECT_EQ(10, sim.GetAngle());
servo.SetAngle(90);
EXPECT_EQ(90, sim.GetAngle());
servo.SetAngle(170);
EXPECT_EQ(170, sim.GetAngle());
}
} // namespace frc::sim

View File

@@ -11,7 +11,7 @@
#include <frc/simulation/BatterySim.h>
#include <frc/simulation/ElevatorSim.h>
#include <frc/simulation/EncoderSim.h>
#include <frc/simulation/PWMSim.h>
#include <frc/simulation/PWMMotorControllerSim.h>
#include <frc/simulation/RoboRioSim.h>
#include <frc/smartdashboard/Mechanism2d.h>
#include <frc/smartdashboard/MechanismLigament2d.h>
@@ -50,7 +50,7 @@ class Elevator {
frc::Encoder m_encoder{Constants::kEncoderAChannel,
Constants::kEncoderBChannel};
frc::PWMSparkMax m_motor{Constants::kMotorPort};
frc::sim::PWMSim m_motorSim{m_motor};
frc::sim::PWMMotorControllerSim m_motorSim{m_motor};
// Simulation classes help us simulate what's going on, including gravity.
frc::sim::ElevatorSim m_elevatorSim{m_elevatorGearbox,

View File

@@ -12,7 +12,7 @@
#include <frc/simulation/BatterySim.h>
#include <frc/simulation/ElevatorSim.h>
#include <frc/simulation/EncoderSim.h>
#include <frc/simulation/PWMSim.h>
#include <frc/simulation/PWMMotorControllerSim.h>
#include <frc/simulation/RoboRioSim.h>
#include <frc/smartdashboard/Mechanism2d.h>
#include <frc/smartdashboard/MechanismLigament2d.h>
@@ -46,7 +46,7 @@ class Elevator {
frc::Encoder m_encoder{Constants::kEncoderAChannel,
Constants::kEncoderBChannel};
frc::PWMSparkMax m_motor{Constants::kMotorPort};
frc::sim::PWMSim m_motorSim{m_motor};
frc::sim::PWMMotorControllerSim m_motorSim{m_motor};
// Simulation classes help us simulate what's going on, including gravity.
frc::sim::ElevatorSim m_elevatorSim{m_elevatorGearbox,

View File

@@ -70,9 +70,6 @@ int main(void) {
return 1;
}
// Set PWM config to standard servo speeds
HAL_SetPWMConfigMicroseconds(pwmPort, 2000, 1501, 1500, 1499, 1000, &status);
// Create an Input
status = 0;
HAL_DigitalHandle dio = HAL_InitializeDIOPort(2, 1, NULL, &status);
@@ -105,9 +102,9 @@ int main(void) {
case TeleopMode:
status = 0;
if (HAL_GetDIO(dio, &status)) {
HAL_SetPWMSpeed(pwmPort, 1.0, &status);
HAL_SetPWMPulseTimeMicroseconds(pwmPort, 2000, &status);
} else {
HAL_SetPWMSpeed(pwmPort, 0, &status);
HAL_SetPWMPulseTimeMicroseconds(pwmPort, 1500, &status);
}
break;
case AutoMode:

View File

@@ -8,7 +8,7 @@
#include <frc/Preferences.h>
#include <frc/simulation/DriverStationSim.h>
#include <frc/simulation/JoystickSim.h>
#include <frc/simulation/PWMSim.h>
#include <frc/simulation/PWMMotorControllerSim.h>
#include <frc/simulation/SimHooks.h>
#include <gtest/gtest.h>
#include <hal/simulation/MockHooks.h>
@@ -23,7 +23,7 @@ class ArmSimulationTest : public testing::TestWithParam<units::degree_t> {
std::optional<std::thread> m_thread;
protected:
frc::sim::PWMSim m_motorSim{kMotorPort};
frc::sim::PWMMotorControllerSim m_motorSim{kMotorPort};
frc::sim::EncoderSim m_encoderSim =
frc::sim::EncoderSim::CreateForChannel(kEncoderAChannel);
frc::sim::JoystickSim m_joystickSim{kJoystickPort};
@@ -41,7 +41,6 @@ class ArmSimulationTest : public testing::TestWithParam<units::degree_t> {
m_thread->join();
m_encoderSim.ResetData();
m_motorSim.ResetData();
frc::sim::DriverStationSim::ResetData();
frc::Preferences::RemoveAll();
}
@@ -61,7 +60,6 @@ TEST_P(ArmSimulationTest, Teleop) {
frc::sim::DriverStationSim::SetEnabled(true);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(m_motorSim.GetInitialized());
EXPECT_TRUE(m_encoderSim.GetInitialized());
}

View File

@@ -7,7 +7,7 @@
#include <frc/simulation/DriverStationSim.h>
#include <frc/simulation/JoystickSim.h>
#include <frc/simulation/PWMSim.h>
#include <frc/simulation/PWMMotorControllerSim.h>
#include <frc/simulation/SimHooks.h>
#include <gtest/gtest.h>
#include <hal/simulation/MockHooks.h>
@@ -25,7 +25,7 @@ class ElevatorSimulationTest : public testing::Test {
std::optional<std::thread> m_thread;
protected:
frc::sim::PWMSim m_motorSim{Constants::kMotorPort};
frc::sim::PWMMotorControllerSim m_motorSim{Constants::kMotorPort};
frc::sim::EncoderSim m_encoderSim =
frc::sim::EncoderSim::CreateForChannel(Constants::kEncoderAChannel);
frc::sim::JoystickSim m_joystickSim{Constants::kJoystickPort};
@@ -43,7 +43,6 @@ class ElevatorSimulationTest : public testing::Test {
m_thread->join();
m_encoderSim.ResetData();
m_motorSim.ResetData();
frc::sim::DriverStationSim::ResetData();
}
};
@@ -55,7 +54,6 @@ TEST_F(ElevatorSimulationTest, Teleop) {
frc::sim::DriverStationSim::SetEnabled(true);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(m_motorSim.GetInitialized());
EXPECT_TRUE(m_encoderSim.GetInitialized());
}

View File

@@ -10,7 +10,7 @@
#include <frc/simulation/DriverStationSim.h>
#include <frc/simulation/ElevatorSim.h>
#include <frc/simulation/JoystickSim.h>
#include <frc/simulation/PWMSim.h>
#include <frc/simulation/PWMMotorControllerSim.h>
#include <frc/simulation/SimHooks.h>
#include <frc/system/plant/DCMotor.h>
#include <gtest/gtest.h>
@@ -39,7 +39,7 @@ class PotentiometerPIDTest : public testing::Test {
Robot::kFullHeight,
true,
0.0_m};
frc::sim::PWMSim m_motorSim{Robot::kMotorChannel};
frc::sim::PWMMotorControllerSim m_motorSim{Robot::kMotorChannel};
frc::sim::AnalogInputSim m_analogSim{Robot::kPotChannel};
frc::sim::JoystickSim m_joystickSim{Robot::kJoystickChannel};
int32_t m_callback;
@@ -85,7 +85,6 @@ class PotentiometerPIDTest : public testing::Test {
HALSIM_CancelSimPeriodicBeforeCallback(m_callback);
m_analogSim.ResetData();
m_motorSim.ResetData();
}
};
@@ -96,7 +95,6 @@ TEST_F(PotentiometerPIDTest, Teleop) {
frc::sim::DriverStationSim::SetEnabled(true);
frc::sim::DriverStationSim::NotifyNewData();
EXPECT_TRUE(m_motorSim.GetInitialized());
EXPECT_TRUE(m_analogSim.GetInitialized());
}

View File

@@ -4,7 +4,7 @@
#include <frc/DoubleSolenoid.h>
#include <frc/simulation/DoubleSolenoidSim.h>
#include <frc/simulation/PWMSim.h>
#include <frc/simulation/PWMMotorControllerSim.h>
#include <gtest/gtest.h>
#include "Constants.h"
@@ -13,7 +13,7 @@
class IntakeTest : public testing::Test {
protected:
Intake intake; // create our intake
frc::sim::PWMSim simMotor{
frc::sim::PWMMotorControllerSim simMotor{
IntakeConstants::kMotorPort}; // create our simulation PWM
frc::sim::DoubleSolenoidSim simPiston{
frc::PneumaticsModuleType::CTREPCM, IntakeConstants::kPistonFwdChannel,

View File

@@ -37,10 +37,9 @@ public class {{ name }} extends PWMMotorController {
public {{ name }}(final int channel) {
super("{{ name }}", channel);
m_pwm.setBoundsMicroseconds({{ (pulse_width_ms.max * 1000) | int }}, {{ (pulse_width_ms.deadbandMax * 1000) | int }}, {{ (pulse_width_ms.center * 1000) | int }}, {{ (pulse_width_ms.deadbandMin * 1000) | int }}, {{ (pulse_width_ms.min * 1000) | int }});
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k{{ PeriodMultiplier | default("1", true)}}X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds({{ (pulse_width_ms.max * 1000) | int }}, {{ (pulse_width_ms.deadbandMax * 1000) | int }}, {{ (pulse_width_ms.center * 1000) | int }}, {{ (pulse_width_ms.deadbandMin * 1000) | int }}, {{ (pulse_width_ms.min * 1000) | int }});
m_pwm.setOutputPeriod(PWM.OutputPeriod.k{{ OutputPeriod | default("5", true)}}Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "{{ ResourceName }}");
}

View File

@@ -147,7 +147,7 @@
"Manufacturer": "Vex Robotics",
"DisplayName": "Victor 888",
"ResourceName": "Victor",
"PeriodMultiplier": 2,
"OutputPeriod": 10,
"pulse_width_ms": {
"max": 2.027,
"deadbandMax": 1.525,
@@ -174,7 +174,7 @@
"Manufacturer": "AndyMark",
"DisplayName": "Koors40",
"ResourceName": "Koors40",
"PeriodMultiplier": 4,
"OutputPeriod": 20,
"pulse_width_ms": {
"max": 2.004,
"deadbandMax": 1.520,

View File

@@ -37,10 +37,9 @@ public class DMC60 extends PWMMotorController {
public DMC60(final int channel) {
super("DMC60", channel);
m_pwm.setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "DigilentDMC60");
}

View File

@@ -37,10 +37,9 @@ public class Jaguar extends PWMMotorController {
public Jaguar(final int channel) {
super("Jaguar", channel);
m_pwm.setBoundsMicroseconds(2310, 1550, 1507, 1454, 697);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2310, 1550, 1507, 1454, 697);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "Jaguar");
}

View File

@@ -37,10 +37,9 @@ public class Koors40 extends PWMMotorController {
public Koors40(final int channel) {
super("Koors40", channel);
m_pwm.setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k4X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k20Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "Koors40");
}

View File

@@ -37,10 +37,9 @@ public class PWMSparkFlex extends PWMMotorController {
public PWMSparkFlex(final int channel) {
super("PWMSparkFlex", channel);
m_pwm.setBoundsMicroseconds(2003, 1550, 1500, 1460, 999);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2003, 1550, 1500, 1460, 999);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "RevSparkFlexPWM");
}

View File

@@ -37,10 +37,9 @@ public class PWMSparkMax extends PWMMotorController {
public PWMSparkMax(final int channel) {
super("PWMSparkMax", channel);
m_pwm.setBoundsMicroseconds(2003, 1550, 1500, 1460, 999);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2003, 1550, 1500, 1460, 999);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "RevSparkMaxPWM");
}

View File

@@ -37,10 +37,9 @@ public class PWMTalonFX extends PWMMotorController {
public PWMTalonFX(final int channel) {
super("PWMTalonFX", channel);
m_pwm.setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "TalonFX");
}

View File

@@ -37,10 +37,9 @@ public class PWMTalonSRX extends PWMMotorController {
public PWMTalonSRX(final int channel) {
super("PWMTalonSRX", channel);
m_pwm.setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "PWMTalonSRX");
}

View File

@@ -37,10 +37,9 @@ public class PWMVenom extends PWMMotorController {
public PWMVenom(final int channel) {
super("PWMVenom", channel);
m_pwm.setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "FusionVenom");
}

View File

@@ -37,10 +37,9 @@ public class PWMVictorSPX extends PWMMotorController {
public PWMVictorSPX(final int channel) {
super("PWMVictorSPX", channel);
m_pwm.setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "PWMVictorSPX");
}

View File

@@ -37,10 +37,9 @@ public class SD540 extends PWMMotorController {
public SD540(final int channel) {
super("SD540", channel);
m_pwm.setBoundsMicroseconds(2050, 1550, 1500, 1440, 940);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2050, 1550, 1500, 1440, 940);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "MindsensorsSD540");
}

View File

@@ -37,10 +37,9 @@ public class Spark extends PWMMotorController {
public Spark(final int channel) {
super("Spark", channel);
m_pwm.setBoundsMicroseconds(2003, 1550, 1500, 1460, 999);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2003, 1550, 1500, 1460, 999);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "RevSPARK");
}

View File

@@ -37,10 +37,9 @@ public class SparkMini extends PWMMotorController {
public SparkMini(final int channel) {
super("SparkMini", channel);
m_pwm.setBoundsMicroseconds(2500, 1510, 1500, 1490, 500);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2500, 1510, 1500, 1490, 500);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "RevSPARK");
}

View File

@@ -37,10 +37,9 @@ public class Talon extends PWMMotorController {
public Talon(final int channel) {
super("Talon", channel);
m_pwm.setBoundsMicroseconds(2037, 1539, 1513, 1487, 989);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2037, 1539, 1513, 1487, 989);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "Talon");
}

View File

@@ -37,10 +37,9 @@ public class Victor extends PWMMotorController {
public Victor(final int channel) {
super("Victor", channel);
m_pwm.setBoundsMicroseconds(2027, 1525, 1507, 1490, 1026);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k2X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2027, 1525, 1507, 1490, 1026);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k10Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "Victor");
}

View File

@@ -37,10 +37,9 @@ public class VictorSP extends PWMMotorController {
public VictorSP(final int channel) {
super("VictorSP", channel);
m_pwm.setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
m_pwm.setSpeed(0.0);
m_pwm.setZeroLatch();
setBoundsMicroseconds(2004, 1520, 1500, 1480, 997);
m_pwm.setOutputPeriod(PWM.OutputPeriod.k5Ms);
setSpeed(0.0);
HAL.reportUsage("IO", getChannel(), "VictorSP");
}

View File

@@ -5,8 +5,8 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.PWMConfigDataResult;
import edu.wpi.first.hal.PWMJNI;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.util.sendable.Sendable;
import edu.wpi.first.util.sendable.SendableBuilder;
import edu.wpi.first.util.sendable.SendableRegistry;
@@ -19,14 +19,14 @@ import edu.wpi.first.util.sendable.SendableRegistry;
* sent to the FPGA, and the update occurs at the next FPGA cycle (5.05ms). There is no delay.
*/
public class PWM implements Sendable, AutoCloseable {
/** Represents the amount to multiply the minimum servo-pulse pwm period by. */
public enum PeriodMultiplier {
/** Period Multiplier: don't skip pulses. PWM pulses occur every 5.05 ms */
k1X,
/** Period Multiplier: skip every other pulse. PWM pulses occur every 10.10 ms */
k2X,
/** Period Multiplier: skip three out of four pulses. PWM pulses occur every 20.20 ms */
k4X
/** Represents the output period in microseconds. */
public enum OutputPeriod {
/** Pulse every 5ms. */
k5Ms,
/** Pulse every 10ms. */
k10Ms,
/** Pulse every 20ms. */
k20Ms
}
private final int m_channel;
@@ -62,8 +62,6 @@ public class PWM implements Sendable, AutoCloseable {
setDisabled();
PWMJNI.setPWMEliminateDeadband(m_handle, false);
HAL.reportUsage("IO", channel, "PWM");
if (registerSendable) {
SendableRegistry.add(this, "PWM", channel);
@@ -82,44 +80,6 @@ public class PWM implements Sendable, AutoCloseable {
m_handle = 0;
}
/**
* Optionally eliminate the deadband from a motor controller.
*
* @param eliminateDeadband If true, set the motor curve for the motor controller to eliminate the
* deadband in the middle of the range. Otherwise, keep the full range without modifying any
* values.
*/
public void enableDeadbandElimination(boolean eliminateDeadband) {
PWMJNI.setPWMEliminateDeadband(m_handle, eliminateDeadband);
}
/**
* Set the bounds on the PWM pulse widths. This sets the bounds on the PWM values for a particular
* type of controller. The values determine the upper and lower speeds as well as the deadband
* bracket.
*
* @param max The max PWM pulse width in us
* @param deadbandMax The high end of the deadband range pulse width in us
* @param center The center (off) pulse width in us
* @param deadbandMin The low end of the deadband pulse width in us
* @param min The minimum pulse width in us
*/
public void setBoundsMicroseconds(
int max, int deadbandMax, int center, int deadbandMin, int min) {
PWMJNI.setPWMConfigMicroseconds(m_handle, max, deadbandMax, center, deadbandMin, min);
}
/**
* Gets the bounds on the PWM pulse widths. This gets the bounds on the PWM values for a
* particular type of controller. The values determine the upper and lower speeds as well as the
* deadband bracket.
*
* @return The bounds on the PWM pulse widths.
*/
public PWMConfigDataResult getBoundsMicroseconds() {
return PWMJNI.getPWMConfigMicroseconds(m_handle);
}
/**
* Gets the channel number associated with the PWM Object.
*
@@ -129,54 +89,6 @@ public class PWM implements Sendable, AutoCloseable {
return m_channel;
}
/**
* Set the PWM value based on a position.
*
* <p>This is intended to be used by servos.
*
* @param pos The position to set the servo between 0.0 and 1.0.
* @pre setBoundsMicroseconds() called.
*/
public void setPosition(double pos) {
PWMJNI.setPWMPosition(m_handle, pos);
}
/**
* Get the PWM value in terms of a position.
*
* <p>This is intended to be used by servos.
*
* @return The position the servo is set to between 0.0 and 1.0.
* @pre setBoundsMicroseconds() called.
*/
public double getPosition() {
return PWMJNI.getPWMPosition(m_handle);
}
/**
* Set the PWM value based on a speed.
*
* <p>This is intended to be used by motor controllers.
*
* @param speed The speed to set the motor controller between -1.0 and 1.0.
* @pre setBoundsMicroseconds() called.
*/
public void setSpeed(double speed) {
PWMJNI.setPWMSpeed(m_handle, speed);
}
/**
* Get the PWM value in terms of speed.
*
* <p>This is intended to be used by motor controllers.
*
* @return The most recently set speed between -1.0 and 1.0.
* @pre setBoundsMicroseconds() called.
*/
public double getSpeed() {
return PWMJNI.getPWMSpeed(m_handle);
}
/**
* Set the PWM value directly to the hardware.
*
@@ -201,33 +113,23 @@ public class PWM implements Sendable, AutoCloseable {
/** Temporarily disables the PWM output. The next set call will re-enable the output. */
public final void setDisabled() {
PWMJNI.setPWMDisabled(m_handle);
setPulseTimeMicroseconds(0);
}
/**
* Slow down the PWM signal for old devices.
* Sets the PWM output period.
*
* @param mult The period multiplier to apply to this channel
* @param mult The output period to apply to this channel
*/
public void setPeriodMultiplier(PeriodMultiplier mult) {
public void setOutputPeriod(OutputPeriod mult) {
int scale =
switch (mult) {
case k4X -> 3; // Squelch 3 out of 4 outputs
case k2X -> 1; // Squelch 1 out of 2 outputs
case k1X -> 0; // Don't squelch any outputs
case k20Ms -> 3;
case k10Ms -> 1;
case k5Ms -> 0;
};
PWMJNI.setPWMPeriodScale(m_handle, scale);
}
/** Latches PWM to zero. */
public void setZeroLatch() {
PWMJNI.latchPWMZero(m_handle);
}
/** Sets the PWM output to be a continuous high signal while enabled. */
public void setAlwaysHighMode() {
PWMJNI.setAlwaysHighMode(m_handle);
PWMJNI.setPWMOutputPeriod(m_handle, scale);
}
/**
@@ -239,13 +141,20 @@ public class PWM implements Sendable, AutoCloseable {
return m_handle;
}
/**
* Indicates this input is used by a simulated device.
*
* @param device simulated device handle
*/
public void setSimDevice(SimDevice device) {
PWMJNI.setPWMSimDevice(m_handle, device.getNativeHandle());
}
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("PWM");
builder.setActuator(true);
builder.addDoubleProperty(
"Value", this::getPulseTimeMicroseconds, value -> setPulseTimeMicroseconds((int) value));
builder.addDoubleProperty("Speed", this::getSpeed, this::setSpeed);
builder.addDoubleProperty("Position", this::getPosition, this::setPosition);
}
}

View File

@@ -5,8 +5,14 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDevice.Direction;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.math.MathUtil;
import edu.wpi.first.util.sendable.Sendable;
import edu.wpi.first.util.sendable.SendableBuilder;
import edu.wpi.first.util.sendable.SendableRegistry;
import edu.wpi.first.wpilibj.PWM.OutputPeriod;
/**
* Standard hobby style servo.
@@ -14,13 +20,21 @@ import edu.wpi.first.util.sendable.SendableRegistry;
* <p>The range parameters default to the appropriate values for the Hitec HS-322HD servo provided
* in the FIRST Kit of Parts in 2008.
*/
public class Servo extends PWM {
public class Servo implements Sendable, AutoCloseable {
private static final double kMaxServoAngle = 180.0;
private static final double kMinServoAngle = 0.0;
private static final int kDefaultMaxServoPWM = 2400;
private static final int kDefaultMinServoPWM = 600;
private final PWM m_pwm;
private SimDevice m_simDevice;
private SimDouble m_simPosition;
private static final int m_minPwm = kDefaultMinServoPWM;
private static final int m_maxPwm = kDefaultMaxServoPWM;
/**
* Constructor.
*
@@ -32,12 +46,31 @@ public class Servo extends PWM {
*/
@SuppressWarnings("this-escape")
public Servo(final int channel) {
super(channel);
setBoundsMicroseconds(kDefaultMaxServoPWM, 0, 0, 0, kDefaultMinServoPWM);
setPeriodMultiplier(PeriodMultiplier.k4X);
m_pwm = new PWM(channel, false);
SendableRegistry.add(this, "Servo", channel);
HAL.reportUsage("IO", getChannel(), "Servo");
SendableRegistry.setName(this, "Servo", getChannel());
m_pwm.setOutputPeriod(OutputPeriod.k20Ms);
HAL.reportUsage("IO", channel, "Servo");
m_simDevice = SimDevice.create("Servo", channel);
if (m_simDevice != null) {
m_simPosition = m_simDevice.createDouble("Position", Direction.kOutput, 0.0);
m_pwm.setSimDevice(m_simDevice);
}
}
/** Free the resource associated with the PWM channel and set the value to 0. */
@Override
public void close() {
SendableRegistry.remove(this);
m_pwm.close();
if (m_simDevice != null) {
m_simDevice.close();
m_simDevice = null;
m_simPosition = null;
}
}
/**
@@ -48,7 +81,15 @@ public class Servo extends PWM {
* @param value Position from 0.0 to 1.0.
*/
public void set(double value) {
setPosition(value);
value = MathUtil.clamp(value, 0.0, 1.0);
if (m_simPosition != null) {
m_simPosition.set(value);
}
int rawValue = (int) ((value * getFullRangeScaleFactor()) + m_minPwm);
m_pwm.setPulseTimeMicroseconds(rawValue);
}
/**
@@ -61,7 +102,14 @@ public class Servo extends PWM {
* @return Position from 0.0 to 1.0.
*/
public double get() {
return getPosition();
int rawValue = m_pwm.getPulseTimeMicroseconds();
if (rawValue < m_minPwm) {
return 0.0;
} else if (rawValue > m_maxPwm) {
return 1.0;
}
return (rawValue - m_minPwm) / getFullRangeScaleFactor();
}
/**
@@ -83,7 +131,7 @@ public class Servo extends PWM {
degrees = kMaxServoAngle;
}
setPosition((degrees - kMinServoAngle) / getServoAngleRange());
set((degrees - kMinServoAngle) / getServoAngleRange());
}
/**
@@ -95,7 +143,29 @@ public class Servo extends PWM {
* @return The angle in degrees to which the servo is set.
*/
public double getAngle() {
return getPosition() * getServoAngleRange() + kMinServoAngle;
return get() * getServoAngleRange() + kMinServoAngle;
}
/**
* Gets the backing PWM handle.
*
* @return The pwm handle.
*/
public int getPwmHandle() {
return m_pwm.getHandle();
}
/**
* Gets the PWM channel number.
*
* @return The channel number.
*/
public int getChannel() {
return m_pwm.getChannel();
}
private double getFullRangeScaleFactor() {
return m_maxPwm - m_minPwm;
}
private double getServoAngleRange() {

View File

@@ -4,6 +4,10 @@
package edu.wpi.first.wpilibj.motorcontrol;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDevice.Direction;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.math.MathUtil;
import edu.wpi.first.util.sendable.Sendable;
import edu.wpi.first.util.sendable.SendableBuilder;
import edu.wpi.first.util.sendable.SendableRegistry;
@@ -22,6 +26,16 @@ public abstract class PWMMotorController extends MotorSafety
/** PWM instances for motor controller. */
protected PWM m_pwm;
private SimDevice m_simDevice;
private SimDouble m_simSpeed;
private boolean m_eliminateDeadband;
private int m_minPwm;
private int m_deadbandMinPwm;
private int m_centerPwm;
private int m_deadbandMaxPwm;
private int m_maxPwm;
/**
* Constructor.
*
@@ -33,6 +47,12 @@ public abstract class PWMMotorController extends MotorSafety
protected PWMMotorController(final String name, final int channel) {
m_pwm = new PWM(channel, false);
SendableRegistry.add(this, name, channel);
m_simDevice = SimDevice.create("PWMMotorController", channel);
if (m_simDevice != null) {
m_simSpeed = m_simDevice.createDouble("Speed", Direction.kOutput, 0.0);
m_pwm.setSimDevice(m_simDevice);
}
}
/** Free the resource associated with the PWM channel and set the value to 0. */
@@ -40,6 +60,105 @@ public abstract class PWMMotorController extends MotorSafety
public void close() {
SendableRegistry.remove(this);
m_pwm.close();
if (m_simDevice != null) {
m_simDevice.close();
m_simDevice = null;
m_simSpeed = null;
}
}
private int getMinPositivePwm() {
if (m_eliminateDeadband) {
return m_deadbandMaxPwm;
} else {
return m_centerPwm + 1;
}
}
private int getMaxNegativePwm() {
if (m_eliminateDeadband) {
return m_deadbandMinPwm;
} else {
return m_centerPwm - 1;
}
}
private int getPositiveScaleFactor() {
return m_maxPwm - getMinPositivePwm();
}
private int getNegativeScaleFactor() {
return getMaxNegativePwm() - m_minPwm;
}
/**
* Takes a speed from -1 to 1, and outputs it in the microsecond format.
*
* @param speed the speed to output
*/
protected final void setSpeed(double speed) {
if (Double.isFinite(speed)) {
speed = MathUtil.clamp(speed, -1.0, 1.0);
} else {
speed = 0.0;
}
if (m_simSpeed != null) {
m_simSpeed.set(speed);
}
int rawValue;
if (speed == 0.0) {
rawValue = m_centerPwm;
} else if (speed > 0.0) {
rawValue = (int) Math.round(speed * getPositiveScaleFactor()) + getMinPositivePwm();
} else {
rawValue = (int) Math.round(speed * getNegativeScaleFactor()) + getMaxNegativePwm();
}
m_pwm.setPulseTimeMicroseconds(rawValue);
}
/**
* Gets the speed from -1 to 1, from the currently set pulse time.
*
* @return motor controller speed
*/
protected final double getSpeed() {
int rawValue = m_pwm.getPulseTimeMicroseconds();
if (rawValue == 0) {
return 0.0;
} else if (rawValue > m_maxPwm) {
return 1.0;
} else if (rawValue < m_minPwm) {
return -1.0;
} else if (rawValue > getMinPositivePwm()) {
return (rawValue - getMinPositivePwm()) / (double) getPositiveScaleFactor();
} else if (rawValue < getMaxNegativePwm()) {
return (rawValue - getMaxNegativePwm()) / (double) getNegativeScaleFactor();
} else {
return 0.0;
}
}
/**
* Sets the bounds in microseconds for the controller.
*
* @param maxPwm maximum
* @param deadbandMaxPwm deadband max
* @param centerPwm center
* @param deadbandMinPwm deadmand min
* @param minPwm minimum
*/
protected final void setBoundsMicroseconds(
int maxPwm, int deadbandMaxPwm, int centerPwm, int deadbandMinPwm, int minPwm) {
m_maxPwm = maxPwm;
m_deadbandMaxPwm = deadbandMaxPwm;
m_centerPwm = centerPwm;
m_deadbandMinPwm = deadbandMinPwm;
m_minPwm = minPwm;
}
/**
@@ -55,7 +174,7 @@ public abstract class PWMMotorController extends MotorSafety
if (m_isInverted) {
speed = -speed;
}
m_pwm.setSpeed(speed);
setSpeed(speed);
for (var follower : m_followers) {
follower.set(speed);
@@ -65,15 +184,13 @@ public abstract class PWMMotorController extends MotorSafety
}
/**
* Get the recently set value of the PWM. This value is affected by the inversion property. If you
* want the value that is sent directly to the MotorController, use {@link
* edu.wpi.first.wpilibj.PWM#getSpeed()} instead.
* Get the recently set value of the PWM. This value is affected by the inversion property.
*
* @return The most recently set value for the PWM between -1.0 and 1.0.
*/
@Override
public double get() {
return m_pwm.getSpeed() * (m_isInverted ? -1.0 : 1.0);
return getSpeed() * (m_isInverted ? -1.0 : 1.0);
}
/**
@@ -99,6 +216,10 @@ public abstract class PWMMotorController extends MotorSafety
public void disable() {
m_pwm.setDisabled();
if (m_simSpeed != null) {
m_simSpeed.set(0.0);
}
for (var follower : m_followers) {
follower.disable();
}
@@ -107,7 +228,7 @@ public abstract class PWMMotorController extends MotorSafety
@Override
public void stopMotor() {
// Don't use set(0) as that will feed the watch kitty
m_pwm.setSpeed(0);
m_pwm.setPulseTimeMicroseconds(0);
for (var follower : m_followers) {
follower.stopMotor();
@@ -145,7 +266,7 @@ public abstract class PWMMotorController extends MotorSafety
* values.
*/
public void enableDeadbandElimination(boolean eliminateDeadband) {
m_pwm.enableDeadbandElimination(eliminateDeadband);
m_eliminateDeadband = eliminateDeadband;
}
/**

View File

@@ -0,0 +1,41 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.wpilibj.motorcontrol.PWMMotorController;
/** Class to control a simulated PWM motor controller. */
public class PWMMotorControllerSim {
private final SimDouble m_simSpeed;
/**
* Constructor.
*
* @param motorctrl The device to simulate
*/
public PWMMotorControllerSim(PWMMotorController motorctrl) {
this(motorctrl.getChannel());
}
/**
* Constructor.
*
* @param channel The channel the motor controller is attached to.
*/
public PWMMotorControllerSim(int channel) {
SimDeviceSim simDevice = new SimDeviceSim("PWMMotorController", channel);
m_simSpeed = simDevice.getDouble("Speed");
}
/**
* Gets the motor speed set.
*
* @return Speed
*/
public double getSpeed() {
return m_simSpeed.get();
}
}

View File

@@ -7,7 +7,6 @@ package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.hal.simulation.PWMDataJNI;
import edu.wpi.first.wpilibj.PWM;
import edu.wpi.first.wpilibj.motorcontrol.PWMMotorController;
/** Class to control a simulated PWM output. */
public class PWMSim {
@@ -22,15 +21,6 @@ public class PWMSim {
m_index = pwm.getChannel();
}
/**
* Constructs from a PWMMotorController object.
*
* @param motorctrl PWMMotorController to simulate
*/
public PWMSim(PWMMotorController motorctrl) {
m_index = motorctrl.getChannel();
}
/**
* Constructs from a PWM channel number.
*
@@ -101,66 +91,6 @@ public class PWMSim {
PWMDataJNI.setPulseMicrosecond(m_index, microsecondPulseTime);
}
/**
* Register a callback to be run when the PWM speed changes.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial value
* @return the {@link CallbackStore} object associated with this callback.
*/
public CallbackStore registerSpeedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerSpeedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelSpeedCallback);
}
/**
* Get the PWM speed.
*
* @return the PWM speed (-1.0 to 1.0)
*/
public double getSpeed() {
return PWMDataJNI.getSpeed(m_index);
}
/**
* Set the PWM speed.
*
* @param speed the PWM speed (-1.0 to 1.0)
*/
public void setSpeed(double speed) {
PWMDataJNI.setSpeed(m_index, speed);
}
/**
* Register a callback to be run when the PWM position changes.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial value
* @return the {@link CallbackStore} object associated with this callback.
*/
public CallbackStore registerPositionCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerPositionCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelPositionCallback);
}
/**
* Get the PWM position.
*
* @return the PWM position (0.0 to 1.0)
*/
public double getPosition() {
return PWMDataJNI.getPosition(m_index);
}
/**
* Set the PWM position.
*
* @param position the PWM position (0.0 to 1.0)
*/
public void setPosition(double position) {
PWMDataJNI.setPosition(m_index, position);
}
/**
* Register a callback to be run when the PWM period scale changes.
*
@@ -168,9 +98,10 @@ public class PWMSim {
* @param initialNotify whether to run the callback with the initial value
* @return the {@link CallbackStore} object associated with this callback.
*/
public CallbackStore registerPeriodScaleCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerPeriodScaleCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelPeriodScaleCallback);
public CallbackStore registerOutputPeriodCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerOutputPeriodCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelOutputPeriodCallback);
}
/**
@@ -178,47 +109,17 @@ public class PWMSim {
*
* @return the PWM period scale
*/
public int getPeriodScale() {
return PWMDataJNI.getPeriodScale(m_index);
public int getOutputPeriod() {
return PWMDataJNI.getOutputPeriod(m_index);
}
/**
* Set the PWM period scale.
*
* @param periodScale the PWM period scale
* @param period the PWM period scale
*/
public void setPeriodScale(int periodScale) {
PWMDataJNI.setPeriodScale(m_index, periodScale);
}
/**
* Register a callback to be run when the PWM zero latch state changes.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial state
* @return the {@link CallbackStore} object associated with this callback.
*/
public CallbackStore registerZeroLatchCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerZeroLatchCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelZeroLatchCallback);
}
/**
* Check whether the PWM is zero latched.
*
* @return true if zero latched
*/
public boolean getZeroLatch() {
return PWMDataJNI.getZeroLatch(m_index);
}
/**
* Define whether the PWM has been zero latched.
*
* @param zeroLatch true to indicate zero latched
*/
public void setZeroLatch(boolean zeroLatch) {
PWMDataJNI.setZeroLatch(m_index, zeroLatch);
public void setOutputPeriod(int period) {
PWMDataJNI.setOutputPeriod(m_index, period);
}
/** Reset all simulation data. */

View File

@@ -0,0 +1,50 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.wpilibj.Servo;
/** Class to control a simulated Servo. */
public class ServoSim {
private final SimDouble m_simPosition;
/**
* Constructor.
*
* @param servo The device to simulate
*/
public ServoSim(Servo servo) {
this(servo.getChannel());
}
/**
* Constructor.
*
* @param channel The channel the servo is attached to.
*/
public ServoSim(int channel) {
SimDeviceSim simDevice = new SimDeviceSim("Servo", channel);
m_simPosition = simDevice.getDouble("Position");
}
/**
* Gets the position set.
*
* @return Position
*/
public double getPosition() {
return m_simPosition.get();
}
/**
* Gets the angle set.
*
* @return Angle
*/
public double getAngle() {
return getPosition() * 180.0;
}
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import static org.junit.jupiter.api.Assertions.assertEquals;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.wpilibj.motorcontrol.Spark;
import org.junit.jupiter.api.Test;
class PWMMotorControllerSimTest {
@Test
void testMotor() {
HAL.initialize(500, 0);
try (Spark spark = new Spark(0)) {
PWMMotorControllerSim sim = new PWMMotorControllerSim(spark);
spark.set(0);
assertEquals(0, sim.getSpeed());
spark.set(0.354);
assertEquals(0.354, sim.getSpeed());
spark.set(-0.785);
assertEquals(-0.785, sim.getSpeed());
}
}
}

View File

@@ -11,13 +11,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.wpilibj.PWM;
import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
import edu.wpi.first.wpilibj.simulation.testutils.IntCallback;
import org.junit.jupiter.api.Test;
class PWMSimTest {
private static final double PWM_STEP_SIZE = 1.0 / 2000.0;
@Test
void testInitialize() {
HAL.initialize(500, 0);
@@ -55,119 +52,7 @@ class PWMSimTest {
}
@Test
void testSetSpeed() {
HAL.initialize(500, 0);
PWMSim sim = new PWMSim(0);
sim.resetData();
assertFalse(sim.getInitialized());
DoubleCallback callback = new DoubleCallback();
try (CallbackStore cb = sim.registerSpeedCallback(callback, false);
PWM pwm = new PWM(0)) {
double kTestValue = 0.3504;
pwm.setSpeed(kTestValue);
assertEquals(kTestValue, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getSpeed(), PWM_STEP_SIZE);
assertTrue(callback.wasTriggered());
assertEquals(kTestValue, callback.getSetValue(), PWM_STEP_SIZE);
assertEquals(kTestValue / 2 + 0.5, sim.getPosition(), PWM_STEP_SIZE * 2);
assertEquals(kTestValue / 2 + 0.5, pwm.getPosition(), PWM_STEP_SIZE * 2);
kTestValue = -1.0;
pwm.setSpeed(kTestValue);
assertEquals(kTestValue, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getSpeed(), PWM_STEP_SIZE);
assertEquals(0.0, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(0.0, pwm.getPosition(), PWM_STEP_SIZE);
kTestValue = 0.0;
pwm.setSpeed(kTestValue);
assertEquals(kTestValue, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getSpeed(), PWM_STEP_SIZE);
assertEquals(0.5, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(0.5, pwm.getPosition(), PWM_STEP_SIZE);
kTestValue = 1.0;
pwm.setSpeed(kTestValue);
assertEquals(kTestValue, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getSpeed(), PWM_STEP_SIZE);
assertEquals(kTestValue, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getPosition(), PWM_STEP_SIZE);
kTestValue = 1.1;
pwm.setSpeed(kTestValue);
assertEquals(1.0, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(1.0, pwm.getSpeed(), PWM_STEP_SIZE);
assertEquals(1.0, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(1.0, pwm.getPosition(), PWM_STEP_SIZE);
}
}
@Test
void testSetPosition() {
HAL.initialize(500, 0);
PWMSim sim = new PWMSim(0);
sim.resetData();
assertFalse(sim.getInitialized());
DoubleCallback callback = new DoubleCallback();
try (CallbackStore cb = sim.registerPositionCallback(callback, false);
PWM pwm = new PWM(0)) {
double kTestValue = 0.3504;
pwm.setPosition(kTestValue);
assertEquals(kTestValue, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getPosition(), PWM_STEP_SIZE);
assertTrue(callback.wasTriggered());
assertEquals(kTestValue, callback.getSetValue(), PWM_STEP_SIZE);
assertEquals(kTestValue * 2 - 1.0, sim.getSpeed(), PWM_STEP_SIZE * 2);
assertEquals(kTestValue * 2 - 1.0, pwm.getSpeed(), PWM_STEP_SIZE * 2);
kTestValue = -1.0;
pwm.setPosition(kTestValue);
assertEquals(0.0, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(0.0, pwm.getPosition(), PWM_STEP_SIZE);
assertEquals(kTestValue, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getSpeed(), PWM_STEP_SIZE);
kTestValue = 0.0;
pwm.setPosition(kTestValue);
assertEquals(kTestValue, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getPosition(), PWM_STEP_SIZE);
assertEquals(-1.0, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(-1.0, pwm.getSpeed(), PWM_STEP_SIZE);
kTestValue = 1.0;
pwm.setPosition(kTestValue);
assertEquals(kTestValue, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getPosition(), PWM_STEP_SIZE);
assertEquals(kTestValue, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(kTestValue, pwm.getSpeed(), PWM_STEP_SIZE);
kTestValue = 1.1;
pwm.setPosition(kTestValue);
assertEquals(1.0, sim.getPosition(), PWM_STEP_SIZE);
assertEquals(1.0, pwm.getPosition(), PWM_STEP_SIZE);
assertEquals(1.0, sim.getSpeed(), PWM_STEP_SIZE);
assertEquals(1.0, pwm.getSpeed(), PWM_STEP_SIZE);
}
}
@Test
void testSetPeriodScale() {
void testSetOutputPeriod() {
HAL.initialize(500, 0);
PWMSim sim = new PWMSim(0);
@@ -176,30 +61,12 @@ class PWMSimTest {
IntCallback callback = new IntCallback();
try (CallbackStore cb = sim.registerPeriodScaleCallback(callback, false);
try (CallbackStore cb = sim.registerOutputPeriodCallback(callback, false);
PWM pwm = new PWM(0)) {
sim.setPeriodScale(3504);
assertEquals(3504, sim.getPeriodScale());
sim.setOutputPeriod(3504);
assertEquals(3504, sim.getOutputPeriod());
assertTrue(callback.wasTriggered());
assertEquals(3504, callback.getSetValue());
}
}
@Test
void testSetZeroLatch() {
HAL.initialize(500, 0);
PWMSim sim = new PWMSim(0);
sim.resetData();
assertFalse(sim.getInitialized());
BooleanCallback callback = new BooleanCallback();
try (CallbackStore cb = sim.registerZeroLatchCallback(callback, false);
PWM pwm = new PWM(0)) {
pwm.setZeroLatch();
assertTrue(callback.wasTriggered());
}
}
}

View File

@@ -0,0 +1,37 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import static org.junit.jupiter.api.Assertions.assertEquals;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.wpilibj.Servo;
import org.junit.jupiter.api.Test;
class ServoSimTest {
@Test
void testServo() {
HAL.initialize(500, 0);
try (Servo servo = new Servo(0)) {
ServoSim sim = new ServoSim(servo);
servo.set(0);
assertEquals(0, sim.getPosition());
servo.set(0.354);
assertEquals(0.354, sim.getPosition());
servo.setAngle(10);
assertEquals(10, sim.getAngle());
servo.setAngle(90);
assertEquals(90, sim.getAngle());
servo.setAngle(170);
assertEquals(170, sim.getAngle());
}
}
}

View File

@@ -16,7 +16,7 @@ import edu.wpi.first.wpilibj.motorcontrol.PWMSparkMax;
import edu.wpi.first.wpilibj.simulation.BatterySim;
import edu.wpi.first.wpilibj.simulation.ElevatorSim;
import edu.wpi.first.wpilibj.simulation.EncoderSim;
import edu.wpi.first.wpilibj.simulation.PWMSim;
import edu.wpi.first.wpilibj.simulation.PWMMotorControllerSim;
import edu.wpi.first.wpilibj.simulation.RoboRioSim;
import edu.wpi.first.wpilibj.smartdashboard.Mechanism2d;
import edu.wpi.first.wpilibj.smartdashboard.MechanismLigament2d;
@@ -62,7 +62,7 @@ public class Elevator implements AutoCloseable {
0.005,
0.0);
private final EncoderSim m_encoderSim = new EncoderSim(m_encoder);
private final PWMSim m_motorSim = new PWMSim(m_motor);
private final PWMMotorControllerSim m_motorSim = new PWMMotorControllerSim(m_motor);
// Create a Mechanism2d visualization of the elevator
private final Mechanism2d m_mech2d =

View File

@@ -15,7 +15,7 @@ import edu.wpi.first.wpilibj.motorcontrol.PWMSparkMax;
import edu.wpi.first.wpilibj.simulation.BatterySim;
import edu.wpi.first.wpilibj.simulation.ElevatorSim;
import edu.wpi.first.wpilibj.simulation.EncoderSim;
import edu.wpi.first.wpilibj.simulation.PWMSim;
import edu.wpi.first.wpilibj.simulation.PWMMotorControllerSim;
import edu.wpi.first.wpilibj.simulation.RoboRioSim;
import edu.wpi.first.wpilibj.smartdashboard.Mechanism2d;
import edu.wpi.first.wpilibj.smartdashboard.MechanismLigament2d;
@@ -57,7 +57,7 @@ public class Elevator implements AutoCloseable {
0.01,
0.0);
private final EncoderSim m_encoderSim = new EncoderSim(m_encoder);
private final PWMSim m_motorSim = new PWMSim(m_motor);
private final PWMMotorControllerSim m_motorSim = new PWMMotorControllerSim(m_motor);
// Create a Mechanism2d visualization of the elevator
private final Mechanism2d m_mech2d = new Mechanism2d(20, 50);

View File

@@ -13,7 +13,7 @@ import edu.wpi.first.wpilibj.Preferences;
import edu.wpi.first.wpilibj.simulation.DriverStationSim;
import edu.wpi.first.wpilibj.simulation.EncoderSim;
import edu.wpi.first.wpilibj.simulation.JoystickSim;
import edu.wpi.first.wpilibj.simulation.PWMSim;
import edu.wpi.first.wpilibj.simulation.PWMMotorControllerSim;
import edu.wpi.first.wpilibj.simulation.RoboRioSim;
import edu.wpi.first.wpilibj.simulation.SimHooks;
import org.junit.jupiter.api.AfterEach;
@@ -27,7 +27,7 @@ class ArmSimulationTest {
private Robot m_robot;
private Thread m_thread;
private PWMSim m_motorSim;
private PWMMotorControllerSim m_motorSim;
private EncoderSim m_encoderSim;
private JoystickSim m_joystickSim;
@@ -39,7 +39,7 @@ class ArmSimulationTest {
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
m_encoderSim = EncoderSim.createForChannel(Constants.kEncoderAChannel);
m_motorSim = new PWMSim(Constants.kMotorPort);
m_motorSim = new PWMMotorControllerSim(Constants.kMotorPort);
m_joystickSim = new JoystickSim(Constants.kJoystickPort);
m_thread.start();
@@ -57,7 +57,6 @@ class ArmSimulationTest {
}
m_robot.close();
m_encoderSim.resetData();
m_motorSim.resetData();
Preferences.remove(Constants.kArmPKey);
Preferences.remove(Constants.kArmPositionKey);
Preferences.removeAll();
@@ -79,7 +78,6 @@ class ArmSimulationTest {
DriverStationSim.setEnabled(true);
DriverStationSim.notifyNewData();
assertTrue(m_motorSim.getInitialized());
assertTrue(m_encoderSim.getInitialized());
}

View File

@@ -11,7 +11,7 @@ import edu.wpi.first.hal.HAL;
import edu.wpi.first.wpilibj.simulation.DriverStationSim;
import edu.wpi.first.wpilibj.simulation.EncoderSim;
import edu.wpi.first.wpilibj.simulation.JoystickSim;
import edu.wpi.first.wpilibj.simulation.PWMSim;
import edu.wpi.first.wpilibj.simulation.PWMMotorControllerSim;
import edu.wpi.first.wpilibj.simulation.RoboRioSim;
import edu.wpi.first.wpilibj.simulation.SimHooks;
import org.junit.jupiter.api.AfterEach;
@@ -24,7 +24,7 @@ class ElevatorSimulationTest {
private Robot m_robot;
private Thread m_thread;
private PWMSim m_motorSim;
private PWMMotorControllerSim m_motorSim;
private EncoderSim m_encoderSim;
private JoystickSim m_joystickSim;
@@ -36,7 +36,7 @@ class ElevatorSimulationTest {
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
m_encoderSim = EncoderSim.createForChannel(Constants.kEncoderAChannel);
m_motorSim = new PWMSim(Constants.kMotorPort);
m_motorSim = new PWMMotorControllerSim(Constants.kMotorPort);
m_joystickSim = new JoystickSim(Constants.kJoystickPort);
m_thread.start();
@@ -54,7 +54,6 @@ class ElevatorSimulationTest {
}
m_robot.close();
m_encoderSim.resetData();
m_motorSim.resetData();
RoboRioSim.resetData();
DriverStationSim.resetData();
DriverStationSim.notifyNewData();
@@ -68,7 +67,6 @@ class ElevatorSimulationTest {
DriverStationSim.setEnabled(true);
DriverStationSim.notifyNewData();
assertTrue(m_motorSim.getInitialized());
assertTrue(m_encoderSim.getInitialized());
}

View File

@@ -16,7 +16,7 @@ import edu.wpi.first.wpilibj.simulation.AnalogInputSim;
import edu.wpi.first.wpilibj.simulation.DriverStationSim;
import edu.wpi.first.wpilibj.simulation.ElevatorSim;
import edu.wpi.first.wpilibj.simulation.JoystickSim;
import edu.wpi.first.wpilibj.simulation.PWMSim;
import edu.wpi.first.wpilibj.simulation.PWMMotorControllerSim;
import edu.wpi.first.wpilibj.simulation.SimHooks;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -34,7 +34,7 @@ class PotentiometerPIDTest {
private Thread m_thread;
private ElevatorSim m_elevatorSim;
private PWMSim m_motorSim;
private PWMMotorControllerSim m_motorSim;
private AnalogInputSim m_analogSim;
private SimPeriodicBeforeCallback m_callback;
private JoystickSim m_joystickSim;
@@ -57,7 +57,7 @@ class PotentiometerPIDTest {
true,
0);
m_analogSim = new AnalogInputSim(Robot.kPotChannel);
m_motorSim = new PWMSim(Robot.kMotorChannel);
m_motorSim = new PWMMotorControllerSim(Robot.kMotorChannel);
m_joystickSim = new JoystickSim(Robot.kJoystickChannel);
m_callback =
@@ -93,7 +93,6 @@ class PotentiometerPIDTest {
m_robot.close();
m_callback.close();
m_analogSim.resetData();
m_motorSim.resetData();
}
@Test
@@ -104,7 +103,6 @@ class PotentiometerPIDTest {
DriverStationSim.setEnabled(true);
DriverStationSim.notifyNewData();
assertTrue(m_motorSim.getInitialized());
assertTrue(m_analogSim.getInitialized());
}

View File

@@ -11,7 +11,7 @@ import edu.wpi.first.wpilibj.DoubleSolenoid;
import edu.wpi.first.wpilibj.PneumaticsModuleType;
import edu.wpi.first.wpilibj.examples.unittest.Constants.IntakeConstants;
import edu.wpi.first.wpilibj.simulation.DoubleSolenoidSim;
import edu.wpi.first.wpilibj.simulation.PWMSim;
import edu.wpi.first.wpilibj.simulation.PWMMotorControllerSim;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -19,7 +19,7 @@ import org.junit.jupiter.api.Test;
class IntakeTest {
static final double DELTA = 1e-2; // acceptable deviation range
Intake m_intake;
PWMSim m_simMotor;
PWMMotorControllerSim m_simMotor;
DoubleSolenoidSim m_simPiston;
@BeforeEach // this method will run before each test
@@ -27,7 +27,8 @@ class IntakeTest {
assert HAL.initialize(500, 0); // initialize the HAL, crash if failed
m_intake = new Intake(); // create our intake
m_simMotor =
new PWMSim(IntakeConstants.kMotorPort); // create our simulation PWM motor controller
new PWMMotorControllerSim(
IntakeConstants.kMotorPort); // create our simulation PWM motor controller
m_simPiston =
new DoubleSolenoidSim(
PneumaticsModuleType.CTREPCM,