Add compose controls to pid simulator
This commit is contained in:
parent
07cc41c645
commit
81d6b672cf
@ -16,12 +16,22 @@ import kotlin.time.DurationUnit
|
|||||||
/**
|
/**
|
||||||
* Pid regulator parameters
|
* Pid regulator parameters
|
||||||
*/
|
*/
|
||||||
public data class PidParameters(
|
public interface PidParameters {
|
||||||
public val kp: Double,
|
public val kp: Double
|
||||||
public val ki: Double,
|
public val ki: Double
|
||||||
public val kd: Double,
|
public val kd: Double
|
||||||
public val timeStep: Duration = 1.milliseconds,
|
public val timeStep: Duration
|
||||||
)
|
}
|
||||||
|
|
||||||
|
private data class PidParametersImpl(
|
||||||
|
override val kp: Double,
|
||||||
|
override val ki: Double,
|
||||||
|
override val kd: Double,
|
||||||
|
override val timeStep: Duration,
|
||||||
|
) : PidParameters
|
||||||
|
|
||||||
|
public fun PidParameters(kp: Double, ki: Double, kd: Double, timeStep: Duration = 1.milliseconds): PidParameters =
|
||||||
|
PidParametersImpl(kp, ki, kd, timeStep)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A drive with PID regulator
|
* A drive with PID regulator
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||||
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
|
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
application
|
id("org.jetbrains.compose") version "1.5.10"
|
||||||
}
|
}
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
@ -20,8 +21,31 @@ kscience {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
kotlin {
|
||||||
mainClass.set("space.kscience.controls.demo.constructor.MainKt")
|
sourceSets {
|
||||||
|
jvmMain {
|
||||||
|
dependencies {
|
||||||
|
implementation(compose.desktop.currentOs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//application {
|
||||||
|
// mainClass.set("space.kscience.controls.demo.constructor.MainKt")
|
||||||
|
//}
|
||||||
|
|
||||||
kotlin.explicitApi = ExplicitApiMode.Disabled
|
kotlin.explicitApi = ExplicitApiMode.Disabled
|
||||||
|
|
||||||
|
|
||||||
|
compose.desktop {
|
||||||
|
application {
|
||||||
|
mainClass = "space.kscience.controls.demo.constructor.MainKt"
|
||||||
|
|
||||||
|
nativeDistributions {
|
||||||
|
targetFormats(TargetFormat.Exe)
|
||||||
|
packageName = "PidConstructor"
|
||||||
|
packageVersion = "1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,26 @@
|
|||||||
package space.kscience.controls.demo.constructor
|
package space.kscience.controls.demo.constructor
|
||||||
|
|
||||||
import kotlinx.coroutines.delay
|
import androidx.compose.foundation.layout.Column
|
||||||
import space.kscience.controls.api.get
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Window
|
||||||
|
import androidx.compose.ui.window.application
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import space.kscience.controls.constructor.*
|
import space.kscience.controls.constructor.*
|
||||||
import space.kscience.controls.manager.ClockManager
|
import space.kscience.controls.manager.ClockManager
|
||||||
import space.kscience.controls.manager.DeviceManager
|
import space.kscience.controls.manager.DeviceManager
|
||||||
import space.kscience.controls.manager.clock
|
import space.kscience.controls.manager.clock
|
||||||
import space.kscience.controls.spec.doRecurring
|
import space.kscience.controls.spec.doRecurring
|
||||||
import space.kscience.controls.spec.name
|
import space.kscience.controls.spec.name
|
||||||
import space.kscience.controls.spec.read
|
|
||||||
import space.kscience.controls.spec.write
|
|
||||||
import space.kscience.controls.vision.plot
|
import space.kscience.controls.vision.plot
|
||||||
import space.kscience.controls.vision.plotDeviceProperty
|
import space.kscience.controls.vision.plotDeviceProperty
|
||||||
import space.kscience.controls.vision.plotNumberState
|
import space.kscience.controls.vision.plotNumberState
|
||||||
@ -21,6 +32,7 @@ import space.kscience.plotly.models.ScatterMode
|
|||||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
@ -46,23 +58,15 @@ class LinearDrive(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun main() {
|
private fun Context.launchPidDevice(
|
||||||
val context = Context {
|
state: DoubleRangeState,
|
||||||
plugin(DeviceManager)
|
pidParameters: PidParameters,
|
||||||
plugin(PlotlyPlugin)
|
mass: Double,
|
||||||
plugin(ClockManager)
|
) = launch {
|
||||||
}
|
val device = install(
|
||||||
|
"device",
|
||||||
val state = DoubleRangeState(0.0, -5.0..5.0)
|
LinearDrive(this@launchPidDevice, state, mass, pidParameters)
|
||||||
|
).apply {
|
||||||
val pidParameters = PidParameters(
|
|
||||||
kp = 2.5,
|
|
||||||
ki = 0.0,
|
|
||||||
kd = -0.1,
|
|
||||||
timeStep = 0.005.seconds
|
|
||||||
)
|
|
||||||
|
|
||||||
val device = context.install("device", LinearDrive(context, state, 0.005, pidParameters)).apply {
|
|
||||||
val clock = context.clock
|
val clock = context.clock
|
||||||
val clockStart = clock.now()
|
val clockStart = clock.now()
|
||||||
doRecurring(10.milliseconds) {
|
doRecurring(10.milliseconds) {
|
||||||
@ -78,7 +82,7 @@ fun main() {
|
|||||||
|
|
||||||
val maxAge = 10.seconds
|
val maxAge = 10.seconds
|
||||||
|
|
||||||
context.showDashboard {
|
showDashboard {
|
||||||
plot {
|
plot {
|
||||||
plotNumberState(context, state, maxAge = maxAge) {
|
plotNumberState(context, state, maxAge = maxAge) {
|
||||||
name = "real position"
|
name = "real position"
|
||||||
@ -106,13 +110,88 @@ fun main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun DeviceGroup.findEnd(): Double{
|
fun main() = application {
|
||||||
val regulator = get("pid") as Regulator
|
val context = Context {
|
||||||
val limitEnd = get("end") as LimitSwitch
|
plugin(DeviceManager)
|
||||||
|
plugin(PlotlyPlugin)
|
||||||
|
plugin(ClockManager)
|
||||||
|
}
|
||||||
|
|
||||||
while(!limitEnd.read(LimitSwitch.locked)){
|
class MutablePidParameters(
|
||||||
delay(10.milliseconds)
|
kp: Double,
|
||||||
regulator.write(Regulator.target, regulator.read(Regulator.position) + 0.1)
|
ki: Double,
|
||||||
|
kd: Double,
|
||||||
|
timeStep: Duration,
|
||||||
|
) : PidParameters {
|
||||||
|
override var kp by mutableStateOf(kp)
|
||||||
|
override var ki by mutableStateOf(ki)
|
||||||
|
override var kd by mutableStateOf(kd)
|
||||||
|
override var timeStep by mutableStateOf(timeStep)
|
||||||
|
}
|
||||||
|
|
||||||
|
val pidParameters = remember {
|
||||||
|
MutablePidParameters(
|
||||||
|
kp = 2.5,
|
||||||
|
ki = 0.0,
|
||||||
|
kd = -0.1,
|
||||||
|
timeStep = 0.005.seconds
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.launchPidDevice(
|
||||||
|
DoubleRangeState(0.0, -6.0..6.0),
|
||||||
|
pidParameters,
|
||||||
|
mass = 0.05
|
||||||
|
)
|
||||||
|
|
||||||
|
Window(onCloseRequest = ::exitApplication) {
|
||||||
|
MaterialTheme {
|
||||||
|
Column {
|
||||||
|
Row {
|
||||||
|
Text("kp:", Modifier.align(Alignment.CenterVertically).width(50.dp).padding(5.dp))
|
||||||
|
TextField(pidParameters.kp.toString(),{pidParameters.kp = it.toDouble()}, enabled = false)
|
||||||
|
Slider(
|
||||||
|
pidParameters.kp.toFloat(),
|
||||||
|
{ pidParameters.kp = it.toDouble()},
|
||||||
|
valueRange = 0f..10f,
|
||||||
|
steps = 100
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
Text("ki:", Modifier.align(Alignment.CenterVertically).width(50.dp).padding(5.dp))
|
||||||
|
TextField(pidParameters.ki.toString(),{pidParameters.ki = it.toDouble()}, enabled = false)
|
||||||
|
|
||||||
|
Slider(
|
||||||
|
pidParameters.ki.toFloat(),
|
||||||
|
{ pidParameters.ki = it.toDouble()},
|
||||||
|
valueRange = -5f..5f,
|
||||||
|
steps = 100
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
Text("kd:", Modifier.align(Alignment.CenterVertically).width(50.dp).padding(5.dp))
|
||||||
|
TextField(pidParameters.kd.toString(),{pidParameters.kd = it.toDouble()}, enabled = false)
|
||||||
|
|
||||||
|
Slider(
|
||||||
|
pidParameters.kd.toFloat(),
|
||||||
|
{ pidParameters.kd = it.toDouble()},
|
||||||
|
valueRange = -5f..5f,
|
||||||
|
steps = 100
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
Button({
|
||||||
|
pidParameters.run {
|
||||||
|
kp = 2.5
|
||||||
|
ki = 0.0
|
||||||
|
kd = -0.1
|
||||||
|
timeStep = 0.005.seconds
|
||||||
|
}
|
||||||
|
}){
|
||||||
|
Text("Reset")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return regulator.read(Regulator.position)
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user