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
|
||||
*/
|
||||
public data class PidParameters(
|
||||
public val kp: Double,
|
||||
public val ki: Double,
|
||||
public val kd: Double,
|
||||
public val timeStep: Duration = 1.milliseconds,
|
||||
)
|
||||
public interface PidParameters {
|
||||
public val kp: Double
|
||||
public val ki: Double
|
||||
public val kd: Double
|
||||
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
|
||||
|
@ -1,12 +1,13 @@
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
|
||||
|
||||
plugins {
|
||||
id("space.kscience.gradle.mpp")
|
||||
application
|
||||
id("org.jetbrains.compose") version "1.5.10"
|
||||
}
|
||||
|
||||
kscience {
|
||||
jvm{
|
||||
jvm {
|
||||
withJava()
|
||||
}
|
||||
useKtor()
|
||||
@ -20,8 +21,31 @@ kscience {
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("space.kscience.controls.demo.constructor.MainKt")
|
||||
kotlin {
|
||||
sourceSets {
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,26 @@
|
||||
package space.kscience.controls.demo.constructor
|
||||
|
||||
import kotlinx.coroutines.delay
|
||||
import space.kscience.controls.api.get
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.manager.ClockManager
|
||||
import space.kscience.controls.manager.DeviceManager
|
||||
import space.kscience.controls.manager.clock
|
||||
import space.kscience.controls.spec.doRecurring
|
||||
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.plotDeviceProperty
|
||||
import space.kscience.controls.vision.plotNumberState
|
||||
@ -21,6 +32,7 @@ import space.kscience.plotly.models.ScatterMode
|
||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.sin
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.DurationUnit
|
||||
@ -46,23 +58,15 @@ class LinearDrive(
|
||||
}
|
||||
|
||||
|
||||
fun main() {
|
||||
val context = Context {
|
||||
plugin(DeviceManager)
|
||||
plugin(PlotlyPlugin)
|
||||
plugin(ClockManager)
|
||||
}
|
||||
|
||||
val state = DoubleRangeState(0.0, -5.0..5.0)
|
||||
|
||||
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 {
|
||||
private fun Context.launchPidDevice(
|
||||
state: DoubleRangeState,
|
||||
pidParameters: PidParameters,
|
||||
mass: Double,
|
||||
) = launch {
|
||||
val device = install(
|
||||
"device",
|
||||
LinearDrive(this@launchPidDevice, state, mass, pidParameters)
|
||||
).apply {
|
||||
val clock = context.clock
|
||||
val clockStart = clock.now()
|
||||
doRecurring(10.milliseconds) {
|
||||
@ -78,7 +82,7 @@ fun main() {
|
||||
|
||||
val maxAge = 10.seconds
|
||||
|
||||
context.showDashboard {
|
||||
showDashboard {
|
||||
plot {
|
||||
plotNumberState(context, state, maxAge = maxAge) {
|
||||
name = "real position"
|
||||
@ -106,13 +110,88 @@ fun main() {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun DeviceGroup.findEnd(): Double{
|
||||
val regulator = get("pid") as Regulator
|
||||
val limitEnd = get("end") as LimitSwitch
|
||||
|
||||
while(!limitEnd.read(LimitSwitch.locked)){
|
||||
delay(10.milliseconds)
|
||||
regulator.write(Regulator.target, regulator.read(Regulator.position) + 0.1)
|
||||
fun main() = application {
|
||||
val context = Context {
|
||||
plugin(DeviceManager)
|
||||
plugin(PlotlyPlugin)
|
||||
plugin(ClockManager)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user