More or less working motors app
This commit is contained in:
parent
62dc6ef127
commit
599d08b62a
@ -93,6 +93,21 @@ public fun DeviceBase.readingNumber(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
public fun DeviceBase.readingDouble(
|
||||||
|
default: Number? = null,
|
||||||
|
descriptorBuilder: PropertyDescriptor.() -> Unit = {},
|
||||||
|
getter: suspend () -> Double,
|
||||||
|
): PropertyDelegateProvider<DeviceBase, TypedReadOnlyPropertyDelegate<Double>> = TypedReadOnlyDevicePropertyProvider(
|
||||||
|
this,
|
||||||
|
default?.let { MetaItem.ValueItem(it.asValue()) },
|
||||||
|
MetaConverter.double,
|
||||||
|
descriptorBuilder,
|
||||||
|
getter = {
|
||||||
|
val number = getter()
|
||||||
|
MetaItem.ValueItem(number.asValue())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
public fun DeviceBase.readingString(
|
public fun DeviceBase.readingString(
|
||||||
default: String? = null,
|
default: String? = null,
|
||||||
descriptorBuilder: PropertyDescriptor.() -> Unit = {},
|
descriptorBuilder: PropertyDescriptor.() -> Unit = {},
|
||||||
|
@ -7,9 +7,11 @@ import javafx.beans.property.ReadOnlyProperty
|
|||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import javafx.collections.FXCollections
|
import javafx.geometry.Pos
|
||||||
import javafx.scene.Parent
|
import javafx.scene.Parent
|
||||||
import javafx.scene.layout.Priority
|
import javafx.scene.layout.Priority
|
||||||
|
import javafx.scene.layout.VBox
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
@ -27,6 +29,51 @@ class PiMotionMasterController : Controller() {
|
|||||||
val motionMaster: PiMotionMasterDevice by deviceManager.installing(PiMotionMasterDevice)
|
val motionMaster: PiMotionMasterDevice by deviceManager.installing(PiMotionMasterDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun VBox.piMotionMasterAxis(
|
||||||
|
axisName: String,
|
||||||
|
axis: PiMotionMasterDevice.Axis,
|
||||||
|
coroutineScope: CoroutineScope,
|
||||||
|
) = hbox {
|
||||||
|
alignment = Pos.CENTER
|
||||||
|
label(axisName)
|
||||||
|
coroutineScope.launch {
|
||||||
|
val min = axis.minPosition.readTyped(true)
|
||||||
|
val max = axis.maxPosition.readTyped(true)
|
||||||
|
val positionProperty = axis.position.fxProperty(axis)
|
||||||
|
val startPosition = axis.position.readTyped(true)
|
||||||
|
runLater {
|
||||||
|
vbox {
|
||||||
|
hgrow = Priority.ALWAYS
|
||||||
|
slider(min..max, startPosition) {
|
||||||
|
minWidth = 300.0
|
||||||
|
isShowTickLabels = true
|
||||||
|
isShowTickMarks = true
|
||||||
|
minorTickCount = 10
|
||||||
|
majorTickUnit = 1.0
|
||||||
|
valueProperty().onChange {
|
||||||
|
coroutineScope.launch {
|
||||||
|
axis.move(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slider(min..max) {
|
||||||
|
isDisable = true
|
||||||
|
valueProperty().bind(positionProperty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Parent.axisPane(axes: Map<String, PiMotionMasterDevice.Axis>, coroutineScope: CoroutineScope) {
|
||||||
|
vbox {
|
||||||
|
axes.forEach { (name, axis) ->
|
||||||
|
this.piMotionMasterAxis(name, axis, coroutineScope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class PiMotionMasterView : View() {
|
class PiMotionMasterView : View() {
|
||||||
|
|
||||||
private val controller: PiMotionMasterController by inject()
|
private val controller: PiMotionMasterController by inject()
|
||||||
@ -35,7 +82,7 @@ class PiMotionMasterView : View() {
|
|||||||
private val connectedProperty: ReadOnlyProperty<Boolean> = device.connected.fxProperty(device)
|
private val connectedProperty: ReadOnlyProperty<Boolean> = device.connected.fxProperty(device)
|
||||||
private val debugServerJobProperty = SimpleObjectProperty<Job>()
|
private val debugServerJobProperty = SimpleObjectProperty<Job>()
|
||||||
private val debugServerStarted = debugServerJobProperty.booleanBinding { it != null }
|
private val debugServerStarted = debugServerJobProperty.booleanBinding { it != null }
|
||||||
private val axisList = FXCollections.observableArrayList<Map.Entry<String, PiMotionMasterDevice.Axis>>()
|
//private val axisList = FXCollections.observableArrayList<Map.Entry<String, PiMotionMasterDevice.Axis>>()
|
||||||
|
|
||||||
override val root: Parent = borderpane {
|
override val root: Parent = borderpane {
|
||||||
top {
|
top {
|
||||||
@ -86,9 +133,11 @@ class PiMotionMasterView : View() {
|
|||||||
action {
|
action {
|
||||||
if (!connectedProperty.value) {
|
if (!connectedProperty.value) {
|
||||||
device.connect(host.get(), port.get())
|
device.connect(host.get(), port.get())
|
||||||
axisList.addAll(device.axes.entries)
|
center {
|
||||||
|
axisPane(device.axes,controller.context)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
axisList.removeAll()
|
this@borderpane.center = null
|
||||||
device.disconnect()
|
device.disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,34 +147,6 @@ class PiMotionMasterView : View() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
center {
|
|
||||||
listview(axisList) {
|
|
||||||
cellFormat { (name, axis) ->
|
|
||||||
hbox {
|
|
||||||
minHeight = 40.0
|
|
||||||
label(name)
|
|
||||||
controller.context.launch {
|
|
||||||
val min = axis.minPosition.readTyped(true)
|
|
||||||
val max = axis.maxPosition.readTyped(true)
|
|
||||||
runLater {
|
|
||||||
slider(min.toDouble()..max.toDouble()){
|
|
||||||
hgrow = Priority.ALWAYS
|
|
||||||
valueProperty().onChange {
|
|
||||||
isDisable = true
|
|
||||||
launch {
|
|
||||||
axis.move(value)
|
|
||||||
runLater {
|
|
||||||
isDisable = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ class PiMotionMasterDevice(
|
|||||||
private suspend fun requestAndParse(command: String, vararg arguments: String): Map<String, String> = buildMap {
|
private suspend fun requestAndParse(command: String, vararg arguments: String): Map<String, String> = buildMap {
|
||||||
request(command, *arguments).forEach { line ->
|
request(command, *arguments).forEach { line ->
|
||||||
val (key, value) = line.split("=")
|
val (key, value) = line.split("=")
|
||||||
put(key, value)
|
put(key, value.trim())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ class PiMotionMasterDevice(
|
|||||||
send("FRF", axisId)
|
send("FRF", axisId)
|
||||||
}
|
}
|
||||||
|
|
||||||
val minPosition by readingNumber(
|
val minPosition by readingDouble(
|
||||||
descriptorBuilder = {
|
descriptorBuilder = {
|
||||||
info = "Minimal position value for the axis"
|
info = "Minimal position value for the axis"
|
||||||
},
|
},
|
||||||
@ -287,7 +287,7 @@ class PiMotionMasterDevice(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val maxPosition by readingNumber(
|
val maxPosition by readingDouble(
|
||||||
descriptorBuilder = {
|
descriptorBuilder = {
|
||||||
info = "Maximal position value for the axis"
|
info = "Maximal position value for the axis"
|
||||||
},
|
},
|
||||||
@ -297,9 +297,15 @@ class PiMotionMasterDevice(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val position: TypedDeviceProperty<Double> by axisNumberProperty("POS") {
|
val position by readingDouble(
|
||||||
|
descriptorBuilder = {
|
||||||
info = "The current axis position."
|
info = "The current axis position."
|
||||||
|
},
|
||||||
|
getter = {
|
||||||
|
requestAndParse("POS?", axisId)[axisId]?.toDoubleOrNull()
|
||||||
|
?: error("Malformed `POS?` response. Should include float value for $axisId")
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
val openLoopTarget: DeviceProperty by axisNumberProperty("OMA") {
|
val openLoopTarget: DeviceProperty by axisNumberProperty("OMA") {
|
||||||
info = "Position for open-loop operation."
|
info = "Position for open-loop operation."
|
||||||
@ -320,7 +326,7 @@ class PiMotionMasterDevice(
|
|||||||
it.node["velocity"].double?.let { v ->
|
it.node["velocity"].double?.let { v ->
|
||||||
velocity.write(v)
|
velocity.write(v)
|
||||||
}
|
}
|
||||||
position.write(target)
|
targetPosition.write(target)
|
||||||
//read `onTarget` and `position` properties in a cycle until movement is complete
|
//read `onTarget` and `position` properties in a cycle until movement is complete
|
||||||
while (!onTarget.readTyped(true)) {
|
while (!onTarget.readTyped(true)) {
|
||||||
position.read(true)
|
position.read(true)
|
||||||
|
@ -8,6 +8,8 @@ import hep.dataforge.control.ports.withDelimiter
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
|
|
||||||
@ -20,8 +22,12 @@ abstract class VirtualDevice(val scope: CoroutineScope) : Socket<ByteArray> {
|
|||||||
private val toReceive = Channel<ByteArray>(100)
|
private val toReceive = Channel<ByteArray>(100)
|
||||||
private val toRespond = Channel<ByteArray>(100)
|
private val toRespond = Channel<ByteArray>(100)
|
||||||
|
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
private val receiveJob: Job = toReceive.consumeAsFlow().transformRequests().onEach {
|
private val receiveJob: Job = toReceive.consumeAsFlow().transformRequests().onEach {
|
||||||
|
mutex.withLock {
|
||||||
evaluateRequest(it)
|
evaluateRequest(it)
|
||||||
|
}
|
||||||
}.catch {
|
}.catch {
|
||||||
it.printStackTrace()
|
it.printStackTrace()
|
||||||
}.launchIn(scope)
|
}.launchIn(scope)
|
||||||
@ -143,7 +149,12 @@ class PiMotionMasterVirtualDevice(
|
|||||||
}
|
}
|
||||||
val response = selectedAxis.joinToString(separator = " \n") {
|
val response = selectedAxis.joinToString(separator = " \n") {
|
||||||
val state = axisState.getValue(it)
|
val state = axisState.getValue(it)
|
||||||
"$it=${state.extract(it)}"
|
val value = when (val extracted = state.extract(it)) {
|
||||||
|
true -> 1
|
||||||
|
false -> 0
|
||||||
|
else -> extracted
|
||||||
|
}
|
||||||
|
"$it=$value"
|
||||||
}
|
}
|
||||||
respond(response)
|
respond(response)
|
||||||
}
|
}
|
||||||
@ -241,6 +252,7 @@ class PiMotionMasterVirtualDevice(
|
|||||||
"TMX?" -> respondForAllAxis(axisIds) { maxPosition }
|
"TMX?" -> respondForAllAxis(axisIds) { maxPosition }
|
||||||
"VEL?" -> respondForAllAxis(axisIds) { velocity }
|
"VEL?" -> respondForAllAxis(axisIds) { velocity }
|
||||||
"SRG?" -> respond(WAT)
|
"SRG?" -> respond(WAT)
|
||||||
|
"ONT?" -> respondForAllAxis(axisIds) { onTarget() }
|
||||||
"SVO" -> doForEachAxis(parts) { key, value ->
|
"SVO" -> doForEachAxis(parts) { key, value ->
|
||||||
axisState[key]?.servoMode = value.toInt()
|
axisState[key]?.servoMode = value.toInt()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user