8
8
from PyQt5 .QtGui import QKeySequence
9
9
from PyQt5 .QtWidgets import (
10
10
QAbstractItemView ,
11
+ QCheckBox ,
11
12
QFileDialog ,
12
13
QGroupBox ,
13
14
QLabel ,
28
29
from std_srvs .srv import SetBool
29
30
30
31
from bitbots_animation_rqt .animation_recording import Recorder
31
- from bitbots_animation_rqt .utils import DragDropList
32
+ from bitbots_animation_rqt .utils import DragDropList , flatten_dict_of_lists
32
33
from bitbots_msgs .action import PlayAnimation
33
34
from bitbots_msgs .msg import JointCommand , JointTorque
34
35
from bitbots_msgs .srv import AddAnimation
@@ -82,7 +83,7 @@ def __init__(self, context):
82
83
83
84
# Initialize the motor tree structure where we can select which motors are stiff
84
85
self ._motor_switcher_active_checkbox : dict [str , QTreeWidgetItem ] = {}
85
- self ._motor_switcher_torque_checkbox : dict [str , QTreeWidgetItem ] = {}
86
+ self ._motor_controller_torque_checkbox : dict [str , QTreeWidgetItem ] = {}
86
87
87
88
# Motor hierarchy
88
89
self ._motor_hierarchy = { # TODO this should be a parameter / loaded from the urdf
@@ -120,6 +121,7 @@ def __init__(self, context):
120
121
},
121
122
}
122
123
}
124
+ self ._motor_hierarchy_flat = flatten_dict_of_lists (self ._motor_hierarchy )
123
125
124
126
# Create drag and dop list for keyframes
125
127
self ._widget .frameList = DragDropList (self ._widget , self .change_keyframe_order )
@@ -175,11 +177,13 @@ def create_motor_controller(self) -> None:
175
177
Sets up the GUI in the middle of the Screen to control the motors.
176
178
Uses self._motorValues to determine which motors are present.
177
179
"""
178
- # Iterate over all motors
179
- for i , motor_name in enumerate (sorted ( self .motors )):
180
+ # Iterate over all motors (we iterate over the flat hierarchy to get the correct order of the motors)
181
+ for i , motor_name in enumerate (self ._motor_hierarchy_flat . values ( )):
180
182
# Create a group of UI elements for each motor
181
183
group = QGroupBox ()
182
184
layout = QVBoxLayout ()
185
+ # Horizontally center the group
186
+ layout .setAlignment (Qt .AlignHCenter )
183
187
# Create a label for the motor name
184
188
label = QLabel ()
185
189
label .setText (motor_name )
@@ -192,7 +196,15 @@ def create_motor_controller(self) -> None:
192
196
layout .addWidget (textfield )
193
197
self ._motor_controller_text_fields [motor_name ] = textfield
194
198
199
+ # Put a torque checkbox below the motor enable checkbox
200
+ torque_checkbox = QCheckBox ()
201
+ torque_checkbox .setText ("Torque" )
202
+ torque_checkbox .setCheckState (Qt .Checked )
203
+ layout .addWidget (torque_checkbox )
204
+ self ._motor_controller_torque_checkbox [motor_name ] = torque_checkbox
205
+
195
206
# Add the layout to the group and the group to the main layout (at the correct position in the 5 x n grid)
207
+ layout .setAlignment (Qt .AlignCenter )
196
208
group .setLayout (layout )
197
209
self ._widget .motorControlLayout .addWidget (group , i // 5 , i % 5 )
198
210
@@ -229,19 +241,12 @@ def build_widget_tree(parent, hierarchy: dict) -> None:
229
241
enable_checkbox .setCheckState (0 , Qt .Checked )
230
242
enable_checkbox .setExpanded (True )
231
243
self ._motor_switcher_active_checkbox [motor_name ] = enable_checkbox
232
-
233
- # Put a torque checkbox below the motor enable checkbox
234
- torque_checkbox = QTreeWidgetItem (enable_checkbox )
235
- torque_checkbox .setText (0 , "Torque" )
236
- torque_checkbox .setFlags (torque_checkbox .flags () | Qt .ItemIsTristate | Qt .ItemIsUserCheckable )
237
- torque_checkbox .setCheckState (0 , Qt .Checked )
238
- self ._motor_switcher_torque_checkbox [motor_name ] = torque_checkbox
239
244
else :
240
245
raise ValueError ("Invalid hierarchy" )
241
246
242
247
# Build the tree
243
248
build_widget_tree (self ._widget .motorTree , self ._motor_hierarchy )
244
- self ._widget .motorTree .setHeaderLabel ("Active / Stiff Motors " )
249
+ self ._widget .motorTree .setHeaderLabel ("Active Motors (for the current keyframe) " )
245
250
246
251
# Register hook that executes our callback when the user clicks on a checkbox
247
252
self ._widget .motorTree .itemClicked .connect (self .react_to_motor_selection )
@@ -502,9 +507,9 @@ def record(self):
502
507
{
503
508
motor_name : self ._working_angles [motor_name ]
504
509
for motor_name in self .motors
505
- if self ._motor_switcher_active_checkbox [motor_name ].checkState (0 ) == 2
510
+ if self ._motor_switcher_active_checkbox [motor_name ].checkState (0 ) == Qt . CheckState . Checked
506
511
},
507
- {motor_name : self ._motor_switcher_torque_checkbox [motor_name ].checkState (0 ) for motor_name in self .motors },
512
+ {motor_name : self ._motor_controller_torque_checkbox [motor_name ].checkState () for motor_name in self .motors },
508
513
new_name ,
509
514
self ._widget .spinBoxDuration .value (),
510
515
self ._widget .spinBoxPause .value (),
@@ -588,7 +593,7 @@ def react_to_frame_change(self):
588
593
stiff = "torques" not in selected_frame or (
589
594
motor_name in selected_frame ["torques" ] and bool (selected_frame ["torques" ][motor_name ])
590
595
)
591
- self ._motor_switcher_torque_checkbox [motor_name ].setCheckState (0 , Qt .Checked if stiff else Qt .Unchecked )
596
+ self ._motor_controller_torque_checkbox [motor_name ].setCheckState (Qt .Checked if stiff else Qt .Unchecked )
592
597
593
598
# Update the motor angle controls (value and active state)
594
599
if active :
@@ -636,9 +641,10 @@ def react_to_motor_selection(self):
636
641
"""
637
642
# Go through all motors
638
643
for motor_name in self .motors :
639
- active = self ._motor_switcher_active_checkbox [motor_name ].checkState (0 ) == 2
644
+ active = self ._motor_switcher_active_checkbox [motor_name ].checkState (0 ) == Qt . CheckState . Checked
640
645
# Enable or disable the motor controls
641
646
self ._motor_controller_text_fields [motor_name ].setEnabled (active )
647
+ self ._motor_controller_torque_checkbox [motor_name ].setEnabled (active )
642
648
# Pull working values from from the joint states if the motor is not active
643
649
if not active and motor_name in self ._joint_states .name :
644
650
self ._working_angles [motor_name ] = self ._joint_states .position [
@@ -663,7 +669,10 @@ def react_to_motor_selection(self):
663
669
self .effort_pub .publish (
664
670
JointTorque (
665
671
joint_names = self .motors ,
666
- on = [self ._motor_switcher_torque_checkbox [motor_name ].checkState (0 ) == 2 for motor_name in self .motors ],
672
+ on = [
673
+ self ._motor_controller_torque_checkbox [motor_name ].checkState () == Qt .CheckState .Checked
674
+ for motor_name in self .motors
675
+ ],
667
676
)
668
677
)
669
678
0 commit comments