add limit readers

This commit is contained in:
Alexander Nozik 2023-10-30 22:51:17 +03:00
parent 984e7f12ef
commit 811477a636
6 changed files with 61 additions and 13 deletions

View File

@ -73,6 +73,7 @@ public class VirtualDrive(
// compute new value based on velocity and acceleration from the previous step // compute new value based on velocity and acceleration from the previous step
positionState.value += velocity * dtSeconds + force / mass * dtSeconds.pow(2) / 2 positionState.value += velocity * dtSeconds + force / mass * dtSeconds.pow(2) / 2
propertyChanged(Drive.position, positionState.value)
// compute new velocity based on acceleration on the previous step // compute new velocity based on acceleration on the previous step
velocity += force / mass * dtSeconds velocity += force / mass * dtSeconds

View File

@ -1,5 +1,7 @@
package space.kscience.controls.constructor package space.kscience.controls.constructor
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import space.kscience.controls.api.Device import space.kscience.controls.api.Device
import space.kscience.controls.spec.DeviceBySpec import space.kscience.controls.spec.DeviceBySpec
import space.kscience.controls.spec.DevicePropertySpec import space.kscience.controls.spec.DevicePropertySpec
@ -28,6 +30,13 @@ public class VirtualLimitSwitch(
context: Context, context: Context,
public val lockedState: DeviceState<Boolean>, public val lockedState: DeviceState<Boolean>,
) : DeviceBySpec<LimitSwitch>(LimitSwitch, context), LimitSwitch { ) : DeviceBySpec<LimitSwitch>(LimitSwitch, context), LimitSwitch {
init {
lockedState.valueFlow.onEach {
propertyChanged(LimitSwitch.locked, it)
}.launchIn(this)
}
override val locked: Boolean get() = lockedState.value override val locked: Boolean get() = lockedState.value
} }

View File

@ -62,6 +62,7 @@ public class PidRegulator(
lastPosition = drive.position lastPosition = drive.position
drive.force = pidParameters.kp * delta + pidParameters.ki * integral + pidParameters.kd * derivative drive.force = pidParameters.kp * delta + pidParameters.ki * integral + pidParameters.kd * derivative
propertyChanged(Regulator.position, drive.position)
} }
} }
} }

View File

@ -32,10 +32,10 @@ public class DoubleRangeState(
/** /**
* A state showing that the range is on its lower boundary * A state showing that the range is on its lower boundary
*/ */
public val atStartState: DeviceState<Boolean> = map(MetaConverter.boolean) { it == range.start } public val atStartState: DeviceState<Boolean> = map(MetaConverter.boolean) { it <= range.start }
/** /**
* A state showing that the range is on its higher boundary * A state showing that the range is on its higher boundary
*/ */
public val atEndState: DeviceState<Boolean> = map(MetaConverter.boolean) { it == range.endInclusive } public val atEndState: DeviceState<Boolean> = map(MetaConverter.boolean) { it >= range.endInclusive }
} }

View File

@ -9,11 +9,10 @@ import space.kscience.controls.api.propertyMessageFlow
import space.kscience.controls.constructor.DeviceState import space.kscience.controls.constructor.DeviceState
import space.kscience.controls.manager.clock import space.kscience.controls.manager.clock
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.meta.ListValue import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.Null
import space.kscience.dataforge.meta.Value
import space.kscience.plotly.Plot import space.kscience.plotly.Plot
import space.kscience.plotly.bar
import space.kscience.plotly.models.Bar
import space.kscience.plotly.models.Scatter import space.kscience.plotly.models.Scatter
import space.kscience.plotly.models.TraceValues import space.kscience.plotly.models.TraceValues
import space.kscience.plotly.scatter import space.kscience.plotly.scatter
@ -33,7 +32,7 @@ public fun Plot.plotDeviceProperty(
propertyName: String, propertyName: String,
extractValue: Meta.() -> Value = { value ?: Null }, extractValue: Meta.() -> Value = { value ?: Null },
pointsNumber: Int = 400, pointsNumber: Int = 400,
coroutineScope: CoroutineScope = device, coroutineScope: CoroutineScope = device.context,
configuration: Scatter.() -> Unit = {}, configuration: Scatter.() -> Unit = {},
): Job = scatter(configuration).run { ): Job = scatter(configuration).run {
val clock = device.context.clock val clock = device.context.clock
@ -43,7 +42,8 @@ public fun Plot.plotDeviceProperty(
}.launchIn(coroutineScope) }.launchIn(coroutineScope)
} }
public fun Plot.plotDeviceState(
public fun Plot.plotNumberState(
context: Context, context: Context,
state: DeviceState<out Number>, state: DeviceState<out Number>,
pointsNumber: Int = 400, pointsNumber: Int = 400,
@ -55,3 +55,16 @@ public fun Plot.plotDeviceState(
y.numbers = (y.numbers + it).takeLast(pointsNumber) y.numbers = (y.numbers + it).takeLast(pointsNumber)
}.launchIn(context) }.launchIn(context)
} }
public fun Plot.plotBooleanState(
context: Context,
state: DeviceState<Boolean>,
pointsNumber: Int = 400,
configuration: Bar.() -> Unit = {},
): Job = bar(configuration).run {
val clock = context.clock
state.valueFlow.onEach {
x.strings = (x.strings + clock.now().toString()).takeLast(pointsNumber)
y.values = (y.values + it.asValue()).takeLast(pointsNumber)
}.launchIn(context)
}

View File

@ -13,9 +13,10 @@ import space.kscience.controls.spec.doRecurring
import space.kscience.controls.spec.name import space.kscience.controls.spec.name
import space.kscience.controls.spec.write import space.kscience.controls.spec.write
import space.kscience.controls.vision.plotDeviceProperty import space.kscience.controls.vision.plotDeviceProperty
import space.kscience.controls.vision.plotDeviceState import space.kscience.controls.vision.plotNumberState
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.request import space.kscience.dataforge.context.request
import space.kscience.plotly.models.ScatterMode
import space.kscience.visionforge.VisionManager import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.html.VisionPage import space.kscience.visionforge.html.VisionPage
import space.kscience.visionforge.plotly.PlotlyPlugin import space.kscience.visionforge.plotly.PlotlyPlugin
@ -40,7 +41,7 @@ public fun main() {
val deviceManager = context.request(DeviceManager) val deviceManager = context.request(DeviceManager)
val visionManager = context.request(VisionManager) val visionManager = context.request(VisionManager)
val state = DoubleRangeState(0.0, -100.0..100.0) val state = DoubleRangeState(0.0, -5.0..5.0)
val pidParameters = PidParameters( val pidParameters = PidParameters(
kp = 2.5, kp = 2.5,
@ -79,14 +80,37 @@ public fun main() {
) { ) {
vision { vision {
plotly { plotly {
plotDeviceState(context, state){ plotNumberState(context, state) {
name = "value" name = "real position"
} }
plotDeviceProperty(device["pid"], Regulator.position.name) {
name = "read position"
}
plotDeviceProperty(device["pid"], Regulator.target.name) { plotDeviceProperty(device["pid"], Regulator.target.name) {
name = "target" name = "target"
} }
} }
} }
vision {
plotly {
// plotBooleanState(context, state.atStartState) {
// name = "start"
// }
// plotBooleanState(context, state.atEndState) {
// name = "end"
// }
plotDeviceProperty(device["start"], LimitSwitch.locked.name) {
name = "start measured"
mode = ScatterMode.markers
}
plotDeviceProperty(device["end"], LimitSwitch.locked.name) {
name = "end measured"
mode = ScatterMode.markers
}
}
}
} }
}.start(false) }.start(false)