Fix PID demo
This commit is contained in:
parent
91f860adf6
commit
c63c2db651
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
# Created by .ignore support plugin (hsz.mobi)
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
.idea/
|
.idea/
|
||||||
.gradle
|
.gradle
|
||||||
|
.kotlin
|
||||||
|
|
||||||
*.iws
|
*.iws
|
||||||
*.iml
|
*.iml
|
||||||
|
@ -24,7 +24,7 @@ public class Inertia<U : UnitsOfMeasurement, V : UnitsOfMeasurement>(
|
|||||||
|
|
||||||
private var currentForce = force.value
|
private var currentForce = force.value
|
||||||
|
|
||||||
private val movement = onTimer { prev, next ->
|
private val movement = onTimer(DefaultTimer.REALTIME) { prev, next ->
|
||||||
val dtSeconds = (next - prev).toDouble(DurationUnit.SECONDS)
|
val dtSeconds = (next - prev).toDouble(DurationUnit.SECONDS)
|
||||||
|
|
||||||
// compute new value based on velocity and acceleration from the previous step
|
// compute new value based on velocity and acceleration from the previous step
|
||||||
|
@ -7,15 +7,18 @@ import space.kscience.controls.constructor.units.*
|
|||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
|
||||||
public class ScrewDrive(
|
/**
|
||||||
|
* https://en.wikipedia.org/wiki/Leadscrew
|
||||||
|
*/
|
||||||
|
public class Leadscrew(
|
||||||
context: Context,
|
context: Context,
|
||||||
public val leverage: NumericalValue<Meters>,
|
public val leverage: NumericalValue<Meters>,
|
||||||
) : ModelConstructor(context) {
|
) : ModelConstructor(context) {
|
||||||
|
|
||||||
public fun torqueToForce(
|
public fun torqueToForce(
|
||||||
stateOfMomentum: DeviceState<NumericalValue<NewtonsMeters>>,
|
stateOfTorque: DeviceState<NumericalValue<NewtonsMeters>>,
|
||||||
): DeviceState<NumericalValue<Newtons>> = DeviceState.map(stateOfMomentum) { momentum ->
|
): DeviceState<NumericalValue<Newtons>> = DeviceState.map(stateOfTorque) { torque ->
|
||||||
NumericalValue(momentum.value / leverage.value )
|
NumericalValue(torque.value / leverage.value )
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun degreesToMeters(
|
public fun degreesToMeters(
|
@ -3,12 +3,20 @@ package space.kscience.controls.vision
|
|||||||
import kotlinx.serialization.modules.SerializersModule
|
import kotlinx.serialization.modules.SerializersModule
|
||||||
import kotlinx.serialization.modules.polymorphic
|
import kotlinx.serialization.modules.polymorphic
|
||||||
import kotlinx.serialization.modules.subclass
|
import kotlinx.serialization.modules.subclass
|
||||||
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.PluginFactory
|
import space.kscience.dataforge.context.PluginFactory
|
||||||
|
import space.kscience.dataforge.context.PluginTag
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionPlugin
|
import space.kscience.visionforge.VisionPlugin
|
||||||
|
|
||||||
public expect class ControlVisionPlugin: VisionPlugin{
|
public expect class ControlVisionPlugin: VisionPlugin{
|
||||||
public companion object: PluginFactory<ControlVisionPlugin>
|
override val tag: PluginTag
|
||||||
|
override val visionSerializersModule: SerializersModule
|
||||||
|
public companion object: PluginFactory<ControlVisionPlugin>{
|
||||||
|
override val tag: PluginTag
|
||||||
|
override fun build(context: Context, meta: Meta): ControlVisionPlugin
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val controlsVisionSerializersModule = SerializersModule {
|
internal val controlsVisionSerializersModule = SerializersModule {
|
||||||
|
@ -158,7 +158,7 @@ public fun <T> Plot.plotDeviceState(
|
|||||||
|
|
||||||
public fun Plot.plotNumberState(
|
public fun Plot.plotNumberState(
|
||||||
context: Context,
|
context: Context,
|
||||||
state: DeviceState<out Number>,
|
state: DeviceState<Number>,
|
||||||
maxAge: Duration = defaultMaxAge,
|
maxAge: Duration = defaultMaxAge,
|
||||||
maxPoints: Int = defaultMaxPoints,
|
maxPoints: Int = defaultMaxPoints,
|
||||||
minPoints: Int = defaultMinPoints,
|
minPoints: Int = defaultMinPoints,
|
||||||
|
@ -43,9 +43,9 @@ private val sliderRenderer = ElementVisionRenderer<SliderVision> { name, vision:
|
|||||||
|
|
||||||
|
|
||||||
public actual class ControlVisionPlugin : VisionPlugin() {
|
public actual class ControlVisionPlugin : VisionPlugin() {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
actual override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
override val visionSerializersModule: SerializersModule get() = controlsVisionSerializersModule
|
actual override val visionSerializersModule: SerializersModule get() = controlsVisionSerializersModule
|
||||||
|
|
||||||
override fun content(target: String): Map<Name, Any> = when (target) {
|
override fun content(target: String): Map<Name, Any> = when (target) {
|
||||||
ElementVisionRenderer.TYPE -> mapOf(
|
ElementVisionRenderer.TYPE -> mapOf(
|
||||||
@ -57,9 +57,9 @@ public actual class ControlVisionPlugin : VisionPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public actual companion object : PluginFactory<ControlVisionPlugin> {
|
public actual companion object : PluginFactory<ControlVisionPlugin> {
|
||||||
override val tag: PluginTag = PluginTag("controls.vision")
|
actual override val tag: PluginTag = PluginTag("controls.vision")
|
||||||
|
|
||||||
override fun build(context: Context, meta: Meta): ControlVisionPlugin = ControlVisionPlugin()
|
actual override fun build(context: Context, meta: Meta): ControlVisionPlugin = ControlVisionPlugin()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,14 +8,14 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
import space.kscience.visionforge.VisionPlugin
|
import space.kscience.visionforge.VisionPlugin
|
||||||
|
|
||||||
public actual class ControlVisionPlugin : VisionPlugin() {
|
public actual class ControlVisionPlugin : VisionPlugin() {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
actual override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
override val visionSerializersModule: SerializersModule get() = controlsVisionSerializersModule
|
actual override val visionSerializersModule: SerializersModule get() = controlsVisionSerializersModule
|
||||||
|
|
||||||
public actual companion object : PluginFactory<ControlVisionPlugin> {
|
public actual companion object : PluginFactory<ControlVisionPlugin> {
|
||||||
override val tag: PluginTag = PluginTag("controls.vision")
|
actual override val tag: PluginTag = PluginTag("controls.vision")
|
||||||
|
|
||||||
override fun build(context: Context, meta: Meta): ControlVisionPlugin = ControlVisionPlugin()
|
actual override fun build(context: Context, meta: Meta): ControlVisionPlugin = ControlVisionPlugin()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,8 @@ import org.jetbrains.compose.ExperimentalComposeLibrary
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
alias(spclibs.plugins.compose)
|
alias(spclibs.plugins.compose.compiler)
|
||||||
|
alias(spclibs.plugins.compose.jb)
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@ package space.kscience.controls.compose
|
|||||||
|
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@ -30,7 +30,7 @@ public fun NumberTextField(
|
|||||||
Row (verticalAlignment = Alignment.CenterVertically, modifier = modifier) {
|
Row (verticalAlignment = Alignment.CenterVertically, modifier = modifier) {
|
||||||
step.takeIf { it > 0.0 }?.let {
|
step.takeIf { it > 0.0 }?.let {
|
||||||
IconButton({ onValueChange(value.toDouble() - step) }, enabled = enabled) {
|
IconButton({ onValueChange(value.toDouble() - step) }, enabled = enabled) {
|
||||||
Icon(Icons.Default.KeyboardArrowLeft, "decrease value")
|
Icon(Icons.AutoMirrored.Filled.KeyboardArrowLeft, "decrease value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TextField(
|
TextField(
|
||||||
@ -52,7 +52,7 @@ public fun NumberTextField(
|
|||||||
)
|
)
|
||||||
step.takeIf { it > 0.0 }?.let {
|
step.takeIf { it > 0.0 }?.let {
|
||||||
IconButton({ onValueChange(value.toDouble() + step) }, enabled = enabled) {
|
IconButton({ onValueChange(value.toDouble() + step) }, enabled = enabled) {
|
||||||
Icon(Icons.Default.KeyboardArrowRight, "increase value")
|
Icon(Icons.AutoMirrored.Filled.KeyboardArrowRight, "increase value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
alias(spclibs.plugins.compose)
|
alias(spclibs.plugins.compose.compiler)
|
||||||
|
alias(spclibs.plugins.compose.jb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
alias(spclibs.plugins.compose)
|
alias(spclibs.plugins.compose.compiler)
|
||||||
|
alias(spclibs.plugins.compose.jb)
|
||||||
}
|
}
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
|
@ -85,7 +85,7 @@ private class BodyOnSprings(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun main() = application {
|
fun main() = application {
|
||||||
val initialState = XYZ<Meters>(0, 0.4, 0)
|
val initialState = XYZ<Meters>(0.05, 0.4, 0)
|
||||||
|
|
||||||
Window(title = "Ball on springs", onCloseRequest = ::exitApplication) {
|
Window(title = "Ball on springs", onCloseRequest = ::exitApplication) {
|
||||||
window.minimumSize = Dimension(400, 400)
|
window.minimumSize = Dimension(400, 400)
|
||||||
|
@ -32,10 +32,10 @@ import space.kscience.controls.constructor.devices.Drive
|
|||||||
import space.kscience.controls.constructor.devices.LimitSwitch
|
import space.kscience.controls.constructor.devices.LimitSwitch
|
||||||
import space.kscience.controls.constructor.devices.LinearDrive
|
import space.kscience.controls.constructor.devices.LinearDrive
|
||||||
import space.kscience.controls.constructor.models.Inertia
|
import space.kscience.controls.constructor.models.Inertia
|
||||||
|
import space.kscience.controls.constructor.models.Leadscrew
|
||||||
import space.kscience.controls.constructor.models.MutableRangeState
|
import space.kscience.controls.constructor.models.MutableRangeState
|
||||||
import space.kscience.controls.constructor.models.PidParameters
|
import space.kscience.controls.constructor.models.PidParameters
|
||||||
import space.kscience.controls.constructor.models.ScrewDrive
|
import space.kscience.controls.constructor.onTimer
|
||||||
import space.kscience.controls.constructor.timer
|
|
||||||
import space.kscience.controls.constructor.units.Kilograms
|
import space.kscience.controls.constructor.units.Kilograms
|
||||||
import space.kscience.controls.constructor.units.Meters
|
import space.kscience.controls.constructor.units.Meters
|
||||||
import space.kscience.controls.constructor.units.NumericalValue
|
import space.kscience.controls.constructor.units.NumericalValue
|
||||||
@ -56,13 +56,13 @@ import kotlin.time.DurationUnit
|
|||||||
class Modulator(
|
class Modulator(
|
||||||
context: Context,
|
context: Context,
|
||||||
target: MutableDeviceState<NumericalValue<Meters>>,
|
target: MutableDeviceState<NumericalValue<Meters>>,
|
||||||
var freq: Double = 0.1,
|
|
||||||
var timeStep: Duration = 5.milliseconds,
|
var timeStep: Duration = 5.milliseconds,
|
||||||
|
var freq: Double = 0.1,
|
||||||
) : DeviceConstructor(context) {
|
) : DeviceConstructor(context) {
|
||||||
private val clockStart = clock.now()
|
private val clockStart = clock.now()
|
||||||
|
|
||||||
private val modulation = timer(10.milliseconds).onNext {
|
private val modulation = onTimer(timeStep) { _, next ->
|
||||||
val timeFromStart = clock.now() - clockStart
|
val timeFromStart = next - clockStart
|
||||||
val t = timeFromStart.toDouble(DurationUnit.SECONDS)
|
val t = timeFromStart.toDouble(DurationUnit.SECONDS)
|
||||||
target.value = NumericalValue(
|
target.value = NumericalValue(
|
||||||
5 * sin(2.0 * PI * freq * t) +
|
5 * sin(2.0 * PI * freq * t) +
|
||||||
@ -72,9 +72,9 @@ class Modulator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val mass = NumericalValue<Kilograms>(0.1)
|
private val mass = NumericalValue<Kilograms>(1)
|
||||||
|
|
||||||
private val leverage = NumericalValue<Meters>(0.05)
|
private val leverage = NumericalValue<Meters>(1.0)
|
||||||
|
|
||||||
private val maxAge = 10.seconds
|
private val maxAge = 10.seconds
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ internal fun createLinearDriveModel(
|
|||||||
val drive = Drive(context)
|
val drive = Drive(context)
|
||||||
|
|
||||||
//a screw drive to convert a rotational moment into a force
|
//a screw drive to convert a rotational moment into a force
|
||||||
val screwDrive = ScrewDrive(context, leverage)
|
val leadscrew = Leadscrew(context, leverage)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,7 +107,7 @@ internal fun createLinearDriveModel(
|
|||||||
*/
|
*/
|
||||||
val inertiaModel = Inertia.linear(
|
val inertiaModel = Inertia.linear(
|
||||||
context = context,
|
context = context,
|
||||||
force = screwDrive.torqueToForce(drive.force),
|
force = leadscrew.torqueToForce(drive.force),
|
||||||
mass = mass,
|
mass = mass,
|
||||||
position = position
|
position = position
|
||||||
)
|
)
|
||||||
@ -130,6 +130,8 @@ private fun createModulator(linearDrive: LinearDrive): Modulator = linearDrive.c
|
|||||||
Modulator(linearDrive.context, linearDrive.pid.target)
|
Modulator(linearDrive.context, linearDrive.pid.target)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val startPid = PidParameters(kp = 250.0, ki = 0.0, kd = -20.0, timeStep = 20.milliseconds)
|
||||||
|
|
||||||
@OptIn(ExperimentalSplitPaneApi::class, ExperimentalKoalaPlotApi::class)
|
@OptIn(ExperimentalSplitPaneApi::class, ExperimentalKoalaPlotApi::class)
|
||||||
fun main() = application {
|
fun main() = application {
|
||||||
val context = remember {
|
val context = remember {
|
||||||
@ -140,7 +142,7 @@ fun main() = application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pidParameters by remember {
|
var pidParameters by remember {
|
||||||
mutableStateOf(PidParameters(kp = 900.0, ki = 20.0, kd = -50.0, timeStep = 0.005.seconds))
|
mutableStateOf(startPid)
|
||||||
}
|
}
|
||||||
|
|
||||||
val linearDrive: LinearDrive = remember {
|
val linearDrive: LinearDrive = remember {
|
||||||
@ -183,14 +185,14 @@ fun main() = application {
|
|||||||
NumberTextField(
|
NumberTextField(
|
||||||
value = pidParameters.kp,
|
value = pidParameters.kp,
|
||||||
onValueChange = { pidParameters = pidParameters.copy(kp = it.toDouble()) },
|
onValueChange = { pidParameters = pidParameters.copy(kp = it.toDouble()) },
|
||||||
formatter = { String.format("%.2f", it.toDouble()) },
|
formatter = { String.format("%.3f", it.toDouble()) },
|
||||||
step = 1.0,
|
step = 0.01,
|
||||||
modifier = Modifier.width(200.dp),
|
modifier = Modifier.width(200.dp),
|
||||||
)
|
)
|
||||||
Slider(
|
Slider(
|
||||||
pidParameters.kp.toFloat(),
|
pidParameters.kp.toFloat(),
|
||||||
{ pidParameters = pidParameters.copy(kp = it.toDouble()) },
|
{ pidParameters = pidParameters.copy(kp = it.toDouble()) },
|
||||||
valueRange = 0f..1000f,
|
valueRange = 0f..100f,
|
||||||
steps = 100
|
steps = 100
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -199,15 +201,15 @@ fun main() = application {
|
|||||||
NumberTextField(
|
NumberTextField(
|
||||||
value = pidParameters.ki,
|
value = pidParameters.ki,
|
||||||
onValueChange = { pidParameters = pidParameters.copy(ki = it.toDouble()) },
|
onValueChange = { pidParameters = pidParameters.copy(ki = it.toDouble()) },
|
||||||
formatter = { String.format("%.2f", it.toDouble()) },
|
formatter = { String.format("%.3f", it.toDouble()) },
|
||||||
step = 0.1,
|
step = 0.01,
|
||||||
modifier = Modifier.width(200.dp),
|
modifier = Modifier.width(200.dp),
|
||||||
)
|
)
|
||||||
|
|
||||||
Slider(
|
Slider(
|
||||||
pidParameters.ki.toFloat(),
|
pidParameters.ki.toFloat(),
|
||||||
{ pidParameters = pidParameters.copy(ki = it.toDouble()) },
|
{ pidParameters = pidParameters.copy(ki = it.toDouble()) },
|
||||||
valueRange = -100f..100f,
|
valueRange = -10f..10f,
|
||||||
steps = 100
|
steps = 100
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -216,15 +218,15 @@ fun main() = application {
|
|||||||
NumberTextField(
|
NumberTextField(
|
||||||
value = pidParameters.kd,
|
value = pidParameters.kd,
|
||||||
onValueChange = { pidParameters = pidParameters.copy(kd = it.toDouble()) },
|
onValueChange = { pidParameters = pidParameters.copy(kd = it.toDouble()) },
|
||||||
formatter = { String.format("%.2f", it.toDouble()) },
|
formatter = { String.format("%.3f", it.toDouble()) },
|
||||||
step = 0.1,
|
step = 0.01,
|
||||||
modifier = Modifier.width(200.dp),
|
modifier = Modifier.width(200.dp),
|
||||||
)
|
)
|
||||||
|
|
||||||
Slider(
|
Slider(
|
||||||
pidParameters.kd.toFloat(),
|
pidParameters.kd.toFloat(),
|
||||||
{ pidParameters = pidParameters.copy(kd = it.toDouble()) },
|
{ pidParameters = pidParameters.copy(kd = it.toDouble()) },
|
||||||
valueRange = -100f..100f,
|
valueRange = -10f..10f,
|
||||||
steps = 100
|
steps = 100
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -247,12 +249,7 @@ fun main() = application {
|
|||||||
}
|
}
|
||||||
Row {
|
Row {
|
||||||
Button({
|
Button({
|
||||||
pidParameters = PidParameters(
|
pidParameters = startPid
|
||||||
kp = 2.5,
|
|
||||||
ki = 0.0,
|
|
||||||
kd = -0.1,
|
|
||||||
timeStep = 0.005.seconds
|
|
||||||
)
|
|
||||||
}) {
|
}) {
|
||||||
Text("Reset")
|
Text("Reset")
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import kotlinx.coroutines.isActive
|
|||||||
import space.kscience.controls.constructor.*
|
import space.kscience.controls.constructor.*
|
||||||
import space.kscience.controls.constructor.devices.StepDrive
|
import space.kscience.controls.constructor.devices.StepDrive
|
||||||
import space.kscience.controls.constructor.devices.angle
|
import space.kscience.controls.constructor.devices.angle
|
||||||
import space.kscience.controls.constructor.models.ScrewDrive
|
import space.kscience.controls.constructor.models.Leadscrew
|
||||||
import space.kscience.controls.constructor.models.coerceIn
|
import space.kscience.controls.constructor.models.coerceIn
|
||||||
import space.kscience.controls.constructor.units.*
|
import space.kscience.controls.constructor.units.*
|
||||||
import space.kscience.controls.manager.ClockManager
|
import space.kscience.controls.manager.ClockManager
|
||||||
@ -99,11 +99,11 @@ private class PlotterModel(
|
|||||||
) : ModelConstructor(context) {
|
) : ModelConstructor(context) {
|
||||||
|
|
||||||
private val xDrive = StepDrive(context, ticksPerSecond)
|
private val xDrive = StepDrive(context, ticksPerSecond)
|
||||||
private val xTransmission = ScrewDrive(context, NumericalValue(0.01))
|
private val xTransmission = Leadscrew(context, NumericalValue(0.01))
|
||||||
val x = xTransmission.degreesToMeters(xDrive.angle(step)).coerceIn(xRange)
|
val x = xTransmission.degreesToMeters(xDrive.angle(step)).coerceIn(xRange)
|
||||||
|
|
||||||
private val yDrive = StepDrive(context, ticksPerSecond)
|
private val yDrive = StepDrive(context, ticksPerSecond)
|
||||||
private val yTransmission = ScrewDrive(context, NumericalValue(0.01))
|
private val yTransmission = Leadscrew(context, NumericalValue(0.01))
|
||||||
val y = yTransmission.degreesToMeters(yDrive.angle(step)).coerceIn(yRange)
|
val y = yTransmission.degreesToMeters(yDrive.angle(step)).coerceIn(yRange)
|
||||||
|
|
||||||
val xy: DeviceState<XY<Meters>> = combineState(x, y) { x, y -> XY(x, y) }
|
val xy: DeviceState<XY<Meters>> = combineState(x, y) { x, y -> XY(x, y) }
|
||||||
@ -143,7 +143,7 @@ suspend fun main() = application {
|
|||||||
|
|
||||||
|
|
||||||
val range = -1000..1000
|
val range = -1000..1000
|
||||||
// plotter.modernArt(range, range)
|
// plotterModel.plotter.modernArt(range, range)
|
||||||
plotterModel.plotter.square(range, range)
|
plotterModel.plotter.square(range, range)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
41
demo/devices-on-map/build.gradle.kts
Normal file
41
demo/devices-on-map/build.gradle.kts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("space.kscience.gradle.mpp")
|
||||||
|
alias(spclibs.plugins.compose.compiler)
|
||||||
|
alias(spclibs.plugins.compose.jb)
|
||||||
|
}
|
||||||
|
|
||||||
|
kscience {
|
||||||
|
jvm()
|
||||||
|
useSerialization()
|
||||||
|
useContextReceivers()
|
||||||
|
commonMain {
|
||||||
|
implementation(projects.controlsVisualisationCompose)
|
||||||
|
implementation(projects.controlsConstructor)
|
||||||
|
}
|
||||||
|
jvmMain {
|
||||||
|
// implementation("io.ktor:ktor-server-cio")
|
||||||
|
implementation(spclibs.logback.classic)
|
||||||
|
implementation(libs.sciprog.maps.compose)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
jvmMain {
|
||||||
|
dependencies {
|
||||||
|
implementation(compose.desktop.currentOs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin.explicitApi = ExplicitApiMode.Disabled
|
||||||
|
|
||||||
|
|
||||||
|
compose.desktop {
|
||||||
|
application {
|
||||||
|
mainClass = "space.kscience.controls.demo.map.MainKt"
|
||||||
|
}
|
||||||
|
}
|
8
demo/devices-on-map/src/jvmMain/kotlin/main.kt
Normal file
8
demo/devices-on-map/src/jvmMain/kotlin/main.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package space.kscience.controls.demo.map
|
||||||
|
|
||||||
|
import androidx.compose.ui.window.application
|
||||||
|
|
||||||
|
|
||||||
|
fun main() = application {
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.jvm")
|
id("space.kscience.gradle.jvm")
|
||||||
alias(spclibs.plugins.compose)
|
alias(spclibs.plugins.compose.compiler)
|
||||||
|
alias(spclibs.plugins.compose.jb)
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin{
|
kotlin{
|
||||||
|
@ -7,4 +7,4 @@ org.gradle.parallel=true
|
|||||||
org.gradle.configureondemand=true
|
org.gradle.configureondemand=true
|
||||||
org.gradle.jvmargs=-Xmx4096m
|
org.gradle.jvmargs=-Xmx4096m
|
||||||
|
|
||||||
toolsVersion=0.15.2-kotlin-1.9.22
|
toolsVersion=0.15.4-kotlin-2.0.0
|
@ -81,6 +81,8 @@ visionforge-markdown = { module = "space.kscience:visionforge-markdown", version
|
|||||||
visionforge-server = { module = "space.kscience:visionforge-server", version.ref = "visionforge" }
|
visionforge-server = { module = "space.kscience:visionforge-server", version.ref = "visionforge" }
|
||||||
visionforge-compose-html = { module = "space.kscience:visionforge-compose-html", version.ref = "visionforge" }
|
visionforge-compose-html = { module = "space.kscience:visionforge-compose-html", version.ref = "visionforge" }
|
||||||
|
|
||||||
|
sciprog-maps-compose = "space.kscience:maps-kt-compose:0.3.0"
|
||||||
|
|
||||||
# Buildscript
|
# Buildscript
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
@ -86,5 +86,6 @@ include(
|
|||||||
":demo:motors",
|
":demo:motors",
|
||||||
":demo:echo",
|
":demo:echo",
|
||||||
":demo:mks-pdr900",
|
":demo:mks-pdr900",
|
||||||
":demo:constructor"
|
":demo:constructor",
|
||||||
|
":demo:devices-on-map"
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user