Add compose controls to pid simulator

This commit is contained in:
Alexander Nozik 2023-11-22 21:55:13 +03:00
parent 07cc41c645
commit 81d6b672cf
3 changed files with 154 additions and 41 deletions

View File

@ -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

View File

@ -1,12 +1,13 @@
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 {
jvm{ jvm {
withJava() withJava()
} }
useKtor() useKtor()
@ -20,8 +21,31 @@ kscience {
} }
} }
application { kotlin {
mainClass.set("space.kscience.controls.demo.constructor.MainKt") sourceSets {
jvmMain {
dependencies {
implementation(compose.desktop.currentOs)
}
}
}
} }
kotlin.explicitApi = ExplicitApiMode.Disabled //application {
// mainClass.set("space.kscience.controls.demo.constructor.MainKt")
//}
kotlin.explicitApi = ExplicitApiMode.Disabled
compose.desktop {
application {
mainClass = "space.kscience.controls.demo.constructor.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Exe)
packageName = "PidConstructor"
packageVersion = "1.0.0"
}
}
}

View File

@ -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)
while(!limitEnd.read(LimitSwitch.locked)){ plugin(ClockManager)
delay(10.milliseconds) }
regulator.write(Regulator.target, regulator.read(Regulator.position) + 0.1)
class MutablePidParameters(
kp: Double,
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)
} }