Compare commits
No commits in common. "91f860adf61a3d0ee49372a99c3dc385a30bed27" and "9f21a14f96fae6588f4802903ca8dfb829db4fc7" have entirely different histories.
91f860adf6
...
9f21a14f96
@ -26,23 +26,17 @@ public class MaterialPoint(
|
|||||||
private var currentForce = force.value
|
private var currentForce = force.value
|
||||||
|
|
||||||
private val movement = onTimer(
|
private val movement = onTimer(
|
||||||
DefaultTimer.REALTIME,
|
|
||||||
reads = setOf(velocity, position),
|
reads = setOf(velocity, position),
|
||||||
writes = setOf(velocity, position)
|
writes = setOf(velocity, position)
|
||||||
) { prev, next ->
|
) { 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
|
||||||
val deltaR = (velocity.value * dtSeconds).cast(Meters) +
|
position.value += (velocity.value * dtSeconds).cast(Meters) +
|
||||||
(currentForce / mass.value * dtSeconds.pow(2) / 2).cast(Meters)
|
(currentForce / mass.value * dtSeconds.pow(2) / 2).cast(Meters)
|
||||||
position.value += deltaR
|
|
||||||
|
|
||||||
// compute new velocity based on acceleration on the previous step
|
// compute new velocity based on acceleration on the previous step
|
||||||
val deltaV = (currentForce / mass.value * dtSeconds).cast(MetersPerSecond)
|
velocity.value += (currentForce / mass.value * dtSeconds).cast(MetersPerSecond)
|
||||||
//TODO apply energy correction
|
|
||||||
//val work = deltaR.length.value * currentForce.length.value
|
|
||||||
velocity.value += deltaV
|
|
||||||
|
|
||||||
currentForce = force.value
|
currentForce = force.value
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,5 @@
|
|||||||
package space.kscience.controls.constructor.units
|
package space.kscience.controls.constructor.units
|
||||||
|
|
||||||
import kotlin.math.pow
|
|
||||||
import kotlin.math.sqrt
|
|
||||||
|
|
||||||
public data class XY<U : UnitsOfMeasurement>(val x: NumericalValue<U>, val y: NumericalValue<U>)
|
public data class XY<U : UnitsOfMeasurement>(val x: NumericalValue<U>, val y: NumericalValue<U>)
|
||||||
|
|
||||||
public fun <U : UnitsOfMeasurement> XY(x: Number, y: Number): XY<U> = XY(NumericalValue(x), NumericalValue((y)))
|
public fun <U : UnitsOfMeasurement> XY(x: Number, y: Number): XY<U> = XY(NumericalValue(x), NumericalValue((y)))
|
||||||
@ -21,11 +18,6 @@ public data class XYZ<U : UnitsOfMeasurement>(
|
|||||||
val z: NumericalValue<U>,
|
val z: NumericalValue<U>,
|
||||||
)
|
)
|
||||||
|
|
||||||
public val <U : UnitsOfMeasurement> XYZ<U>.length: NumericalValue<U>
|
|
||||||
get() = NumericalValue(
|
|
||||||
sqrt(x.value.pow(2) + y.value.pow(2) + z.value.pow(2))
|
|
||||||
)
|
|
||||||
|
|
||||||
public fun <U : UnitsOfMeasurement> XYZ(x: Number, y: Number, z: Number): XYZ<U> =
|
public fun <U : UnitsOfMeasurement> XYZ(x: Number, y: Number, z: Number): XYZ<U> =
|
||||||
XYZ(NumericalValue(x), NumericalValue((y)), NumericalValue(z))
|
XYZ(NumericalValue(x), NumericalValue((y)), NumericalValue(z))
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ import space.kscience.controls.constructor.models.MaterialPoint
|
|||||||
import space.kscience.controls.constructor.units.*
|
import space.kscience.controls.constructor.units.*
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import java.awt.Dimension
|
import java.awt.Dimension
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
|
||||||
private class Spring(
|
private class Spring(
|
||||||
@ -31,7 +33,7 @@ private class Spring(
|
|||||||
*/
|
*/
|
||||||
val tension: DeviceState<XYZ<Newtons>> = combineState(begin, end) { begin: XYZ<Meters>, end: XYZ<Meters> ->
|
val tension: DeviceState<XYZ<Newtons>> = combineState(begin, end) { begin: XYZ<Meters>, end: XYZ<Meters> ->
|
||||||
val delta = end - begin
|
val delta = end - begin
|
||||||
val l = delta.length.value
|
val l = sqrt(delta.x.value.pow(2) + delta.y.value.pow(2) + delta.z.value.pow(2))
|
||||||
((delta / l) * k * (l - l0.value)).cast(Newtons)
|
((delta / l) * k * (l - l0.value)).cast(Newtons)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +87,7 @@ private class BodyOnSprings(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun main() = application {
|
fun main() = application {
|
||||||
val initialState = XYZ<Meters>(0, 0.4, 0)
|
val initialState = XYZ<Meters>(0.01, 0.1, 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)
|
||||||
|
@ -11,10 +11,11 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.window.Window
|
import androidx.compose.ui.window.Window
|
||||||
import androidx.compose.ui.window.application
|
import androidx.compose.ui.window.application
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import space.kscience.controls.constructor.*
|
import kotlinx.coroutines.launch
|
||||||
|
import space.kscience.controls.constructor.DeviceConstructor
|
||||||
|
import space.kscience.controls.constructor.MutableDeviceState
|
||||||
|
import space.kscience.controls.constructor.device
|
||||||
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.ScrewDrive
|
||||||
@ -27,7 +28,7 @@ import java.awt.Dimension
|
|||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
private class Plotter(
|
class Plotter(
|
||||||
context: Context,
|
context: Context,
|
||||||
xDrive: StepDrive,
|
xDrive: StepDrive,
|
||||||
yDrive: StepDrive,
|
yDrive: StepDrive,
|
||||||
@ -41,16 +42,16 @@ private class Plotter(
|
|||||||
yDrive.target.value = y.toLong()
|
yDrive.target.value = y.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
val ticks = combineState(xDrive.position, yDrive.position) { x, y ->
|
// val position = combineState(xDrive.position, yDrive.position) { x, y ->
|
||||||
x to y
|
// space.kscience.controls.constructor.models.XY(x, y)
|
||||||
}
|
// }
|
||||||
|
|
||||||
//TODO add calibration
|
//TODO add calibration
|
||||||
|
|
||||||
// TODO add draw as action
|
// TODO add draw as action
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun Plotter.modernArt(xRange: IntRange, yRange: IntRange) {
|
suspend fun Plotter.modernArt(xRange: IntRange, yRange: IntRange) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
val randomX = Random.nextInt(xRange.first, xRange.last)
|
val randomX = Random.nextInt(xRange.first, xRange.last)
|
||||||
val randomY = Random.nextInt(yRange.first, yRange.last)
|
val randomY = Random.nextInt(yRange.first, yRange.last)
|
||||||
@ -61,7 +62,7 @@ private suspend fun Plotter.modernArt(xRange: IntRange, yRange: IntRange) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun Plotter.square(xRange: IntRange, yRange: IntRange) {
|
suspend fun Plotter.square(xRange: IntRange, yRange: IntRange) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
moveToXY(xRange.first, yRange.first)
|
moveToXY(xRange.first, yRange.first)
|
||||||
delay(1000)
|
delay(1000)
|
||||||
@ -93,33 +94,12 @@ private data class PlotterPoint(
|
|||||||
val color: Color = Color.Black,
|
val color: Color = Color.Black,
|
||||||
)
|
)
|
||||||
|
|
||||||
private class PlotterModel(
|
|
||||||
context: Context,
|
|
||||||
val callback: (PlotterPoint) -> Unit,
|
|
||||||
) : ModelConstructor(context) {
|
|
||||||
|
|
||||||
private val xDrive = StepDrive(context, ticksPerSecond)
|
|
||||||
private val xTransmission = ScrewDrive(context, NumericalValue(0.01))
|
|
||||||
val x = xTransmission.degreesToMeters(xDrive.angle(step)).coerceIn(xRange)
|
|
||||||
|
|
||||||
private val yDrive = StepDrive(context, ticksPerSecond)
|
|
||||||
private val yTransmission = ScrewDrive(context, NumericalValue(0.01))
|
|
||||||
val y = yTransmission.degreesToMeters(yDrive.angle(step)).coerceIn(yRange)
|
|
||||||
|
|
||||||
val xy: DeviceState<XY<Meters>> = combineState(x, y) { x, y -> XY(x, y) }
|
|
||||||
|
|
||||||
val plotter = Plotter(context, xDrive, yDrive) { color ->
|
|
||||||
println("Point X: ${x.value.value}, Y: ${y.value.value}, color: $color")
|
|
||||||
callback(PlotterPoint(x.value, y.value, color))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun main() = application {
|
suspend fun main() = application {
|
||||||
Window(title = "Pid regulator simulator", onCloseRequest = ::exitApplication) {
|
Window(title = "Pid regulator simulator", onCloseRequest = ::exitApplication) {
|
||||||
window.minimumSize = Dimension(400, 400)
|
window.minimumSize = Dimension(400, 400)
|
||||||
|
|
||||||
val points = remember { mutableStateListOf<PlotterPoint>() }
|
val points = remember { mutableStateListOf<PlotterPoint>() }
|
||||||
var position by remember { mutableStateOf(XY<Meters>(0, 0)) }
|
var position by remember { mutableStateOf(PlotterPoint(NumericalValue(0), NumericalValue(0))) }
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
val context = Context {
|
val context = Context {
|
||||||
@ -129,23 +109,42 @@ suspend fun main() = application {
|
|||||||
|
|
||||||
/* Here goes the device definition block */
|
/* Here goes the device definition block */
|
||||||
|
|
||||||
val plotterModel = PlotterModel(context) { plotterPoint ->
|
|
||||||
points.add(plotterPoint)
|
val xDrive = StepDrive(context, ticksPerSecond)
|
||||||
|
val xTransmission = ScrewDrive(context, NumericalValue(0.01))
|
||||||
|
val x = xTransmission.degreesToMeters(xDrive.angle(step)).coerceIn(xRange)
|
||||||
|
|
||||||
|
val yDrive = StepDrive(context, ticksPerSecond)
|
||||||
|
val yTransmission = ScrewDrive(context, NumericalValue(0.01))
|
||||||
|
val y = yTransmission.degreesToMeters(yDrive.angle(step)).coerceIn(yRange)
|
||||||
|
|
||||||
|
val plotter = Plotter(context, xDrive, yDrive) { color ->
|
||||||
|
println("Point X: ${x.value.value}, Y: ${y.value.value}, color: $color")
|
||||||
|
points.add(PlotterPoint(x.value, y.value, color))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Start visualization program */
|
/* Start visualization program */
|
||||||
|
|
||||||
plotterModel.xy.valueFlow.onEach {
|
launch {
|
||||||
position = it
|
x.valueFlow.collect {
|
||||||
}.launchIn(this)
|
position = position.copy(x = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch {
|
||||||
|
y.valueFlow.collect {
|
||||||
|
position = position.copy(y = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* run program */
|
/* run program */
|
||||||
|
|
||||||
|
launch {
|
||||||
val range = -1000..1000
|
val range = -1000..1000
|
||||||
// plotter.modernArt(range, range)
|
// plotter.modernArt(range, range)
|
||||||
plotterModel.plotter.square(range, range)
|
plotter.square(range, range)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user