gursi26 commited on
Commit
0185a1a
1 Parent(s): ba08b5d
Files changed (2) hide show
  1. app.py +139 -197
  2. requirements.txt +1 -0
app.py CHANGED
@@ -1,25 +1,94 @@
1
  import gradio as gr
2
  from client import CobotController
3
  from utils import get_credentials
4
- from typing import Any
5
  import json
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  user, pwd, host, endpoint, port = get_credentials(False)
8
  client = CobotController(user, pwd, host, port, endpoint)
9
 
10
  CSS = """
11
  #col {
12
- background-color: #161624;
13
- padding: 16px;
14
- border-radius: 8px;
15
  }
16
  #nogaprow {
17
- gap: 0px !important;
18
  }
19
  #nogapcol {
20
- padding: 0px !important;
21
- border: none !important; /* Removes the border around each column */
22
- box-shadow: none !important;
23
  }
24
  """
25
 
@@ -68,17 +137,41 @@ def handle_request(
68
  resp["command"] = command
69
  return json.dumps(resp, indent=4), gr.Image(visible=False)
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  with gr.Blocks(css=CSS) as app:
72
  gr.Markdown("# MyCobot 280pi MQTT Control Demo")
73
  gr.Markdown("This is a demo that uses the MQTT protocol to communicate with the MyCobot 280pi over the internet. You can remotely send commands to the cobot and query it's current status.")
74
 
75
- user_id = gr.Textbox(label="User ID", info="Enter a unique user id of your choice. This user id will be placed into a queue to give you access to the cobot, so make sure you remember it!")
 
 
 
 
76
 
77
  with gr.Row():
78
  # QUERY PANEL
79
  with gr.Column(elem_id="col"):
80
  gr.Markdown("## Query")
81
- gr.Markdown("Use buttons on this panel to query the current status of the cobot, including information like joint angles, coordinates, gripper state and what the onboard camera sees.")
82
  angle_query_button = gr.Button("Query Angles")
83
  coord_query_button = gr.Button("Query Coordinates")
84
  gripper_query_button = gr.Button("Query Gripper state")
@@ -87,8 +180,7 @@ with gr.Blocks(css=CSS) as app:
87
  # GRIPPER PANEL
88
  with gr.Column(elem_id="col"):
89
  gr.Markdown("## Gripper Control")
90
- gr.Markdown("Use this panel to control the gripper of the cobot.")
91
- gripper_value = gr.Slider(minimum=0.0, maximum=100.0, step=1.0, label="Gripper value", info="0 = gripper fully closed, 100 = gripper fully open")
92
  speed_gripper = gr.Slider(value=50.0, minimum=0.0, maximum=100.0, step=1.0, label="Movement speed")
93
  gripper_control_button = gr.Button("Send gripper command")
94
 
@@ -96,7 +188,6 @@ with gr.Blocks(css=CSS) as app:
96
  # ANGLE PANEL
97
  with gr.Column(elem_id="col"):
98
  gr.Markdown("## Angle Control")
99
- gr.Markdown("Use this panel to control the joint angles of the cobot. Each angle corresponds to one of the 6 joints on the cobot.")
100
  with gr.Row(elem_id="nogaprow"):
101
  with gr.Column(elem_id="nogapcol"):
102
  angle1 = gr.Number(value=0.0, label="Angle 1", step=5.0)
@@ -112,7 +203,6 @@ with gr.Blocks(css=CSS) as app:
112
  # COORD PANEL
113
  with gr.Column(elem_id="col"):
114
  gr.Markdown("## Coordinate Control")
115
- gr.Markdown("Use this panel to control the joint coordinates of the cobot head. The angles are in [6-DoF format](https://en.wikipedia.org/wiki/Six_degrees_of_freedom).")
116
  with gr.Row(elem_id="nogaprow"):
117
  with gr.Column(elem_id="nogapcol"):
118
  xcoord = gr.Number(value=0.0, label="X coordinate", step=5.0)
@@ -128,202 +218,54 @@ with gr.Blocks(css=CSS) as app:
128
  response = gr.Textbox(label="Response")
129
  response_image = gr.Image(visible=False)
130
 
 
131
  angle_query_button.click(
132
- handle_request,
133
- inputs = [
134
- gr.Textbox(value="query/angles", visible=False),
135
- gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
136
- angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch,
137
- yaw, speed_coords
138
- ],
139
- outputs = [response, response_image]
140
  )
141
  coord_query_button.click(
142
- handle_request,
143
- inputs = [
144
- gr.Textbox(value="query/coords", visible=False),
145
- gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
146
- angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch,
147
- yaw, speed_coords
148
- ],
149
- outputs = [response, response_image]
150
  )
151
  gripper_query_button.click(
152
- handle_request,
153
- inputs = [
154
- gr.Textbox(value="query/gripper", visible=False),
155
- gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
156
- angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch,
157
- yaw, speed_coords
158
- ],
159
- outputs = [response, response_image]
160
  )
161
  camera_query_button.click(
162
- handle_request,
163
- inputs = [
164
- gr.Textbox(value="query/camera", visible=False),
165
- gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
166
- angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch,
167
- yaw, speed_coords
168
- ],
169
- outputs = [response, response_image]
170
  )
171
  gripper_control_button.click(
172
- handle_request,
173
- inputs = [
174
- gr.Textbox(value="control/gripper", visible=False),
175
- gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
176
- angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch,
177
- yaw, speed_coords
178
- ],
179
- outputs = [response, response_image]
180
  )
181
  angle_control_button.click(
182
- handle_request,
183
- inputs = [
184
- gr.Textbox(value="control/angles", visible=False),
185
- gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
186
- angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch,
187
- yaw, speed_coords
188
- ],
189
- outputs = [response, response_image]
190
  )
191
  coord_control_button.click(
192
- handle_request,
193
- inputs = [
194
- gr.Textbox(value="control/coords", visible=False),
195
- gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
196
- angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch,
197
- yaw, speed_coords
198
- ],
199
- outputs = [response, response_image]
200
  )
201
 
202
- app.launch()
203
-
204
- # import gradio as gr
205
- # from collections import deque
206
- # import threading
207
- # import time
208
-
209
- # SESSION_TIME = 30
210
-
211
- # class QueueSystem:
212
- # def __init__(self):
213
- # self.queue = deque()
214
- # self.current_user = None
215
- # self.session_start_time = None
216
- # self.lock = threading.Lock()
217
-
218
- # def enqueue_user(self, user_id):
219
- # with self.lock:
220
- # if user_id not in self.queue and user_id != self.current_user:
221
- # self.queue.append(user_id)
222
-
223
- # def dequeue_user(self):
224
- # with self.lock:
225
- # if self.queue:
226
- # return self.queue.popleft()
227
- # return None
228
-
229
- # def get_queue_info(self, user_id):
230
- # with self.lock:
231
- # if user_id == self.current_user:
232
- # # Calculate remaining time for the current user
233
- # remaining_time = max(0, SESSION_TIME - (time.time() - self.session_start_time))
234
- # return 0, remaining_time
235
- # elif user_id in self.queue:
236
- # # Calculate wait time based on the queue position
237
- # position = list(self.queue).index(user_id) + 1
238
- # if self.session_start_time:
239
- # # Use the current session time to calculate wait time
240
- # wait_time = (position - 1) * SESSION_TIME + max(0, SESSION_TIME - (time.time() - self.session_start_time))
241
- # else:
242
- # # If no session is active, assume each user gets the full session time
243
- # wait_time = position * SESSION_TIME
244
- # return position, wait_time
245
- # else:
246
- # return None, None
247
-
248
- # def start_session(self, user_id):
249
- # with self.lock:
250
- # if self.current_user is None:
251
- # self.current_user = user_id
252
- # self.session_start_time = time.time()
253
- # return True
254
- # return False
255
-
256
- # def end_session(self):
257
- # with self.lock:
258
- # if self.current_user and time.time() - self.session_start_time >= SESSION_TIME:
259
- # self.current_user = None
260
- # self.session_start_time = None
261
- # return True
262
- # return False
263
-
264
- # queue_system = QueueSystem()
265
-
266
- # def process_input(input_text, user_id):
267
- # if queue_system.current_user is None:
268
- # queue_system.start_session(user_id)
269
- # queue_system.enqueue_user(user_id)
270
- # position, wait_time = queue_system.get_queue_info(user_id)
271
-
272
- # if position == 0: # User is currently being served
273
- # result = f"Processed: {input_text}"
274
- # remaining_time = wait_time
275
- # return result, f"Your turn! Time remaining: {remaining_time:.0f} seconds."
276
- # elif position is not None:
277
- # return None, f"You are in position {position}. Estimated wait time: {wait_time:.0f} seconds."
278
- # else:
279
- # return None, "Error: You are not in the queue."
280
-
281
-
282
- # def gradio_function(input_text, user_id):
283
- # result, status = process_input(input_text, user_id)
284
- # return result, status
285
-
286
- # def get_queue_status(user_id):
287
- # if not user_id:
288
- # return "Enter a User ID and submit to join the queue."
289
- # position, wait_time = queue_system.get_queue_info(user_id)
290
- # if position == 0:
291
- # return f"Your turn! Time remaining: {wait_time:.0f} seconds."
292
- # elif position is not None:
293
- # return f"You are in position {position}. Estimated wait time: {wait_time:.0f} seconds."
294
- # else:
295
- # return "You are not in the queue. Submit to join."
296
-
297
- # def background_timer():
298
- # while True:
299
- # time.sleep(1)
300
- # if queue_system.end_session():
301
- # next_user = queue_system.dequeue_user()
302
- # if next_user:
303
- # queue_system.start_session(next_user)
304
-
305
- # # Start the background timer thread
306
- # timer_thread = threading.Thread(target=background_timer, daemon=True)
307
- # timer_thread.start()
308
-
309
- # with gr.Blocks() as demo:
310
- # input_text = gr.Textbox(label="Input")
311
- # user_id = gr.Textbox(label="User ID")
312
- # output_text = gr.Textbox(label="Output")
313
- # status_text = gr.Markdown("Enter a User ID and submit to join the queue.")
314
- # submit_btn = gr.Button("Submit")
315
-
316
- # submit_btn.click(
317
- # fn=gradio_function,
318
- # inputs=[input_text, user_id],
319
- # outputs=[output_text, status_text]
320
- # )
321
-
322
- # demo.load(
323
- # fn=get_queue_status,
324
- # inputs=user_id,
325
- # outputs=status_text,
326
- # )
327
 
328
- # demo.queue(default_concurrency_limit=1, max_size=100)
329
- # demo.launch()
 
1
  import gradio as gr
2
  from client import CobotController
3
  from utils import get_credentials
 
4
  import json
5
+ import threading
6
+ import time
7
+ from collections import deque
8
+ import namesgenerator
9
+
10
+ # Queue system setup
11
+ SESSION_TIME = 120
12
+
13
+ class QueueSystem:
14
+ def __init__(self):
15
+ self.queue = deque()
16
+ self.current_user = None
17
+ self.session_start_time = None
18
+ self.lock = threading.Lock()
19
+
20
+ def enqueue_user(self, user_id):
21
+ with self.lock:
22
+ if user_id not in self.queue and user_id != self.current_user:
23
+ self.queue.append(user_id)
24
+
25
+ def dequeue_user(self):
26
+ with self.lock:
27
+ if self.queue:
28
+ return self.queue.popleft()
29
+ return None
30
+
31
+ def get_queue_info(self, user_id):
32
+ with self.lock:
33
+ if user_id == self.current_user:
34
+ remaining_time = max(0, SESSION_TIME - (time.time() - self.session_start_time))
35
+ return 0, remaining_time
36
+ elif user_id in self.queue:
37
+ position = list(self.queue).index(user_id) + 1
38
+ if self.session_start_time:
39
+ wait_time = (position - 1) * SESSION_TIME + max(0, SESSION_TIME - (time.time() - self.session_start_time))
40
+ else:
41
+ wait_time = position * SESSION_TIME
42
+ return position, wait_time
43
+ else:
44
+ return None, None
45
+
46
+ def start_session(self, user_id):
47
+ with self.lock:
48
+ if self.current_user is None:
49
+ self.current_user = user_id
50
+ self.session_start_time = time.time()
51
+ return True
52
+ return False
53
+
54
+ def end_session(self):
55
+ with self.lock:
56
+ if self.current_user and time.time() - self.session_start_time >= SESSION_TIME:
57
+ self.current_user = None
58
+ self.session_start_time = None
59
+ return True
60
+ return False
61
+
62
+ queue_system = QueueSystem()
63
+
64
+ # Background timer thread to end session after SESSION_TIME
65
+ def background_timer():
66
+ while True:
67
+ time.sleep(1)
68
+ if queue_system.end_session():
69
+ next_user = queue_system.dequeue_user()
70
+ if next_user:
71
+ queue_system.start_session(next_user)
72
+
73
+ timer_thread = threading.Thread(target=background_timer, daemon=True)
74
+ timer_thread.start()
75
 
76
  user, pwd, host, endpoint, port = get_credentials(False)
77
  client = CobotController(user, pwd, host, port, endpoint)
78
 
79
  CSS = """
80
  #col {
81
+ background-color: #161624;
82
+ padding: 16px;
83
+ border-radius: 8px;
84
  }
85
  #nogaprow {
86
+ gap: 0px !important;
87
  }
88
  #nogapcol {
89
+ padding: 0px !important;
90
+ border: none !important;
91
+ box-shadow: none !important;
92
  }
93
  """
94
 
 
137
  resp["command"] = command
138
  return json.dumps(resp, indent=4), gr.Image(visible=False)
139
 
140
+ def process_user_auth(command, user_id, gripper_value, gripper_speed, angle1, angle2, angle3, angle4,
141
+ angle5, angle6, angle_speed, xcoord, ycoord, zcoord, roll, pitch, yaw, coord_speed):
142
+ if queue_system.current_user is None:
143
+ queue_system.start_session(user_id)
144
+ queue_system.enqueue_user(user_id)
145
+ position, wait_time = queue_system.get_queue_info(user_id)
146
+
147
+ if position == 0:
148
+ result, response_image = handle_request(
149
+ command, gripper_value, gripper_speed, angle1, angle2, angle3, angle4,
150
+ angle5, angle6, angle_speed, xcoord, ycoord, zcoord, roll, pitch, yaw, coord_speed
151
+ )
152
+ remaining_time_msg = f"Your turn!\nTime remaining: {wait_time:.2f} seconds."
153
+ return result, response_image, remaining_time_msg
154
+ elif position is not None:
155
+ wait_msg = f"There are {position - 1} people ahead of you in the queue.\nWait time: {wait_time:.2f} seconds."
156
+ return None, None, wait_msg
157
+ else:
158
+ return None, None, "Error: You are not in the queue."
159
+
160
+
161
  with gr.Blocks(css=CSS) as app:
162
  gr.Markdown("# MyCobot 280pi MQTT Control Demo")
163
  gr.Markdown("This is a demo that uses the MQTT protocol to communicate with the MyCobot 280pi over the internet. You can remotely send commands to the cobot and query it's current status.")
164
 
165
+ with gr.Row():
166
+ with gr.Column():
167
+ user_id = gr.Textbox(label="User ID", info="Enter a unique user id of your choice or take note of the current one. This user id will be placed into a queue to give you access to the cobot, so make sure you remember it!")
168
+ with gr.Column():
169
+ status_text = gr.Textbox(label="Queue status", value="", interactive=False, max_lines=2)
170
 
171
  with gr.Row():
172
  # QUERY PANEL
173
  with gr.Column(elem_id="col"):
174
  gr.Markdown("## Query")
 
175
  angle_query_button = gr.Button("Query Angles")
176
  coord_query_button = gr.Button("Query Coordinates")
177
  gripper_query_button = gr.Button("Query Gripper state")
 
180
  # GRIPPER PANEL
181
  with gr.Column(elem_id="col"):
182
  gr.Markdown("## Gripper Control")
183
+ gripper_value = gr.Slider(minimum=0.0, maximum=100.0, step=1.0, label="Gripper value")
 
184
  speed_gripper = gr.Slider(value=50.0, minimum=0.0, maximum=100.0, step=1.0, label="Movement speed")
185
  gripper_control_button = gr.Button("Send gripper command")
186
 
 
188
  # ANGLE PANEL
189
  with gr.Column(elem_id="col"):
190
  gr.Markdown("## Angle Control")
 
191
  with gr.Row(elem_id="nogaprow"):
192
  with gr.Column(elem_id="nogapcol"):
193
  angle1 = gr.Number(value=0.0, label="Angle 1", step=5.0)
 
203
  # COORD PANEL
204
  with gr.Column(elem_id="col"):
205
  gr.Markdown("## Coordinate Control")
 
206
  with gr.Row(elem_id="nogaprow"):
207
  with gr.Column(elem_id="nogapcol"):
208
  xcoord = gr.Number(value=0.0, label="X coordinate", step=5.0)
 
218
  response = gr.Textbox(label="Response")
219
  response_image = gr.Image(visible=False)
220
 
221
+ # Queue-aware event handling
222
  angle_query_button.click(
223
+ process_user_auth,
224
+ inputs = [gr.Textbox(value="query/angles", visible=False), user_id, gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
225
+ angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch, yaw, speed_coords],
226
+ outputs = [response, response_image, status_text]
 
 
 
 
227
  )
228
  coord_query_button.click(
229
+ process_user_auth,
230
+ inputs = [gr.Textbox(value="query/coords", visible=False), user_id, gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
231
+ angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch, yaw, speed_coords],
232
+ outputs = [response, response_image, status_text]
 
 
 
 
233
  )
234
  gripper_query_button.click(
235
+ process_user_auth,
236
+ inputs = [gr.Textbox(value="query/gripper", visible=False), user_id, gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
237
+ angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch, yaw, speed_coords],
238
+ outputs = [response, response_image, status_text]
 
 
 
 
239
  )
240
  camera_query_button.click(
241
+ process_user_auth,
242
+ inputs = [gr.Textbox(value="query/camera", visible=False), user_id, gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
243
+ angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch, yaw, speed_coords],
244
+ outputs = [response, response_image, status_text]
 
 
 
 
245
  )
246
  gripper_control_button.click(
247
+ process_user_auth,
248
+ inputs = [gr.Textbox(value="control/gripper", visible=False), user_id, gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
249
+ angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch, yaw, speed_coords],
250
+ outputs = [response, response_image, status_text]
 
 
 
 
251
  )
252
  angle_control_button.click(
253
+ process_user_auth,
254
+ inputs = [gr.Textbox(value="control/angles", visible=False), user_id, gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
255
+ angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch, yaw, speed_coords],
256
+ outputs = [response, response_image, status_text]
 
 
 
 
257
  )
258
  coord_control_button.click(
259
+ process_user_auth,
260
+ inputs = [gr.Textbox(value="control/coords", visible=False), user_id, gripper_value, speed_gripper, angle1, angle2, angle3, angle4,
261
+ angle5, angle6, speed_angles, xcoord, ycoord, zcoord, roll, pitch, yaw, speed_coords],
262
+ outputs = [response, response_image, status_text]
 
 
 
 
263
  )
264
 
265
+ app.load(
266
+ namesgenerator.get_random_name,
267
+ outputs=[user_id]
268
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
 
270
+ app.queue(default_concurrency_limit=1, max_size=100)
271
+ app.launch()
requirements.txt CHANGED
@@ -50,3 +50,4 @@ tzdata==2024.2
50
  urllib3==2.2.3
51
  uvicorn==0.32.0
52
  websockets==12.0
 
 
50
  urllib3==2.2.3
51
  uvicorn==0.32.0
52
  websockets==12.0
53
+ namesgenerator==0.3