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(
|
||||
default: String? = null,
|
||||
descriptorBuilder: PropertyDescriptor.() -> Unit = {},
|
||||
|
@ -7,9 +7,11 @@ import javafx.beans.property.ReadOnlyProperty
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import javafx.collections.FXCollections
|
||||
import javafx.geometry.Pos
|
||||
import javafx.scene.Parent
|
||||
import javafx.scene.layout.Priority
|
||||
import javafx.scene.layout.VBox
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import tornadofx.*
|
||||
@ -27,6 +29,51 @@ class PiMotionMasterController : Controller() {
|
||||
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() {
|
||||
|
||||
private val controller: PiMotionMasterController by inject()
|
||||
@ -35,7 +82,7 @@ class PiMotionMasterView : View() {
|
||||
private val connectedProperty: ReadOnlyProperty<Boolean> = device.connected.fxProperty(device)
|
||||
private val debugServerJobProperty = SimpleObjectProperty<Job>()
|
||||
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 {
|
||||
top {
|
||||
@ -49,7 +96,7 @@ class PiMotionMasterView : View() {
|
||||
}
|
||||
}
|
||||
field("Port:") {
|
||||
textfield(port){
|
||||
textfield(port) {
|
||||
stripNonNumeric()
|
||||
}
|
||||
button {
|
||||
@ -86,9 +133,11 @@ class PiMotionMasterView : View() {
|
||||
action {
|
||||
if (!connectedProperty.value) {
|
||||
device.connect(host.get(), port.get())
|
||||
axisList.addAll(device.axes.entries)
|
||||
center {
|
||||
axisPane(device.axes,controller.context)
|
||||
}
|
||||
} else {
|
||||
axisList.removeAll()
|
||||
this@borderpane.center = null
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ class PiMotionMasterDevice(
|
||||
}
|
||||
|
||||
fun disconnect() {
|
||||
runBlocking{
|
||||
runBlocking {
|
||||
disconnect.invoke()
|
||||
}
|
||||
}
|
||||
@ -165,7 +165,7 @@ class PiMotionMasterDevice(
|
||||
private suspend fun requestAndParse(command: String, vararg arguments: String): Map<String, String> = buildMap {
|
||||
request(command, *arguments).forEach { line ->
|
||||
val (key, value) = line.split("=")
|
||||
put(key, value)
|
||||
put(key, value.trim())
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ class PiMotionMasterDevice(
|
||||
send("FRF", axisId)
|
||||
}
|
||||
|
||||
val minPosition by readingNumber(
|
||||
val minPosition by readingDouble(
|
||||
descriptorBuilder = {
|
||||
info = "Minimal position value for the axis"
|
||||
},
|
||||
@ -287,7 +287,7 @@ class PiMotionMasterDevice(
|
||||
}
|
||||
)
|
||||
|
||||
val maxPosition by readingNumber(
|
||||
val maxPosition by readingDouble(
|
||||
descriptorBuilder = {
|
||||
info = "Maximal position value for the axis"
|
||||
},
|
||||
@ -297,9 +297,15 @@ class PiMotionMasterDevice(
|
||||
}
|
||||
)
|
||||
|
||||
val position: TypedDeviceProperty<Double> by axisNumberProperty("POS") {
|
||||
info = "The current axis position."
|
||||
}
|
||||
val position by readingDouble(
|
||||
descriptorBuilder = {
|
||||
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") {
|
||||
info = "Position for open-loop operation."
|
||||
@ -320,7 +326,7 @@ class PiMotionMasterDevice(
|
||||
it.node["velocity"].double?.let { v ->
|
||||
velocity.write(v)
|
||||
}
|
||||
position.write(target)
|
||||
targetPosition.write(target)
|
||||
//read `onTarget` and `position` properties in a cycle until movement is complete
|
||||
while (!onTarget.readTyped(true)) {
|
||||
position.read(true)
|
||||
|
@ -8,6 +8,8 @@ import hep.dataforge.control.ports.withDelimiter
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlin.math.abs
|
||||
import kotlin.time.Duration
|
||||
|
||||
@ -20,8 +22,12 @@ abstract class VirtualDevice(val scope: CoroutineScope) : Socket<ByteArray> {
|
||||
private val toReceive = Channel<ByteArray>(100)
|
||||
private val toRespond = Channel<ByteArray>(100)
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
private val receiveJob: Job = toReceive.consumeAsFlow().transformRequests().onEach {
|
||||
evaluateRequest(it)
|
||||
mutex.withLock {
|
||||
evaluateRequest(it)
|
||||
}
|
||||
}.catch {
|
||||
it.printStackTrace()
|
||||
}.launchIn(scope)
|
||||
@ -143,7 +149,12 @@ class PiMotionMasterVirtualDevice(
|
||||
}
|
||||
val response = selectedAxis.joinToString(separator = " \n") {
|
||||
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)
|
||||
}
|
||||
@ -241,13 +252,14 @@ class PiMotionMasterVirtualDevice(
|
||||
"TMX?" -> respondForAllAxis(axisIds) { maxPosition }
|
||||
"VEL?" -> respondForAllAxis(axisIds) { velocity }
|
||||
"SRG?" -> respond(WAT)
|
||||
"ONT?" -> respondForAllAxis(axisIds) { onTarget() }
|
||||
"SVO" -> doForEachAxis(parts) { key, value ->
|
||||
axisState[key]?.servoMode = value.toInt()
|
||||
}
|
||||
"MOV" -> doForEachAxis(parts) { key, value ->
|
||||
axisState[key]?.targetPosition = value.toDouble()
|
||||
}
|
||||
"VEL"-> doForEachAxis(parts){key, value ->
|
||||
"VEL" -> doForEachAxis(parts) { key, value ->
|
||||
axisState[key]?.velocity = value.toDouble()
|
||||
}
|
||||
"INI" -> {
|
||||
|
Loading…
Reference in New Issue
Block a user