Change VirtualCar state and add controller
This commit is contained in:
parent
5322bf743b
commit
7c4d0a5f36
@ -11,28 +11,33 @@ import kotlin.time.Duration
|
|||||||
import kotlin.time.ExperimentalTime
|
import kotlin.time.ExperimentalTime
|
||||||
|
|
||||||
class VirtualCar : DeviceBySpec<VirtualCar>(VirtualCar) {
|
class VirtualCar : DeviceBySpec<VirtualCar>(VirtualCar) {
|
||||||
private var speedState: Pair<Double, Double> = Pair(0.0, 0.0)
|
private var _speedState: Pair<Double, Double> = Pair(0.0, 0.0)
|
||||||
|
private val speedState: Pair<Double, Double>
|
||||||
get() {
|
get() {
|
||||||
val previous_speed = field
|
updateSpeedLocationTime()
|
||||||
val current_acceleration = this.accelerationState
|
return this._speedState
|
||||||
val now = Instant.now().toEpochMilli().toDouble()
|
|
||||||
val time_difference = now - this.timeState
|
|
||||||
this.timeState = now
|
|
||||||
field = Pair(
|
|
||||||
previous_speed.first + time_difference * current_acceleration.first,
|
|
||||||
previous_speed.second + time_difference * current_acceleration.second
|
|
||||||
)
|
|
||||||
return field
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var accelerationState: Pair<Double, Double> = Pair(0.0, 0.0)
|
private var accelerationState: Pair<Double, Double> = Pair(0.0, 0.0)
|
||||||
set(value) {
|
set(value) {
|
||||||
this.speedState
|
updateSpeedLocationTime()
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private var timeState = Instant.now().toEpochMilli().toDouble()
|
private var timeState = Instant.now().toEpochMilli().toDouble()
|
||||||
|
|
||||||
|
private fun updateSpeedLocationTime() {
|
||||||
|
val previousSpeed = this._speedState
|
||||||
|
val currentAcceleration = this.accelerationState
|
||||||
|
val now = Instant.now().toEpochMilli().toDouble()
|
||||||
|
val timeDifference = now - this.timeState
|
||||||
|
this.timeState = now
|
||||||
|
this._speedState = Pair(
|
||||||
|
previousSpeed.first + timeDifference * currentAcceleration.first * 1e-3,
|
||||||
|
previousSpeed.second + timeDifference * currentAcceleration.second * 1e-3
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
object DoublePairMetaConverter : MetaConverter<Pair<Double, Double>> {
|
object DoublePairMetaConverter : MetaConverter<Pair<Double, Double>> {
|
||||||
override fun metaToObject(meta: Meta): Pair<Double, Double> = Pair(
|
override fun metaToObject(meta: Meta): Pair<Double, Double> = Pair(
|
||||||
meta["x"].double ?: 0.0,
|
meta["x"].double ?: 0.0,
|
||||||
@ -43,7 +48,6 @@ class VirtualCar : DeviceBySpec<VirtualCar>(VirtualCar) {
|
|||||||
"x" put obj.first
|
"x" put obj.first
|
||||||
"y" put obj.second
|
"y" put obj.second
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : DeviceSpec<VirtualCar>(::VirtualCar) {
|
companion object : DeviceSpec<VirtualCar>(::VirtualCar) {
|
||||||
@ -66,7 +70,7 @@ class VirtualCar : DeviceBySpec<VirtualCar>(VirtualCar) {
|
|||||||
speed.read()
|
speed.read()
|
||||||
acceleration.read()
|
acceleration.read()
|
||||||
}
|
}
|
||||||
doRecurring(Duration.milliseconds(50)){
|
doRecurring(Duration.seconds(1)){
|
||||||
carProperties.read()
|
carProperties.read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,125 @@
|
|||||||
|
package ru.mipt.npm.controls.demo.virtual_car
|
||||||
|
|
||||||
|
import io.ktor.server.engine.ApplicationEngine
|
||||||
|
import javafx.beans.property.DoubleProperty
|
||||||
|
import javafx.scene.Parent
|
||||||
|
import javafx.scene.control.TextField
|
||||||
|
import javafx.scene.layout.Priority
|
||||||
|
import javafx.stage.Stage
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.eclipse.milo.opcua.sdk.server.OpcUaServer
|
||||||
|
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText
|
||||||
|
import ru.mipt.npm.controls.api.DeviceMessage
|
||||||
|
import ru.mipt.npm.controls.client.connectToMagix
|
||||||
|
import ru.mipt.npm.controls.controllers.DeviceManager
|
||||||
|
import ru.mipt.npm.controls.controllers.install
|
||||||
|
import ru.mipt.npm.controls.demo.virtual_car.VirtualCar.Companion.acceleration
|
||||||
|
import ru.mipt.npm.controls.opcua.server.OpcUaServer
|
||||||
|
import ru.mipt.npm.controls.opcua.server.endpoint
|
||||||
|
import ru.mipt.npm.controls.opcua.server.serveDevices
|
||||||
|
import ru.mipt.npm.magix.api.MagixEndpoint
|
||||||
|
import ru.mipt.npm.magix.rsocket.rSocketWithTcp
|
||||||
|
import ru.mipt.npm.magix.server.startMagixServer
|
||||||
|
import space.kscience.dataforge.context.*
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
class VirtualCarController : Controller(), ContextAware {
|
||||||
|
|
||||||
|
var device: VirtualCar? = null
|
||||||
|
var magixServer: ApplicationEngine? = null
|
||||||
|
var opcUaServer: OpcUaServer = OpcUaServer {
|
||||||
|
setApplicationName(LocalizedText.english("ru.mipt.npm.controls.opcua"))
|
||||||
|
endpoint {
|
||||||
|
setBindPort(9999)
|
||||||
|
//use default endpoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val context = Context("demoDevice") {
|
||||||
|
plugin(DeviceManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val deviceManager = context.fetch(DeviceManager)
|
||||||
|
|
||||||
|
fun init() {
|
||||||
|
context.launch {
|
||||||
|
device = deviceManager.install("virtual-car", VirtualCar)
|
||||||
|
//starting magix event loop
|
||||||
|
magixServer = startMagixServer(enableRawRSocket = true, enableZmq = true)
|
||||||
|
//Launch device client and connect it to the server
|
||||||
|
val deviceEndpoint = MagixEndpoint.rSocketWithTcp("localhost", DeviceMessage.serializer())
|
||||||
|
deviceManager.connectToMagix(deviceEndpoint)
|
||||||
|
|
||||||
|
opcUaServer.startup()
|
||||||
|
opcUaServer.serveDevices(deviceManager)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun shutdown() {
|
||||||
|
logger.info { "Shutting down..." }
|
||||||
|
opcUaServer.shutdown()
|
||||||
|
logger.info { "OpcUa server stopped" }
|
||||||
|
magixServer?.stop(1000, 5000)
|
||||||
|
logger.info { "Magix server stopped" }
|
||||||
|
device?.close()
|
||||||
|
logger.info { "Device server stopped" }
|
||||||
|
context.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCarControllerView : View(title = " Virtual car controller remote") {
|
||||||
|
private val controller: VirtualCarController by inject()
|
||||||
|
private var accelerationXProperty: DoubleProperty by singleAssign()
|
||||||
|
private var accelerationXTF: TextField by singleAssign()
|
||||||
|
private var accelerationYProperty: DoubleProperty by singleAssign()
|
||||||
|
private var accelerationYTF: TextField by singleAssign()
|
||||||
|
|
||||||
|
override val root: Parent = vbox {
|
||||||
|
hbox {
|
||||||
|
label("AccelerationX")
|
||||||
|
pane {
|
||||||
|
hgrow = Priority.ALWAYS
|
||||||
|
}
|
||||||
|
accelerationXProperty = doubleProperty()
|
||||||
|
accelerationXTF = textfield(accelerationXProperty)
|
||||||
|
}
|
||||||
|
hbox {
|
||||||
|
label("AccelerationY")
|
||||||
|
pane {
|
||||||
|
hgrow = Priority.ALWAYS
|
||||||
|
}
|
||||||
|
accelerationYProperty = doubleProperty()
|
||||||
|
accelerationYTF = textfield(accelerationYProperty)
|
||||||
|
}
|
||||||
|
button("Submit") {
|
||||||
|
useMaxWidth = true
|
||||||
|
action {
|
||||||
|
controller.device?.run {
|
||||||
|
launch {
|
||||||
|
acceleration.write(Pair(accelerationXProperty.get(), accelerationYProperty.get()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VirtualCarControllerApp : App(VirtualCarControllerView::class) {
|
||||||
|
private val controller: VirtualCarController by inject()
|
||||||
|
|
||||||
|
override fun start(stage: Stage) {
|
||||||
|
super.start(stage)
|
||||||
|
controller.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stop() {
|
||||||
|
controller.shutdown()
|
||||||
|
super.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
launch<VirtualCarControllerApp>()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user