From 4a5f5fab8c953bb288749ef17f6a359ee20a8a78 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 3 Jun 2024 15:38:39 +0300 Subject: [PATCH] Finish plotter demo --- .../controls/constructor/devices/Drive.kt | 1 + .../controls/constructor/devices/StepDrive.kt | 22 ++++++------ .../controls/constructor/models/Inertia.kt | 33 +---------------- .../controls/constructor/models/ScrewDrive.kt | 14 ++++---- .../controls/constructor/models/XYPosition.kt | 17 --------- .../constructor/models/coordinates.kt | 8 +++++ .../constructor/src/jvmMain/kotlin/PidDemo.kt | 6 ++-- .../constructor/src/jvmMain/kotlin/Plotter.kt | 36 +++++++++++-------- 8 files changed, 53 insertions(+), 84 deletions(-) delete mode 100644 controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/XYPosition.kt create mode 100644 controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/coordinates.kt diff --git a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/devices/Drive.kt b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/devices/Drive.kt index 3436856..9880508 100644 --- a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/devices/Drive.kt +++ b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/devices/Drive.kt @@ -9,6 +9,7 @@ import space.kscience.controls.constructor.units.numerical import space.kscience.dataforge.context.Context import space.kscience.dataforge.meta.MetaConverter +//TODO use current as input public class Drive( context: Context, diff --git a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/devices/StepDrive.kt b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/devices/StepDrive.kt index a8d9894..be32f07 100644 --- a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/devices/StepDrive.kt +++ b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/devices/StepDrive.kt @@ -9,7 +9,7 @@ import space.kscience.dataforge.context.Context import space.kscience.dataforge.meta.MetaConverter import kotlin.math.max import kotlin.math.min -import kotlin.math.roundToInt +import kotlin.math.roundToLong import kotlin.time.DurationUnit /** @@ -22,25 +22,27 @@ import kotlin.time.DurationUnit public class StepDrive( context: Context, ticksPerSecond: MutableDeviceState, - target: MutableDeviceState = MutableDeviceState(0), - private val writeTicks: suspend (ticks: Int, speed: Double) -> Unit = { _, _ -> }, + target: MutableDeviceState = MutableDeviceState(0), + private val writeTicks: suspend (ticks: Long, speed: Double) -> Unit = { _, _ -> }, ) : DeviceConstructor(context) { - public val target: MutableDeviceState by property(MetaConverter.int, target) + public val target: MutableDeviceState by property(MetaConverter.long, target) public val speed: MutableDeviceState by property(MetaConverter.double, ticksPerSecond) private val positionState = stateOf(target.value) - public val position: DeviceState by property(MetaConverter.int, positionState) + public val position: DeviceState by property(MetaConverter.long, positionState) + + //FIXME round to zero problem private val ticker = onTimer(reads = setOf(target, position), writes = setOf(position)) { prev, next -> val tickSpeed = ticksPerSecond.value val timeDelta = (next - prev).toDouble(DurationUnit.SECONDS) - val ticksDelta: Int = target.value - position.value - val steps: Int = when { - ticksDelta > 0 -> min(ticksDelta, (timeDelta * tickSpeed).roundToInt()) - ticksDelta < 0 -> max(ticksDelta, -(timeDelta * tickSpeed).roundToInt()) + val ticksDelta: Long = target.value - position.value + val steps: Long = when { + ticksDelta > 0 -> min(ticksDelta, (timeDelta * tickSpeed).roundToLong()) + ticksDelta < 0 -> max(ticksDelta, -(timeDelta * tickSpeed).roundToLong()) else -> return@onTimer } writeTicks(steps, tickSpeed) @@ -55,6 +57,6 @@ public fun StepDrive.angle( step: NumericalValue, zero: NumericalValue = NumericalValue(0), ): DeviceState> = position.map { - zero + it.toDouble() * step + zero + it * step } diff --git a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/Inertia.kt b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/Inertia.kt index d6c3fc7..88a377e 100644 --- a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/Inertia.kt +++ b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/Inertia.kt @@ -25,11 +25,9 @@ public class Inertia( registerState(velocity) } - private val movementTimer = timer(timerPrecision) - private var currentForce = force.value - private val movement = movementTimer.onChange { prev, next -> + private val movement = onTimer (timerPrecision) { prev, next -> val dtSeconds = (next - prev).toDouble(DurationUnit.SECONDS) // compute new value based on velocity and acceleration from the previous step @@ -57,21 +55,6 @@ public class Inertia( position = position, velocity = velocity ) -// -// -// public fun linear( -// context: Context, -// force: DeviceState>, -// mass: NumericalValue, -// initialPosition: NumericalValue, -// initialVelocity: NumericalValue = NumericalValue(0), -// ): Inertia = Inertia( -// context = context, -// force = force.values(), -// inertia = mass.value, -// position = MutableDeviceState(initialPosition), -// velocity = MutableDeviceState(initialVelocity) -// ) public fun circular( context: Context, @@ -86,19 +69,5 @@ public class Inertia( position = position, velocity = velocity ) -// -// public fun circular( -// context: Context, -// force: DeviceState>, -// momentOfInertia: NumericalValue, -// initialPosition: NumericalValue, -// initialVelocity: NumericalValue = NumericalValue(0), -// ): Inertia = Inertia( -// context = context, -// force = force.values(), -// inertia = momentOfInertia.value, -// position = MutableDeviceState(initialPosition), -// velocity = MutableDeviceState(initialVelocity) -// ) } } \ No newline at end of file diff --git a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/ScrewDrive.kt b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/ScrewDrive.kt index 5a6b6bc..573a648 100644 --- a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/ScrewDrive.kt +++ b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/ScrewDrive.kt @@ -12,17 +12,17 @@ public class ScrewDrive( public val leverage: NumericalValue, ) : ModelConstructor(context) { - public fun transformForce( - stateOfForce: DeviceState>, - ): DeviceState> = DeviceState.map(stateOfForce) { - NumericalValue(it.value * leverage.value/2/ PI) + public fun torqueToForce( + stateOfMomentum: DeviceState>, + ): DeviceState> = DeviceState.map(stateOfMomentum) { momentum -> + NumericalValue(momentum.value / leverage.value ) } - public fun transformOffset( + public fun degreesToMeters( stateOfAngle: DeviceState>, offset: NumericalValue = NumericalValue(0), - ): DeviceState> = DeviceState.map(stateOfAngle) { - offset + NumericalValue(it.value * leverage.value/2/ PI) + ): DeviceState> = DeviceState.map(stateOfAngle) { degrees -> + offset + NumericalValue(degrees.value * 2 * PI / 360 *leverage.value ) } } \ No newline at end of file diff --git a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/XYPosition.kt b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/XYPosition.kt deleted file mode 100644 index 15411f8..0000000 --- a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/XYPosition.kt +++ /dev/null @@ -1,17 +0,0 @@ -package space.kscience.controls.constructor.models - -import space.kscience.controls.constructor.ModelConstructor -import space.kscience.controls.constructor.MutableDeviceState -import space.kscience.controls.constructor.stateOf -import space.kscience.controls.constructor.units.Meters -import space.kscience.controls.constructor.units.NumericalValue -import space.kscience.dataforge.context.Context - -public class XYPosition( - context: Context, - initialX: NumericalValue = NumericalValue(0.0), - initialY: NumericalValue = NumericalValue(0.0), -) : ModelConstructor(context) { - public val x: MutableDeviceState> = stateOf(initialX) - public val y: MutableDeviceState> = stateOf(initialY) -} \ No newline at end of file diff --git a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/coordinates.kt b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/coordinates.kt new file mode 100644 index 0000000..50db92b --- /dev/null +++ b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/models/coordinates.kt @@ -0,0 +1,8 @@ +package space.kscience.controls.constructor.models + +import space.kscience.controls.constructor.units.NumericalValue +import space.kscience.controls.constructor.units.UnitsOfMeasurement + +public data class XY(val x: NumericalValue, val y: NumericalValue) + +public data class XYZ(val x: NumericalValue, val y: NumericalValue, val z: NumericalValue) \ No newline at end of file diff --git a/demo/constructor/src/jvmMain/kotlin/PidDemo.kt b/demo/constructor/src/jvmMain/kotlin/PidDemo.kt index a77544f..b19e179 100644 --- a/demo/constructor/src/jvmMain/kotlin/PidDemo.kt +++ b/demo/constructor/src/jvmMain/kotlin/PidDemo.kt @@ -94,7 +94,7 @@ internal fun createLinearDriveModel( //create a drive model with zero starting force val drive = Drive(context) - //a screw drive to converse a rotational moment into a linear one + //a screw drive to convert a rotational moment into a force val screwDrive = ScrewDrive(context, leverage) @@ -107,7 +107,7 @@ internal fun createLinearDriveModel( */ val inertiaModel = Inertia.linear( context = context, - force = screwDrive.transformForce(drive.force), + force = screwDrive.torqueToForce(drive.force), mass = mass, position = position ) @@ -266,7 +266,7 @@ fun main() = application { yAxisModel = rememberDoubleLinearAxisModel((range.start - 1.0)..(range.endInclusive + 1.0)), xAxisTitle = { Text("Time in seconds relative to current") }, xAxisLabels = { it: Instant -> - androidx.compose.material3.Text( + Text( (clock.now() - it).toDouble( DurationUnit.SECONDS ).toString(2) diff --git a/demo/constructor/src/jvmMain/kotlin/Plotter.kt b/demo/constructor/src/jvmMain/kotlin/Plotter.kt index 9d48965..b605dd4 100644 --- a/demo/constructor/src/jvmMain/kotlin/Plotter.kt +++ b/demo/constructor/src/jvmMain/kotlin/Plotter.kt @@ -18,7 +18,6 @@ import space.kscience.controls.constructor.MutableDeviceState import space.kscience.controls.constructor.device import space.kscience.controls.constructor.devices.StepDrive import space.kscience.controls.constructor.devices.angle -import space.kscience.controls.constructor.models.RangeState import space.kscience.controls.constructor.models.ScrewDrive import space.kscience.controls.constructor.models.coerceIn import space.kscience.controls.constructor.units.* @@ -38,21 +37,26 @@ class Plotter( val xDrive by device(xDrive) val yDrive by device(yDrive) - public fun moveToXY(x: Int, y: Int) { - xDrive.target.value = x - yDrive.target.value = y + public fun moveToXY(x: Number, y: Number) { + xDrive.target.value = x.toLong() + yDrive.target.value = y.toLong() } +// val position = combineState(xDrive.position, yDrive.position) { x, y -> +// space.kscience.controls.constructor.models.XY(x, y) +// } + //TODO add calibration // TODO add draw as action } suspend fun Plotter.modernArt(xRange: IntRange, yRange: IntRange) { - while (isActive){ + while (isActive) { val randomX = Random.nextInt(xRange.first, xRange.last) - val randomY = Random.nextInt(xRange.first, xRange.last) + val randomY = Random.nextInt(yRange.first, yRange.last) moveToXY(randomX, randomY) + //TODO wait for position instead of custom delay delay(500) paint(Color(Random.nextInt())) } @@ -80,8 +84,8 @@ suspend fun Plotter.square(xRange: IntRange, yRange: IntRange) { private val xRange = NumericalValue(-0.5)..NumericalValue(0.5) private val yRange = NumericalValue(-0.5)..NumericalValue(0.5) -private val ticksPerSecond = MutableDeviceState(250.0) -private val step = NumericalValue(1.2) +private val ticksPerSecond = MutableDeviceState(3000.0) +private val step = NumericalValue(1.8) private data class PlotterPoint( @@ -106,13 +110,13 @@ suspend fun main() = application { /* Here goes the device definition block */ - val xScrewDrive = ScrewDrive(context, NumericalValue(0.01)) val xDrive = StepDrive(context, ticksPerSecond) - val x: RangeState> = xScrewDrive.transformOffset(xDrive.angle(step)).coerceIn(xRange) + val xTransmission = ScrewDrive(context, NumericalValue(0.01)) + val x = xTransmission.degreesToMeters(xDrive.angle(step)).coerceIn(xRange) - val yScrewDrive = ScrewDrive(context, NumericalValue(0.01)) val yDrive = StepDrive(context, ticksPerSecond) - val y: RangeState> = yScrewDrive.transformOffset(yDrive.angle(step)).coerceIn(yRange) + val yTransmission = ScrewDrive(context, NumericalValue(0.01)) + val y = yTransmission.degreesToMeters(yDrive.angle(step)).coerceIn(yRange) val plotter = Plotter(context, xDrive, yDrive) { color -> println("Point X: ${x.value.value}, Y: ${y.value.value}, color: $color") @@ -134,10 +138,12 @@ suspend fun main() = application { } } + /* run program */ + launch { - val range = -100..100 - plotter.modernArt(range, range) - //plotter.square(range, range) + val range = -1000..1000 +// plotter.modernArt(range, range) + plotter.square(range, range) } }