diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml
index dde3dd1..cdd61d8 100644
--- a/.idea/caches/deviceStreaming.xml
+++ b/.idea/caches/deviceStreaming.xml
@@ -99,6 +99,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -135,6 +147,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -183,6 +207,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -387,6 +423,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -591,6 +639,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -651,6 +711,11 @@
+
@@ -700,6 +765,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1072,6 +1149,11 @@
+
+
+
+
+
@@ -1109,6 +1191,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1424,6 +1518,11 @@
+
+
+
+
+
@@ -1485,6 +1584,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1533,6 +1644,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1545,6 +1668,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1715,6 +1850,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1751,6 +1898,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1763,6 +1922,11 @@
+
+
+
+
+
@@ -1775,6 +1939,11 @@
+
+
+
+
+
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextCRServo.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextCRServo.kt
index 1fedabb..2c16de4 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextCRServo.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextCRServo.kt
@@ -44,12 +44,21 @@ open class NextCRServo @JvmOverloads constructor(
* @param port The servo port (in the range [0, 5]).
* @param cacheTolerance Tolerance used by the [Caching] delegate for power updates; defaults to 0.01.
*/
- @JvmOverloads constructor(module: NextLynxModule, port: Int, cacheTolerance: Double = 0.01) : this(
+ @JvmOverloads constructor(
+ module: NextLynxModule,
+ port: Int,
+ cacheTolerance: Double = 0.01,
+ ) : this(
{ CRServoImplEx(module.servoController, port, ServoConfigurationType.getStandardServoType()) },
cacheTolerance,
- )
+ ) {
+ require(port in 0..3) { "Expected port in range [0, 3], got $port" }
+ }
- @JvmOverloads constructor(name: String, cacheTolerance: Double = 0.01) : this(
+ @JvmOverloads constructor(
+ name: String,
+ cacheTolerance: Double = 0.01,
+ ) : this(
{ RobotController.hardwareMap[name] as CRServoImplEx },
cacheTolerance,
)
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackCRServo.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackCRServo.kt
index 6d7ffa0..39be2e8 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackCRServo.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackCRServo.kt
@@ -8,7 +8,6 @@
package dev.nextftc.hardware.actuators
-import com.qualcomm.robotcore.hardware.AnalogInput
import com.qualcomm.robotcore.hardware.CRServoImplEx
import com.qualcomm.robotcore.hardware.configuration.typecontainers.ServoConfigurationType
import dev.nextftc.hardware.RobotController
@@ -29,45 +28,48 @@ import dev.nextftc.units.radians
*
* @param initializer A function returning the backing [CRServoImplEx]. It will
* be invoked lazily the first time the servo is accessed.
- * @param feedbackName Hardware map name of the analog input.
+ * @param feedbackInitializer A function returning the backing [AnalogFeedback]
+ * used to read the feedback angle. Accepts any [AnalogFeedback] implementation.
* @param cacheTolerance Tolerance for the [NextCRServo] power caching delegate.
*/
class NextFeedbackCRServo @JvmOverloads constructor(
initializer: () -> CRServoImplEx,
- feedbackName: String,
+ feedbackInitializer: () -> AnalogFeedback,
cacheTolerance: Double = 0.01,
) : NextCRServo(initializer, cacheTolerance) {
/**
- * Constructor to create a NextFeedbackCRServo using a servo name.
+ * Constructor to create a NextFeedbackCRServo using a servo name and an
+ * already-constructed [AnalogFeedback] instance for the feedback input.
*
* @param servoName Hardware map name of the servo.
- * @param feedbackName Hardware map name of the analog input.
+ * @param feedback An already-constructed [AnalogFeedback] instance to read the angle from.
* @param cacheTolerance Tolerance for the [NextCRServo] power caching delegate.
*/
@JvmOverloads constructor(
servoName: String,
- feedbackName: String,
+ feedback: AnalogFeedback,
cacheTolerance: Double = 0.01,
) : this(
{ RobotController.hardwareMap[servoName] as CRServoImplEx },
- feedbackName,
+ { feedback },
cacheTolerance,
)
/**
- * Constructor to create a NextFeedbackCRServo using a LynxModule and port number.
+ * Constructor to create a NextFeedbackCRServo using a LynxModule and port number for
+ * the servo, and an already-constructed [AnalogFeedback] instance for the feedback input.
*
* @param module The Lynx module, see [RobotController.controlHub], [RobotController.expansionHub],
* and [RobotController.servoHubs].
* @param port The servo port (in the range [0, 5]).
- * @param feedbackName Hardware map name of the analog input.
+ * @param feedback An already-constructed [AnalogFeedback] instance to read the angle from.
* @param cacheTolerance Tolerance for the [NextCRServo] power caching delegate.
*/
@JvmOverloads constructor(
module: NextLynxModule,
port: Int,
- feedbackName: String,
+ feedback: AnalogFeedback,
cacheTolerance: Double = 0.01,
) : this(
{
@@ -77,14 +79,12 @@ class NextFeedbackCRServo @JvmOverloads constructor(
ServoConfigurationType.getStandardServoType(),
)
},
- feedbackName,
+ { feedback },
cacheTolerance,
)
- private val analogInput by LazyHardware {
- RobotController.hardwareMap[feedbackName] as AnalogInput
- }
- private val rawAngleRadians: Double by AnalogFeedback { analogInput.voltage }
+ private val analogInput by LazyHardware(feedbackInitializer)
+ private val rawAngleRadians: Double by analogInput
/**
* Actual angle of the servo, reported from the analog feedback input.
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackServo.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackServo.kt
index 2b8f094..8782b16 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackServo.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextFeedbackServo.kt
@@ -8,7 +8,6 @@
package dev.nextftc.hardware.actuators
-import com.qualcomm.robotcore.hardware.AnalogInput
import com.qualcomm.robotcore.hardware.ServoImplEx
import com.qualcomm.robotcore.hardware.configuration.typecontainers.ServoConfigurationType
import dev.nextftc.hardware.RobotController
@@ -29,64 +28,65 @@ import dev.nextftc.units.radians
* Example:
*
* ```
- * val arm = NextFeedbackServo("armServo", "armEncoder")
+ * val arm = NextFeedbackServo("armServo", myAnalogFeedback)
* arm.position = 0.5
* val angle = arm.angle
* ```
*
* @param initializer A function returning the backing [ServoImplEx]. It will be
* invoked lazily the first time the servo is accessed.
- * @param feedbackName Hardware map name of the analog input.
+ * @param feedbackInitializer A function returning the backing [AnalogFeedback]
+ * used to read the feedback angle. Accepts any [AnalogFeedback] implementation.
* @param cacheTolerance Tolerance for the [NextServo] position caching delegate.
*/
class NextFeedbackServo @JvmOverloads constructor(
initializer: () -> ServoImplEx,
- feedbackName: String,
+ feedbackInitializer: () -> AnalogFeedback,
cacheTolerance: Double = 0.01,
) : NextServo(initializer, cacheTolerance) {
/**
- * Constructor to create a NextFeedbackServo using a servo name.
+ * Constructor to create a NextFeedbackServo using a servo name and an
+ * already-constructed [AnalogFeedback] instance for the feedback input.
*
* @param servoName Hardware map name of the servo.
- * @param feedbackName Hardware map name of the analog input.
+ * @param feedback An already-constructed [AnalogFeedback] instance to read the angle from.
* @param cacheTolerance Tolerance for the [NextServo] position caching delegate.
*/
@JvmOverloads constructor(
servoName: String,
- feedbackName: String,
+ feedback: AnalogFeedback,
cacheTolerance: Double = 0.01,
) : this(
{ RobotController.hardwareMap[servoName] as ServoImplEx },
- feedbackName,
+ { feedback },
cacheTolerance,
)
/**
- * Constructor to create a NextFeedbackServo using a LynxModule and port number.
+ * Constructor to create a NextFeedbackServo using a LynxModule and port number for
+ * the servo, and an already-constructed [AnalogFeedback] instance for the feedback input.
*
* @param module The Lynx module, see [RobotController.controlHub], [RobotController.expansionHub],
* and [RobotController.servoHubs].
* @param port The servo port (in the range [0, 5]).
- * @param feedbackName Hardware map name of the analog input.
+ * @param feedback An already-constructed [AnalogFeedback] instance to read the angle from.
* @param cacheTolerance Tolerance for the [NextServo] position caching delegate.
*/
@JvmOverloads constructor(
module: NextLynxModule,
port: Int,
- feedbackName: String,
+ feedback: AnalogFeedback,
cacheTolerance: Double = 0.01,
) : this(
{ ServoImplEx(module.servoController, port, ServoConfigurationType.getStandardServoType()) },
- feedbackName,
+ { feedback },
cacheTolerance,
)
- private val analogInput by LazyHardware {
- RobotController.hardwareMap[feedbackName] as AnalogInput
- }
+ private val analogInput by LazyHardware(feedbackInitializer)
- private val rawAngleRadians: Double by AnalogFeedback { analogInput.voltage }
+ private val rawAngleRadians: Double by analogInput
/**
* Actual angle of the servo, reported from the analog feedback input.
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextMotor.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextMotor.kt
index c79a403..20dd422 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextMotor.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextMotor.kt
@@ -77,7 +77,9 @@ class NextMotor @JvmOverloads constructor(
{ DcMotorImplEx(module.motorController, port) },
anglePerCount,
cacheTolerance,
- )
+ ) {
+ require(port in 0..3) { "Expected bus in range [0, 3], got $port" }
+ }
/**
* Constructs a motor by name from the current hardware map.
@@ -92,7 +94,11 @@ class NextMotor @JvmOverloads constructor(
name: String,
anglePerCount: Angle = 1.0.radians,
cacheTolerance: Double = 0.01,
- ) : this({ RobotController.hardwareMap[name] as DcMotorImplEx }, anglePerCount, cacheTolerance)
+ ) : this(
+ { RobotController.hardwareMap[name] as DcMotorImplEx },
+ anglePerCount,
+ cacheTolerance,
+ )
init {
motorEventLoop.bind(this::update)
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextServo.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextServo.kt
index c87b82f..2191591 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextServo.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/actuators/NextServo.kt
@@ -63,7 +63,9 @@ open class NextServo @JvmOverloads constructor(
{ ServoImplEx(module.servoController, port, ServoConfigurationType.getStandardServoType()) },
cacheTolerance,
direction,
- )
+ ) {
+ require(port in 0..3) { "Expected bus in range [0, 3], got $port" }
+ }
/**
* Constructor to create a NextServo using configuration name
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/lynx/NextLynxModule.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/lynx/NextLynxModule.kt
index cc695ce..76e8a9b 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/lynx/NextLynxModule.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/lynx/NextLynxModule.kt
@@ -1,6 +1,10 @@
package dev.nextftc.hardware.lynx
+import com.qualcomm.hardware.lynx.LynxAnalogInputController
import com.qualcomm.hardware.lynx.LynxDcMotorController
+import com.qualcomm.hardware.lynx.LynxDigitalChannelController
+import com.qualcomm.hardware.lynx.LynxI2cDeviceSynch
+import com.qualcomm.hardware.lynx.LynxI2cDeviceSynchV2
import com.qualcomm.hardware.lynx.LynxModule
import com.qualcomm.hardware.lynx.LynxServoController
import dev.nextftc.hardware.RobotController
@@ -26,6 +30,10 @@ class NextLynxModule internal constructor(initializer: () -> LynxModule, @JvmFie
private val module by LazyHardware(initializer)
+ private val i2cControllers = Array(4) { bus ->
+ LazyHardware { LynxI2cDeviceSynchV2(RobotController.appContext, module, bus) }
+ }
+
/** Current module temperature. */
val temperature: Temperature
get() = module.getTemperature(TempUnit.CELSIUS).celsius
@@ -47,4 +55,20 @@ class NextLynxModule internal constructor(initializer: () -> LynxModule, @JvmFie
val servoController: LynxServoController by LazyHardware {
LynxServoController(RobotController.appContext, module)
}
+
+ /** Creates or gets a [LynxI2cDeviceSynch] bound to this module. */
+ fun i2cController(bus: Int): LynxI2cDeviceSynch {
+ require(bus in 0..3) { "I2C bus must be in range of 0 - 3, got $bus" }
+ return i2cControllers[bus].getValue(this, ::i2cControllers)
+ }
+
+ /** Creates or gets a [LynxDigitalChannelController] bound to this module. */
+ val digitalController: LynxDigitalChannelController by LazyHardware {
+ LynxDigitalChannelController(RobotController.appContext, module)
+ }
+
+ /** Creates or gets a [LynxAnalogInputController] bound to this module. */
+ val analogController: LynxAnalogInputController by LazyHardware {
+ LynxAnalogInputController(RobotController.appContext, module)
+ }
}
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextAnalogInput.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextAnalogInput.kt
new file mode 100644
index 0000000..dc61548
--- /dev/null
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextAnalogInput.kt
@@ -0,0 +1,101 @@
+package dev.nextftc.hardware.sensors
+
+import com.qualcomm.robotcore.hardware.AnalogInput
+import dev.nextftc.hardware.RobotController
+import dev.nextftc.hardware.lynx.NextLynxModule
+import dev.nextftc.hardware.util.AnalogFeedback
+import dev.nextftc.hardware.util.LazyHardware
+import dev.nextftc.units.Volts
+import dev.nextftc.units.measuretypes.Voltage
+import dev.nextftc.units.volts
+import java.util.function.Supplier
+
+/**
+ * A wrapper around an [AnalogInput] that provides convenient access to raw voltage
+ * readings as well as a normalized, optionally transformed value.
+ *
+ * The hardware device is resolved lazily, so constructing an instance of this class
+ * does not require the hardware map to be ready yet.
+ *
+ * Inherits from [AnalogFeedback] so that any `NextAnalogInput` can also be used
+ * directly as a `by`-delegate returning an angle in radians (e.g. for feedback
+ * CR servos).
+ *
+ * @param initializer A lambda that resolves and returns the underlying [AnalogInput].
+ * @param customTransformation An optional transformation applied to the normalized
+ * voltage ratio (raw voltage divided by [maxVoltage]) before it is exposed via [value].
+ * Defaults to the identity function.
+ * @param maxVoltage The voltage that corresponds to a normalized value of `1.0`.
+ * Defaults to `3.3` volts.
+ */
+open class NextAnalogInput @JvmOverloads constructor(
+ initializer: () -> AnalogInput,
+ val customTransformation: (Double) -> Double = { n: Double -> n },
+ maxVoltage: Voltage = 3.3.volts,
+) : AnalogFeedback(maxVoltage, voltageSupplier(initializer)) {
+
+ companion object {
+ private fun voltageSupplier(initializer: () -> AnalogInput): Supplier {
+ val input by LazyHardware(initializer)
+ return Supplier { input.voltage }
+ }
+ }
+
+ /**
+ * Creates a [NextAnalogInput] by looking up the [AnalogInput] in the hardware map
+ * by its configured name.
+ *
+ * @param name The name of the analog input device as configured in the hardware map.
+ * @param customTransformation An optional transformation applied to the normalized
+ * voltage ratio before it is exposed via [value]. Defaults to the identity function.
+ * @param maxVoltage The voltage that corresponds to a normalized value of `1.0`.
+ * Defaults to `3.3` volts.
+ */
+ @JvmOverloads constructor(
+ name: String,
+ customTransformation: (Double) -> Double = { n: Double -> n },
+ maxVoltage: Voltage = 3.3.volts,
+ ) : this(
+ { RobotController.hardwareMap[name] as AnalogInput },
+ customTransformation,
+ maxVoltage,
+ )
+
+ /**
+ * Creates a [NextAnalogInput] directly from a [NextLynxModule] and analog channel
+ * number, bypassing the hardware map.
+ *
+ * @param module The Lynx module whose analog controller the input is attached to.
+ * @param channel The analog channel index, must be in the range `[0, 3]`.
+ * @param customTransformation An optional transformation applied to the normalized
+ * voltage ratio before it is exposed via [value]. Defaults to the identity function.
+ * @param maxVoltage The voltage that corresponds to a normalized value of `1.0`.
+ * Defaults to `3.3` volts.
+ * @throws IllegalArgumentException if [channel] is not in the range `[0, 3]`.
+ */
+ @JvmOverloads constructor(
+ module: NextLynxModule,
+ channel: Int,
+ customTransformation: (Double) -> Double = { n: Double -> n },
+ maxVoltage: Voltage = 3.3.volts,
+ ) : this(
+ { AnalogInput(module.analogController, channel) },
+ customTransformation,
+ maxVoltage,
+ ) {
+ require(channel in 0..3) { "Expected channel in range [0, 3], got $channel" }
+ }
+
+ private val rawVoltageSupplier = voltageSupplier(initializer)
+
+ /** The raw, untransformed voltage currently read from the analog input. */
+ val rawVoltage: Voltage
+ get() = rawVoltageSupplier.get().volts
+
+ /**
+ * The normalized reading from the analog input, computed as [rawVoltage] divided
+ * by [maxVoltage] and passed through [customTransformation].
+ */
+ val value: Double
+ get() = customTransformation.invoke(rawVoltage.into(Volts) / maxVoltage.into(Volts))
+}
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextColorDistanceSensor.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextColorDistanceSensor.kt
index 2eb952b..d8531a8 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextColorDistanceSensor.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextColorDistanceSensor.kt
@@ -9,9 +9,11 @@
package dev.nextftc.hardware.sensors
import android.graphics.Color
+import com.qualcomm.hardware.lynx.LynxI2cColorRangeSensor
import com.qualcomm.robotcore.hardware.DistanceSensor
import com.qualcomm.robotcore.hardware.NormalizedColorSensor
import dev.nextftc.hardware.RobotController
+import dev.nextftc.hardware.lynx.NextLynxModule
import dev.nextftc.hardware.sensors.colors.ColorProfile
import dev.nextftc.hardware.sensors.colors.NextColor
import dev.nextftc.hardware.util.LazyHardware
@@ -47,8 +49,18 @@ class NextColorDistanceSensor @JvmOverloads constructor(
colorInitializer: () -> NormalizedColorSensor,
distanceInitializer: (() -> DistanceSensor)? = null,
) {
+ /**
+ * Constructor to create a NextColorDistanceSensor using a configuration name.
+ *
+ * @param sensorName The configuration name for the sensor, usually found on the Driver Station.
+ * @param hasDistance Whether to also resolve a [DistanceSensor] from the same device. Defaults to false.
+ */
+
@JvmOverloads
- constructor(sensorName: String, hasDistance: Boolean = false) : this(
+ constructor(
+ sensorName: String,
+ hasDistance: Boolean = false,
+ ) : this(
{ RobotController.hardwareMap[sensorName] as NormalizedColorSensor },
if (hasDistance) {
{ RobotController.hardwareMap[sensorName] as DistanceSensor }
@@ -57,6 +69,30 @@ class NextColorDistanceSensor @JvmOverloads constructor(
},
)
+ /**
+ * Constructor to create a NextColorDistanceSensor using a LynxModule and I2C bus number.
+ *
+ * @param module The Lynx Module, see [RobotController.controlHub], [RobotController.expansionHub],
+ * and [RobotController.servoHubs]
+ * @param bus The I2C bus number (in the range [0, 3])
+ * @param hasDistance Whether to also resolve a [DistanceSensor] from the same device. Defaults to false.
+ */
+ @JvmOverloads
+ constructor(
+ module: NextLynxModule,
+ bus: Int,
+ hasDistance: Boolean = false,
+ ) : this(
+ { LynxI2cColorRangeSensor(module.i2cController(bus), true) },
+ if (hasDistance) {
+ { LynxI2cColorRangeSensor(module.i2cController(bus), true) as DistanceSensor }
+ } else {
+ null
+ },
+ ) {
+ require(bus in 0..3) { "Expected bus in range [0, 3], got $bus" }
+ }
+
private val lazySensor = LazyHardware(colorInitializer)
private val colorSensor by lazySensor
private val distanceSensor: DistanceSensor? by lazy { distanceInitializer?.invoke() }
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDigitalSensor.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDigitalSensor.kt
index a3a1b62..e270ad0 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDigitalSensor.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDigitalSensor.kt
@@ -8,8 +8,11 @@
package dev.nextftc.hardware.sensors
+import com.qualcomm.hardware.lynx.LynxModule
import com.qualcomm.robotcore.hardware.DigitalChannel
+import com.qualcomm.robotcore.hardware.DigitalChannelImpl
import dev.nextftc.hardware.RobotController
+import dev.nextftc.hardware.lynx.NextLynxModule
import dev.nextftc.hardware.util.LazyHardware
/**
@@ -42,14 +45,29 @@ class NextDigitalSensor @JvmOverloads constructor(
private val inverted: Boolean = true,
) {
/**
+ * @param module The Lynx Module, see [RobotController.controlHub], [RobotController.expansionHub],
+ * @param port The digital sensor port (in the range [0, 7])
* @param name Hardware map name to resolve the [DigitalChannel] from.
* @param inverted If true, [isTriggered] is the opposite of the raw state. Defaults to true.
*/
@JvmOverloads
- constructor(name: String, inverted: Boolean = true) : this(
- {
- RobotController.hardwareMap[name] as DigitalChannel
- },
+ constructor(
+ module: NextLynxModule,
+ port: Int,
+ inverted: Boolean = true,
+ ) : this(
+ { DigitalChannelImpl(module.digitalController, port) },
+ inverted,
+ ) {
+ require(port in 0..3) { "Expected port in range [0, 7], got $port" }
+ }
+
+ @JvmOverloads
+ constructor(
+ name: String,
+ inverted: Boolean = true,
+ ) : this(
+ { RobotController.hardwareMap[name] as DigitalChannel },
inverted,
)
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDistanceSensor.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDistanceSensor.kt
index debdcf6..5a0e6cb 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDistanceSensor.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextDistanceSensor.kt
@@ -8,10 +8,13 @@
package dev.nextftc.hardware.sensors
+import com.qualcomm.hardware.lynx.LynxI2cColorRangeSensor
import com.qualcomm.robotcore.hardware.DistanceSensor
import dev.nextftc.hardware.RobotController
+import dev.nextftc.hardware.lynx.NextLynxModule
import dev.nextftc.hardware.util.LazyHardware
import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit
+
/**
* Lightweight wrapper for a distance sensor that caches the last reading.
* Call [update] in periodic to read the hardware.
@@ -32,10 +35,32 @@ import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit
* @author 28shettr
*/
class NextDistanceSensor(initializer: () -> DistanceSensor) {
+ /**
+ * Constructor to create a NextDistanceSensor using a configuration name.
+ *
+ * @param name The configuration name for the sensor, usually found on the Driver Station.
+ */
+
constructor(name: String) : this(
{ RobotController.hardwareMap[name] as DistanceSensor },
)
+ /**
+ * Constructor to create a NextDistanceSensor using a LynxModule and I2C bus number.
+ *
+ * @param module The Lynx Module, see [RobotController.controlHub], [RobotController.expansionHub],
+ * and [RobotController.servoHubs]
+ * @param bus The I2C bus number (in the range [0, 3])
+ */
+ constructor(
+ module: NextLynxModule,
+ bus: Int,
+ ) : this(
+ { LynxI2cColorRangeSensor(module.i2cController(bus), true) },
+ ) {
+ require(bus in 0..3) { "Expected bus in range [0, 3], got $bus" }
+ }
+
private val distanceSensor by LazyHardware(initializer)
private var cachedDistanceCm: Double = Double.NaN
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextPinpoint.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextPinpoint.kt
index 9a2ba7a..5252ceb 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextPinpoint.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/sensors/NextPinpoint.kt
@@ -13,6 +13,7 @@ import dev.nextftc.control.geometry.Pose2d
import dev.nextftc.control.geometry.PoseVelocity2d
import dev.nextftc.control.geometry.Vector2d
import dev.nextftc.hardware.RobotController
+import dev.nextftc.hardware.lynx.NextLynxModule
import dev.nextftc.hardware.util.LazyHardware
import dev.nextftc.units.inchesPerSecond
import dev.nextftc.units.radiansPerSecond
@@ -26,6 +27,17 @@ import org.firstinspires.ftc.robotcore.external.navigation.UnnormalizedAngleUnit
class NextPinpoint(initializer: () -> GoBildaPinpointDriver) {
constructor(name: String) : this({ RobotController.hardwareMap[name] as GoBildaPinpointDriver })
+ constructor(
+ module: NextLynxModule,
+ bus: Int,
+ ) : this(
+ {
+ GoBildaPinpointDriver(module.i2cController(bus), true)
+ },
+ ) {
+ require(bus in 0..3) { "Expected bus in range [0, 3], got $bus" }
+ }
+
private val driver by LazyHardware(initializer)
val device: GoBildaPinpointDriver get() = driver
diff --git a/hardware/src/main/kotlin/dev/nextftc/hardware/util/AnalogFeedback.kt b/hardware/src/main/kotlin/dev/nextftc/hardware/util/AnalogFeedback.kt
index 5e8e45f..61de803 100644
--- a/hardware/src/main/kotlin/dev/nextftc/hardware/util/AnalogFeedback.kt
+++ b/hardware/src/main/kotlin/dev/nextftc/hardware/util/AnalogFeedback.kt
@@ -8,7 +8,7 @@ import kotlin.math.PI
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
-class AnalogFeedback @JvmOverloads constructor(
+open class AnalogFeedback @JvmOverloads constructor(
val maxVoltage: Voltage = 3.3.volts,
private val voltageSupplier: Supplier,
) : ReadOnlyProperty {
diff --git a/robot/src/main/kotlin/dev/nextftc/robot/RobotScanner.kt b/robot/src/main/kotlin/dev/nextftc/robot/RobotScanner.kt
index 90d67b9..0e28093 100644
--- a/robot/src/main/kotlin/dev/nextftc/robot/RobotScanner.kt
+++ b/robot/src/main/kotlin/dev/nextftc/robot/RobotScanner.kt
@@ -124,9 +124,9 @@ internal object RobotScanner : Scanner {
object RobotState : OnCreateEventLoop {
/** The singleton or freshly constructed instance of the user's robot. */
internal lateinit var robot: NextRobot
-
+
override fun onCreateEventLoop(context: Context, ftcEventLoop: FtcEventLoop) {
robot = RobotScanner.robotConstructor()
ftcEventLoop.opModeManager.registerListener(DriverStationTelemetry)
}
-}
\ No newline at end of file
+}