Skip to content

robot_manual

RobotManualEntity #

Bases: QEntity

An robot entity that can be moved and rotated manually on the table.

When selected with a mouse click, a property window is displayed to modify the robot properties.

The robot can also be moved using the mouse.

Attributes:

Name Type Description
color QColor

Robot color

enable_controller

Qt signal used to disable the camera controller when moving the robot using the mouse

Source code in cogip/entities/robot_manual.py
  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
class RobotManualEntity(Qt3DCore.QEntity):
    """
    An robot entity that can be moved and rotated manually on the table.

    When selected with a mouse click, a property window is displayed
    to modify the robot properties.

    The robot can also be moved using the mouse.

    Attributes:
        color: Robot color
        enable_controller: Qt signal used to disable the camera controller
            when moving the robot using the mouse
    """

    color: QtGui.QColor = QtGui.QColor.fromRgb(17, 70, 92, 100)
    enable_controller = qtSignal(bool)

    def __init__(
        self,
        parent: Qt3DCore.QEntity,
        parent_widget: QtWidgets.QWidget,
        robot_id: int = 1,
        x: int = 1200,
        y: int = 1200,
        rotation: int = 180,
    ):
        """
        Class constructor.

        Arguments:
            parent: The parent entity
            parent_widget: Parent widget
            x: X position
            y: Y position
            rotation: Rotation
        """
        super().__init__(parent)

        self.parent_widget = parent_widget

        self.mesh = Qt3DRender.QMesh(self)
        self.mesh.setSource(QtCore.QUrl(f"file:assets/{'robot' if robot_id == 1 else 'pami'}2024.stl"))
        self.addComponent(self.mesh)

        self.material = Qt3DExtras.QPhongMaterial(self)
        self.material.setShininess(1.0)
        self.material.setDiffuse(self.color)
        self.material.setSpecular(self.color)
        self.addComponent(self.material)

        self.transform = Qt3DCore.QTransform(self)
        self.transform.setTranslation(QtGui.QVector3D(x, y, 0))
        self.transform.setRotationZ(rotation)
        self.addComponent(self.transform)

        self.picker = Qt3DRender.QObjectPicker()
        self.picker.setDragEnabled(True)
        self.picker.pressed.connect(self.pressed)
        self.picker.released.connect(self.released)
        self.picker.moved.connect(self.moved)
        self.addComponent(self.picker)

        self.moving = False

        # Create a layer used by sensors to activate detection on the robot
        self.layer = Qt3DRender.QLayer(self)
        self.layer.setRecursive(True)
        self.layer.setEnabled(True)
        self.addComponent(self.layer)

        # Create properties dialog
        self.properties = RobotManualProperties(self.parent_widget, self)

    @qtSlot(int)
    def setXTranslation(self, x: int):
        """
        Qt Slot

        Set the X position.
        """
        translation = self.transform.translation()
        translation.setX(float(x))
        self.transform.setTranslation(translation)

    @qtSlot(int)
    def setYTranslation(self, y: int):
        """
        Qt Slot

        Set the Y position.
        """
        translation = self.transform.translation()
        translation.setY(float(y))
        self.transform.setTranslation(translation)

    @qtSlot(Qt3DRender.QPickEvent)
    def pressed(self, pick: Qt3DRender.QPickEvent):
        """
        Qt Slot

        Slot called on a ```pressed``` mouse event on the robot.

        Emit a signal to disable the camera controller before moving the robot.
        """
        self.enable_controller.emit(False)

    @qtSlot(Qt3DRender.QPickEvent)
    def released(self, pick: Qt3DRender.QPickEvent):
        """
        Qt Slot

        Slot called on a ```released``` mouse event on the robot.

        If this event occurs just after a ```pressed``` event, it is only a mouse click,
        so display the property window.

        Emit a signal to re-enable the camera controller after moving the robot.
        """
        if not self.moving:
            if RobotManualProperties.active_properties:
                RobotManualProperties.active_properties.close()
            self.properties.show()
            self.properties.raise_()
            self.properties.activateWindow()
            RobotManualProperties.set_active_properties(self.properties)
        self.moving = False
        self.enable_controller.emit(True)

    @qtSlot(Qt3DRender.QPickEvent)
    def moved(self, pick: Qt3DRender.QPickEvent):
        """
        Qt Slot

        Slot called on a ```moved``` mouse event on the robot.

        Just record that the robot is moving, the translation is computed
        in the [GameView][cogip.widgets.gameview.GameView] object.
        """
        self.moving = True

    @qtSlot(QtGui.QVector3D)
    def new_move_delta(self, delta: QtGui.QVector3D):
        """
        Qt Slot

        Update the robot position.

        Arguments:
            delta: The difference between current and new position
        """
        if not delta:
            self.moving = False
        elif self.moving:
            new_translation = self.transform.translation() + delta
            self.transform.setTranslation(new_translation)
            self.properties.spin_x.setValue(new_translation.x())
            self.properties.spin_y.setValue(new_translation.y())

__init__(parent, parent_widget, robot_id=1, x=1200, y=1200, rotation=180) #

Class constructor.

Parameters:

Name Type Description Default
parent QEntity

The parent entity

required
parent_widget QWidget

Parent widget

required
x int

X position

1200
y int

Y position

1200
rotation int

Rotation

180
Source code in cogip/entities/robot_manual.py
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
def __init__(
    self,
    parent: Qt3DCore.QEntity,
    parent_widget: QtWidgets.QWidget,
    robot_id: int = 1,
    x: int = 1200,
    y: int = 1200,
    rotation: int = 180,
):
    """
    Class constructor.

    Arguments:
        parent: The parent entity
        parent_widget: Parent widget
        x: X position
        y: Y position
        rotation: Rotation
    """
    super().__init__(parent)

    self.parent_widget = parent_widget

    self.mesh = Qt3DRender.QMesh(self)
    self.mesh.setSource(QtCore.QUrl(f"file:assets/{'robot' if robot_id == 1 else 'pami'}2024.stl"))
    self.addComponent(self.mesh)

    self.material = Qt3DExtras.QPhongMaterial(self)
    self.material.setShininess(1.0)
    self.material.setDiffuse(self.color)
    self.material.setSpecular(self.color)
    self.addComponent(self.material)

    self.transform = Qt3DCore.QTransform(self)
    self.transform.setTranslation(QtGui.QVector3D(x, y, 0))
    self.transform.setRotationZ(rotation)
    self.addComponent(self.transform)

    self.picker = Qt3DRender.QObjectPicker()
    self.picker.setDragEnabled(True)
    self.picker.pressed.connect(self.pressed)
    self.picker.released.connect(self.released)
    self.picker.moved.connect(self.moved)
    self.addComponent(self.picker)

    self.moving = False

    # Create a layer used by sensors to activate detection on the robot
    self.layer = Qt3DRender.QLayer(self)
    self.layer.setRecursive(True)
    self.layer.setEnabled(True)
    self.addComponent(self.layer)

    # Create properties dialog
    self.properties = RobotManualProperties(self.parent_widget, self)

moved(pick) #

Qt Slot

Slot called on a moved mouse event on the robot.

Just record that the robot is moving, the translation is computed in the GameView object.

Source code in cogip/entities/robot_manual.py
138
139
140
141
142
143
144
145
146
147
148
@qtSlot(Qt3DRender.QPickEvent)
def moved(self, pick: Qt3DRender.QPickEvent):
    """
    Qt Slot

    Slot called on a ```moved``` mouse event on the robot.

    Just record that the robot is moving, the translation is computed
    in the [GameView][cogip.widgets.gameview.GameView] object.
    """
    self.moving = True

new_move_delta(delta) #

Qt Slot

Update the robot position.

Parameters:

Name Type Description Default
delta QVector3D

The difference between current and new position

required
Source code in cogip/entities/robot_manual.py
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
@qtSlot(QtGui.QVector3D)
def new_move_delta(self, delta: QtGui.QVector3D):
    """
    Qt Slot

    Update the robot position.

    Arguments:
        delta: The difference between current and new position
    """
    if not delta:
        self.moving = False
    elif self.moving:
        new_translation = self.transform.translation() + delta
        self.transform.setTranslation(new_translation)
        self.properties.spin_x.setValue(new_translation.x())
        self.properties.spin_y.setValue(new_translation.y())

pressed(pick) #

Qt Slot

Slot called on a pressed mouse event on the robot.

Emit a signal to disable the camera controller before moving the robot.

Source code in cogip/entities/robot_manual.py
105
106
107
108
109
110
111
112
113
114
@qtSlot(Qt3DRender.QPickEvent)
def pressed(self, pick: Qt3DRender.QPickEvent):
    """
    Qt Slot

    Slot called on a ```pressed``` mouse event on the robot.

    Emit a signal to disable the camera controller before moving the robot.
    """
    self.enable_controller.emit(False)

released(pick) #

Qt Slot

Slot called on a released mouse event on the robot.

If this event occurs just after a pressed event, it is only a mouse click, so display the property window.

Emit a signal to re-enable the camera controller after moving the robot.

Source code in cogip/entities/robot_manual.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
@qtSlot(Qt3DRender.QPickEvent)
def released(self, pick: Qt3DRender.QPickEvent):
    """
    Qt Slot

    Slot called on a ```released``` mouse event on the robot.

    If this event occurs just after a ```pressed``` event, it is only a mouse click,
    so display the property window.

    Emit a signal to re-enable the camera controller after moving the robot.
    """
    if not self.moving:
        if RobotManualProperties.active_properties:
            RobotManualProperties.active_properties.close()
        self.properties.show()
        self.properties.raise_()
        self.properties.activateWindow()
        RobotManualProperties.set_active_properties(self.properties)
    self.moving = False
    self.enable_controller.emit(True)

setXTranslation(x) #

Qt Slot

Set the X position.

Source code in cogip/entities/robot_manual.py
83
84
85
86
87
88
89
90
91
92
@qtSlot(int)
def setXTranslation(self, x: int):
    """
    Qt Slot

    Set the X position.
    """
    translation = self.transform.translation()
    translation.setX(float(x))
    self.transform.setTranslation(translation)

setYTranslation(y) #

Qt Slot

Set the Y position.

Source code in cogip/entities/robot_manual.py
 94
 95
 96
 97
 98
 99
100
101
102
103
@qtSlot(int)
def setYTranslation(self, y: int):
    """
    Qt Slot

    Set the Y position.
    """
    translation = self.transform.translation()
    translation.setY(float(y))
    self.transform.setTranslation(translation)

RobotManualProperties #

Bases: QDialog

The property window.

Attributes:

Name Type Description
active_properties RobotManualProperties

The current property window displayed.

Source code in cogip/entities/robot_manual.py
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
class RobotManualProperties(QtWidgets.QDialog):
    """
    The property window.

    Attributes:
        active_properties: The current property window displayed.
    """

    active_properties: "RobotManualProperties" = None

    def __init__(self, parent: QtWidgets.QWidget, robot_entity: RobotManualEntity):
        """
        Class constructor.

        Arguments:
            parent: The parent widget
            robot_entity: The related robot entity
        """
        super().__init__(parent)

        self.robot_entity = robot_entity
        self.setWindowTitle("Robot Properties")
        self.setModal(False)
        self.setMinimumWidth(self.fontMetrics().horizontalAdvance(self.windowTitle()))

        layout = QtWidgets.QGridLayout()
        self.setLayout(layout)

        row = 0

        label_x = QtWidgets.QLabel("X")
        self.spin_x = QtWidgets.QSpinBox()
        self.spin_x.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
        self.spin_x.setMinimum(-1200)
        self.spin_x.setMaximum(1200)
        self.spin_x.setValue(int(self.robot_entity.transform.translation().x()))
        self.spin_x.valueChanged.connect(self.robot_entity.setXTranslation)
        layout.addWidget(label_x, row, 0)
        layout.addWidget(self.spin_x, row, 1)
        row += 1

        label_y = QtWidgets.QLabel("Y")
        self.spin_y = QtWidgets.QSpinBox()
        self.spin_y.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
        self.spin_y.setMinimum(-1700)
        self.spin_y.setMaximum(1700)
        self.spin_y.setValue(int(self.robot_entity.transform.translation().y()))
        self.spin_y.valueChanged.connect(self.robot_entity.setYTranslation)
        layout.addWidget(label_y, row, 0)
        layout.addWidget(self.spin_y, row, 1)
        row += 1

        label_rotation = QtWidgets.QLabel("Rotation")
        self.spin_rotation = QtWidgets.QSpinBox()
        self.spin_rotation.setSuffix("°")
        self.spin_rotation.setMinimum(-180)
        self.spin_rotation.setMaximum(180)
        self.spin_rotation.setValue(int(self.robot_entity.transform.rotationZ()))
        self.spin_rotation.valueChanged.connect(self.robot_entity.transform.setRotationZ)
        layout.addWidget(label_rotation, row, 0)
        layout.addWidget(self.spin_rotation, row, 1)
        row += 1

        self.readSettings()

    @classmethod
    def set_active_properties(cls, properties: "RobotManualProperties"):
        """
        Class method.

        Set the current property window displayed.

        Arguments:
            properties: The current property
        """
        cls.active_properties = properties

    def closeEvent(self, event: QtGui.QCloseEvent):
        """
        Close the property windows.

        Arguments:
            event: The close event (unused)
        """
        RobotManualProperties.set_active_properties(None)

        settings = QtCore.QSettings("COGIP", "monitor")
        settings.setValue("manual_robot_dialog/geometry", self.saveGeometry())

        super().closeEvent(event)

    def readSettings(self):
        settings = QtCore.QSettings("COGIP", "monitor")
        self.restoreGeometry(settings.value("manual_robot_dialog/geometry"))

__init__(parent, robot_entity) #

Class constructor.

Parameters:

Name Type Description Default
parent QWidget

The parent widget

required
robot_entity RobotManualEntity

The related robot entity

required
Source code in cogip/entities/robot_manual.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
def __init__(self, parent: QtWidgets.QWidget, robot_entity: RobotManualEntity):
    """
    Class constructor.

    Arguments:
        parent: The parent widget
        robot_entity: The related robot entity
    """
    super().__init__(parent)

    self.robot_entity = robot_entity
    self.setWindowTitle("Robot Properties")
    self.setModal(False)
    self.setMinimumWidth(self.fontMetrics().horizontalAdvance(self.windowTitle()))

    layout = QtWidgets.QGridLayout()
    self.setLayout(layout)

    row = 0

    label_x = QtWidgets.QLabel("X")
    self.spin_x = QtWidgets.QSpinBox()
    self.spin_x.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
    self.spin_x.setMinimum(-1200)
    self.spin_x.setMaximum(1200)
    self.spin_x.setValue(int(self.robot_entity.transform.translation().x()))
    self.spin_x.valueChanged.connect(self.robot_entity.setXTranslation)
    layout.addWidget(label_x, row, 0)
    layout.addWidget(self.spin_x, row, 1)
    row += 1

    label_y = QtWidgets.QLabel("Y")
    self.spin_y = QtWidgets.QSpinBox()
    self.spin_y.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType)
    self.spin_y.setMinimum(-1700)
    self.spin_y.setMaximum(1700)
    self.spin_y.setValue(int(self.robot_entity.transform.translation().y()))
    self.spin_y.valueChanged.connect(self.robot_entity.setYTranslation)
    layout.addWidget(label_y, row, 0)
    layout.addWidget(self.spin_y, row, 1)
    row += 1

    label_rotation = QtWidgets.QLabel("Rotation")
    self.spin_rotation = QtWidgets.QSpinBox()
    self.spin_rotation.setSuffix("°")
    self.spin_rotation.setMinimum(-180)
    self.spin_rotation.setMaximum(180)
    self.spin_rotation.setValue(int(self.robot_entity.transform.rotationZ()))
    self.spin_rotation.valueChanged.connect(self.robot_entity.transform.setRotationZ)
    layout.addWidget(label_rotation, row, 0)
    layout.addWidget(self.spin_rotation, row, 1)
    row += 1

    self.readSettings()

closeEvent(event) #

Close the property windows.

Parameters:

Name Type Description Default
event QCloseEvent

The close event (unused)

required
Source code in cogip/entities/robot_manual.py
246
247
248
249
250
251
252
253
254
255
256
257
258
def closeEvent(self, event: QtGui.QCloseEvent):
    """
    Close the property windows.

    Arguments:
        event: The close event (unused)
    """
    RobotManualProperties.set_active_properties(None)

    settings = QtCore.QSettings("COGIP", "monitor")
    settings.setValue("manual_robot_dialog/geometry", self.saveGeometry())

    super().closeEvent(event)

set_active_properties(properties) classmethod #

Class method.

Set the current property window displayed.

Parameters:

Name Type Description Default
properties RobotManualProperties

The current property

required
Source code in cogip/entities/robot_manual.py
234
235
236
237
238
239
240
241
242
243
244
@classmethod
def set_active_properties(cls, properties: "RobotManualProperties"):
    """
    Class method.

    Set the current property window displayed.

    Arguments:
        properties: The current property
    """
    cls.active_properties = properties