-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathMinimalApp.py
More file actions
196 lines (176 loc) · 8.97 KB
/
Copy pathMinimalApp.py
File metadata and controls
196 lines (176 loc) · 8.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import sys
from irc_app.AppClient import AppClient
from irc_app.DataTypes.Matrix44 import Matrix44FromGrpc
from irc_app.rpc.robotcontrolapp_pb2 import (
AppFunction,
AppUIElement,
ButtonState,
CheckboxState,
)
from google.protobuf.internal import containers as protobufContainers
class MinimalApp(AppClient):
"""This is an example app implementation"""
def __init__(self, appName: str, target: str):
"""
Initializes the app. Pass the app name (as defined in rcapp.xml) and
socket to connect to (default: "localhost:5000")
"""
AppClient.__init__(self, appName, target)
def _AppFunctionHandler(self, function: AppFunction):
"""Gets called on remote app function calls received from the robot control"""
# This prints the received function data
print("Received app function:")
print(function)
# Select the app function to call
if function.name == "pow":
self.ExampleExponentiation(function)
else:
# Example on how to handle app functions (these are called by the program command "App")
self.ExamplePrintAppFunctionParameters(function)
# Confirm that the function finished, otherwise the robot program will wait forever.
# You may send this later if the function call takes some time but it must be sent at some point.
self.SendFunctionDone(function.call_id)
# Or call this in case the function failed. This stops the robot program.
# self.SendFunctionFailed(function.call_id, "example failure reason - this is a test, see MinimalApp.py")
def _UiUpdateHandler(
self, updates: protobufContainers.RepeatedCompositeFieldContainer[AppUIElement]
):
"""Gets called on remote UI update requests received from the robot control"""
# This prints the received UI updates:
print("Received UI updates: ")
print(updates)
# Example on how to handle UI events (button clicked, value changed etc)
self.ExamplePrintUIEvents(updates)
# Example on how to handle UI events (button clicked, value changed etc)
self.ExampleUIElementClicked(updates)
def ExamplePrintAppFunctionParameters(self, function):
"""
This example prints all app functions contained in an AppFunction
request (e.g. coming from the App program command)
"""
print(
f"App function '{function.name}' called with call ID {function.call_id}, label = '{function.label}', ui hint = '{function.ui_hint}', number of parameters = {len(function.parameters)}"
)
# print all parameters
for parameter in function.parameters:
if parameter.HasField("bool_value"):
# boolean
print(
f"\tparameter '{parameter.name}', type 'bool' {parameter.bool_value}"
)
elif parameter.HasField("int64_value"):
# integer
print(
f"\tparameter '{parameter.name}', type 'int64' {parameter.int64_value}"
)
elif parameter.HasField("double_value"):
# double
print(
f"\tparameter '{parameter.name}', type 'double' {parameter.double_value:.2f}"
)
elif parameter.HasField("string_value"):
# string
print(
f"\tparameter '{parameter.name}', type 'string' {parameter.string_value}"
)
elif parameter.HasField("vector3_value"):
# 3 dimensional vector
print(
f"\tparameter '{parameter.name}', type 'vector3' ({parameter.vector3_value.GetX():.2f} {parameter.vector3_value.GetY():.2f} {parameter.vector3_value.GetZ():.2f})"
)
elif parameter.HasField("cartesian_value"):
# cartesian position and orientation
matrix = Matrix44FromGrpc(parameter.cartesian_value)
print(
f"\tparameter '{parameter.name}', type 'cartesian' X={matrix.GetX():.2f}, Y={matrix.GetY():.2f}, Z={matrix.GetZ():.2f}, A={matrix.GetA():.2f}, B={matrix.GetB():.2f}, C={matrix.GetC():.2f}"
)
def ExampleExponentiation(self, function):
"""
This example exponentiates the value of a number variable by a given exponent
and assigns the result to a different number variable
"""
# Get the function parameters by iterating over the list
exponentValue = 1
baseVariableName = ""
resultVariableName = ""
for parameter in function.parameters:
if parameter.name == "base_variable" and parameter.HasField("string_value"):
baseVariableName = parameter.string_value
elif parameter.name == "result_variable" and parameter.HasField(
"string_value"
):
resultVariableName = parameter.string_value
elif parameter.name == "exponent_number" and parameter.HasField(
"double_value"
):
exponentValue = parameter.double_value
try:
# Now request the value of the base number variable from the robot control
baseVariable = self.GetNumberVariable(baseVariableName)
baseValue = baseVariable.value
# And calculate the result
resultValue = pow(baseValue, exponentValue)
# Write the result to the target variable
self.SetNumber(resultVariableName, resultValue)
print(
f'Calculated {baseValue}^{exponentValue} = {resultValue}, result was written to variable "{resultVariableName}"'
)
except Exception as ex:
print('Function call "exponentiation" failed', file=sys.stderr)
print(ex, file=sys.stderr)
def ExamplePrintUIEvents(self, updates):
"""This example prints all UI events contained in a UI update"""
for update in updates:
if update.state.HasField("button_state"):
# button clicked
isClicked = update.state.button_state == ButtonState.CLICKED
print(
f"Button '{update.element_name}' changed: is clicked = {isClicked}"
)
elif update.state.HasField("checkbox_state"):
# checkbox toggled
isChecked = update.state.checkbox_state == CheckboxState.CHECKED
print(
f"Checkbox '{update.element_name}' changed: is checked = {isChecked}"
)
elif update.state.HasField("dropdown_state"):
# drop down selected
# to compare with strings call .__str__()!
selectedOption = update.state.dropdown_state.selected_option
print(
f"Dropdown '{update.element_name}' changed: selected option = {selectedOption}"
)
elif update.state.HasField("textfield_state"):
# text box changed
# to compare with strings call .__str__()!
text = update.state.textfield_state.current_text
print(f"Text box '{update.element_name}' changed: text = {text}")
elif update.state.HasField("numberfield_state"):
# number box changed
number = update.state.numberfield_state.current_number
print(f"Number box '{update.element_name}' changed: value = {number}")
elif update.state.HasField("image_state"):
# image clicked
if update.state.image_state.HasField("clicked_at"):
x = update.state.image_state.clicked_at.X()
y = update.state.image_state.clicked_at.X()
isClicked = update.state.image_state.clicked_at.is_clicked
if isClicked:
print(
f"Image clicked '{update.element_name}': x = {x:.3f}, y = {y:.3f}"
)
# Counting variable for ExampleUIElementClicked()
_examplePlusMinusValue = 0
def ExampleUIElementClicked(self, updates):
"""This example handles the plus/minus buttons to increase a text element in the app UI"""
for update in updates:
# The following sample will increase/decrease a value if the
# plus/minus button is pressed and send it back to the UI.
if update.element_name == "buttonMinus": # button minus pressed
self._examplePlusMinusValue -= 1
print(f"Decreasing UI number to {self._examplePlusMinusValue:.0f}")
self.SetNumber("textLeftRight", self._examplePlusMinusValue)
elif update.element_name == "buttonPlus": # button plus pressed
self._examplePlusMinusValue += 1
print(f"Increasing UI number to {self._examplePlusMinusValue:.0f}")
self.SetNumber("textLeftRight", self._examplePlusMinusValue)