| 152 | | We need to create our remote control, in order to drive our simulated robot. for this example, let's use an old gamepad, a [http://www.thrustmaster.com/en_IN/products/firestorm-dual-analog-3 Thrustmaster Firestorm Dual Analog 3]. As I own such gamepad, I already added support in Py4bot. |
| 153 | | |
| 154 | | Back in '''{{{hexapod.py}}}''': |
| 155 | | |
| 156 | | {{{ |
| 157 | | #!python |
| 158 | | |
| 159 | | class Gamepad(RemoteControl): |
| 160 | | def _createFrontend(self): |
| 161 | | return FrontendFactory().create("thrustmaster", path="/dev/input/by-id/usb-Mega_World_Thrustmaster_dual_analog_3.2-event-joystick") |
| 162 | | |
| 163 | | def _buildComponents(self): |
| 164 | | self._addComponent(Button, command=GaitSequencer().walkStop, key="button_000") |
| 165 | | self._addComponent(Button, command=GaitSequencer().walkStep, key="button_003") |
| 166 | | |
| 167 | | self._addComponent(Button, command=GaitSequencer().selectPrevGait, key="button_009", trigger="hold") |
| 168 | | self._addComponent(Button, command=GaitSequencer().selectNextGait, key="button_008", trigger="hold") |
| 169 | | |
| 170 | | self._addComponent(Joystick, command=GaitSequencer().walk, keys=("analog_02", "analog_03", "analog_00"), mapper=MapperWalk()) |
| 171 | | |
| 172 | | self._addComponent(Button, command=self.robot.incBodyPosition, key="button_004", mapper=MapperSetValue(dz=+5)) |
| 173 | | self._addComponent(Button, command=self.robot.incBodyPosition, key="button_005", mapper=MapperSetValue(dz=-5)) |
| 174 | | |
| 175 | | self._addComponent(Analog, command=self.robot.setBodyExtraPosition, key="analog_01", modifier="button_006", mapper=MapperSet('z')) |
| 176 | | }}} |
| 177 | | |
| 194 | | def addGait(gaitClass, gaitName): |
| 195 | | gait = gaitClass(gaitName, settings.GAIT_LEGS_GROUPS[gaitName], settings.GAIT_PARAMS[gaitName]) |
| 196 | | GaitManager().add(gait) |
| 197 | | |
| 198 | | addGait(GaitTripod, "tripod") |
| 199 | | addGait(GaitTetrapod, "tetrapod") |
| 200 | | addGait(GaitRiple, "riple") |
| 201 | | addGait(GaitWave, "metachronal") |
| 202 | | addGait(GaitWave, "wave") |
| | 168 | gait = GaitRiple("riple", settings.GAIT_LEGS_GROUPS, settings.GAIT_PARAMS) |
| | 169 | GaitManager().add(gait) |
| 211 | | GAIT_LEGS_GROUPS = { |
| 212 | | 'tripod': (('RM', 'LF', 'LR'), ('RF', 'LM', 'RR')), |
| 213 | | 'tetrapod': (('RR', 'LM'), ('RF', 'LR'), ('RM', 'LF')), |
| 214 | | 'riple': (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)), |
| 215 | | 'metachronal': (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)), |
| 216 | | 'wave': (('RR',), ('RM',), ('RF',), ('LR',), ('LM',), ('LF',)) |
| 217 | | } |
| | 178 | GAIT_LEGS_GROUPS = (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)) |
| 220 | | 'tripod': {'length': 40., 'angle': 10., 'height': 40., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 221 | | 'tetrapod': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 222 | | 'riple': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 300.}, |
| 223 | | 'metachronal': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 224 | | 'wave': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.} |
| 225 | | } |
| 226 | | }}} |
| 227 | | |
| 228 | | Final steps are: instanciate the gamepad, launch the gait sequencer, and run the robot! |
| 229 | | |
| 230 | | {{{ |
| 231 | | #!python |
| 232 | | |
| 233 | | remote = Gamepad(robot) |
| | 181 | 'length': 40., |
| | 182 | 'angle': 10., |
| | 183 | 'height': 30., |
| | 184 | 'minLength': 4., |
| | 185 | 'minAngle': 2., |
| | 186 | 'speedMin': 50., |
| | 187 | 'speedMax': 300. |
| | 188 | } |
| | 189 | }}} |
| | 190 | |
| | 191 | Final steps are: launch the gait sequencer, move a little bit the body position, ask the robot to start walking, and run the robot main loop: |
| | 192 | |
| | 193 | {{{ |
| | 194 | #!python |
| 353 | | {{{LEGS_SERVOS_MAPPING}}} dict contains a table to map all joints to servos nums. |
| 354 | | |
| 355 | | {{{ |
| 356 | | #!python |
| 357 | | |
| 358 | | GAIT_LEGS_GROUPS = { |
| 359 | | 'tripod': (('RM', 'LF', 'LR'), ('RF', 'LM', 'RR')), |
| 360 | | 'tetrapod': (('RR', 'LM'), ('RF', 'LR'), ('RM', 'LF')), |
| 361 | | 'riple': (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)), |
| 362 | | 'metachronal': (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)), |
| 363 | | 'wave': (('RR',), ('RM',), ('RF',), ('LR',), ('LM',), ('LF',)) |
| 364 | | } |
| 365 | | }}} |
| 366 | | |
| 367 | | {{{GAIT_LEGS_GROUPS}}} dict contains the legs grouped together and controlled at the same time during the gait usage. |
| 368 | | |
| 369 | | For example, the '''tripod''' gait is made of 2 groups of 3 legs. |
| | 313 | {{{LEGS_ACTUATORS_MAPPING}}} dict contains a table to map all joints to actuators nums. |
| | 314 | |
| | 315 | {{{ |
| | 316 | #!python |
| | 317 | |
| | 318 | GAIT_LEGS_GROUPS = (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)) |
| | 319 | }}} |
| | 320 | |
| | 321 | {{{GAIT_LEGS_GROUPS}}} contains the legs grouped together and controlled at the same time during the gait usage. |
| | 322 | |
| | 323 | In this example, the '''riple''' gait is made of 6 groups of 1 legs. |
| 377 | | 'tripod': {'length': 40., 'angle': 10., 'height': 40., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 378 | | 'tetrapod': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 379 | | 'riple': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 300.}, |
| 380 | | 'metachronal': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 381 | | 'wave': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.} |
| 382 | | } |
| 383 | | }}} |
| 384 | | |
| 385 | | {{{GAIT_PARAMS}}} dict contains some additional gaits params: |
| | 331 | 'length': 40., |
| | 332 | 'angle': 10., |
| | 333 | 'height': 30., |
| | 334 | 'minLength': 4., |
| | 335 | 'minAngle': 2., |
| | 336 | 'speedMin': 50., |
| | 337 | 'speedMax': 300. |
| | 338 | } |
| | 339 | }}} |
| | 340 | |
| | 341 | {{{GAIT_PARAMS}}} contains some additional gaits params: |
| | 354 | |
| | 355 | In this tutorial, we are just going to add a remote control in order to drive our tutorial 1 simulated robot. |
| | 356 | |
| | 357 | Add the following code between the {{{Hexapod}} class, and the {{{main()}}} function: |
| | 358 | |
| | 359 | |
| | 360 | {{{ |
| | 361 | #!python |
| | 362 | |
| | 363 | class Gamepad(RemoteControl): |
| | 364 | def _createFrontend(self): |
| | 365 | return FrontendFactory().create("thrustmaster", path="/dev/input/by-id/usb-Mega_World_Thrustmaster_dual_analog_3.2-event-joystick") |
| | 366 | |
| | 367 | def _buildComponents(self): |
| | 368 | self._addComponent(Button, command=GaitSequencer().walkStop, key="button_000") |
| | 369 | self._addComponent(Button, command=GaitSequencer().walkStep, key="button_003") |
| | 370 | |
| | 371 | self._addComponent(Button, command=GaitSequencer().selectPrevGait, key="button_009", trigger="hold") |
| | 372 | self._addComponent(Button, command=GaitSequencer().selectNextGait, key="button_008", trigger="hold") |
| | 373 | |
| | 374 | self._addComponent(Joystick, command=GaitSequencer().walk, keys=("analog_02", "analog_03", "analog_00"), mapper=MapperWalk()) |
| | 375 | |
| | 376 | self._addComponent(Button, command=self.robot.incBodyPosition, key="button_004", mapper=MapperSetValue(dz=+5)) |
| | 377 | self._addComponent(Button, command=self.robot.incBodyPosition, key="button_005", mapper=MapperSetValue(dz=-5)) |
| | 378 | |
| | 379 | self._addComponent(Analog, command=self.robot.setBodyExtraPosition, key="analog_01", modifier="button_006", mapper=MapperSet('z')) |
| | 380 | }}} |
| | 381 | |
| | 382 | Then, modify the {{{main.py}}} function as following: |
| | 383 | |
| | 384 | {{{ |
| | 385 | #!python |
| | 386 | |
| | 387 | def main(): |
| | 388 | robot = Hexapod() |
| | 389 | |
| | 390 | robot = Hexapod() |
| | 391 | |
| | 392 | gait = GaitRiple("riple", settings.GAIT_LEGS_GROUPS, settings.GAIT_PARAMS) |
| | 393 | GaitManager().add(gait) |
| | 394 | |
| | 395 | remote = Gamepad(robot) |
| | 396 | |
| | 397 | GaitSequencer().start() |
| | 398 | remote.start() |
| | 399 | |
| | 400 | robot.setBodyPosition(z=-30) |
| | 401 | |
| | 402 | robot.mainLoop() |
| | 403 | |
| | 404 | remote.stop() |
| | 405 | remote.join() |
| | 406 | GaitSequencer().stop() |
| | 407 | GaitSequencer().join() |
| | 408 | }}} |
| | 409 | |
| | 410 | == Tutorial 3 == |
| | 411 | |
| | 412 | ''Files for this tutorial are available in [source:/py4bot/examples/tutorial_3/]'' |
| | 511 | |
| | 512 | |
| | 513 | |
| | 514 | |
| | 515 | |
| | 516 | We need to create our remote control, in order to drive our simulated robot. for this example, let's use an old gamepad, a [http://www.thrustmaster.com/en_IN/products/firestorm-dual-analog-3 Thrustmaster Firestorm Dual Analog 3]. As I own such gamepad, I already added support in Py4bot. |
| | 517 | |
| | 518 | Back in '''{{{hexapod.py}}}''': |
| | 519 | |
| | 520 | {{{ |
| | 521 | #!python |
| | 522 | |
| | 523 | class Gamepad(RemoteControl): |
| | 524 | def _createFrontend(self): |
| | 525 | return FrontendFactory().create("thrustmaster", path="/dev/input/by-id/usb-Mega_World_Thrustmaster_dual_analog_3.2-event-joystick") |
| | 526 | |
| | 527 | def _buildComponents(self): |
| | 528 | self._addComponent(Button, command=GaitSequencer().walkStop, key="button_000") |
| | 529 | self._addComponent(Button, command=GaitSequencer().walkStep, key="button_003") |
| | 530 | |
| | 531 | self._addComponent(Button, command=GaitSequencer().selectPrevGait, key="button_009", trigger="hold") |
| | 532 | self._addComponent(Button, command=GaitSequencer().selectNextGait, key="button_008", trigger="hold") |
| | 533 | |
| | 534 | self._addComponent(Joystick, command=GaitSequencer().walk, keys=("analog_02", "analog_03", "analog_00"), mapper=MapperWalk()) |
| | 535 | |
| | 536 | self._addComponent(Button, command=self.robot.incBodyPosition, key="button_004", mapper=MapperSetValue(dz=+5)) |
| | 537 | self._addComponent(Button, command=self.robot.incBodyPosition, key="button_005", mapper=MapperSetValue(dz=-5)) |
| | 538 | |
| | 539 | self._addComponent(Analog, command=self.robot.setBodyExtraPosition, key="analog_01", modifier="button_006", mapper=MapperSet('z')) |
| | 540 | }}} |
| | 541 | |
| | 542 | |