| 296 | | Then, modify the {{{main()}}} function as following: |
| 297 | | |
| 298 | | {{{ |
| 299 | | #!python |
| 300 | | |
| 301 | | def main(): |
| 302 | | robot = Hexapod() |
| 303 | | |
| 304 | | gait = GaitRiple("riple", settings.GAIT_LEGS_GROUPS, settings.GAIT_PARAMS) |
| 305 | | GaitManager().add(gait) |
| 306 | | |
| 307 | | remote = Gamepad(robot) |
| 308 | | |
| 309 | | GaitSequencer().start() |
| 310 | | remote.start() |
| 311 | | |
| 312 | | robot.setBodyPosition(z=-30) |
| 313 | | |
| 314 | | robot.mainLoop() |
| 315 | | |
| 316 | | remote.stop() |
| 317 | | remote.join() |
| 318 | | GaitSequencer().stop() |
| 319 | | GaitSequencer().join() |
| 320 | | }}} |
| 321 | | |
| 322 | | See [[UserGuideGit#Controllers|documentation]] for a full description of the controllers implementation. |
| 323 | | == Tutorial 3 == |
| 324 | | |
| 325 | | ''Files for this tutorial are available in [source:/py4bot/examples/tutorial_3/]'' |
| 326 | | |
| 327 | | Ok, a simulated robot is cool, but a real one is much more fun! |
| 328 | | |
| 329 | | Let's say that you built you own cool 3DoF hexapod, like one of these: |
| 330 | | |
| 331 | | * http://www.thingiverse.com/search/page:5?q=hexapod&sa= |
| 332 | | |
| 333 | | and let's say you want to use a [http://www.dfrobot.com/wiki/index.php/Veyron_Servo_Driver_(24-Channel)_(SKU:DRI0029) Veyron servos driver] as low-level hardware driver. |
| 334 | | |
| 335 | | Here is the new {{{Hexapod}}} class: |
| 336 | | |
| 337 | | {{{ |
| 338 | | #!python |
| 339 | | |
| 340 | | class Hexapod(Robot): |
| 341 | | def _createLegs(self): |
| 342 | | legs = {} |
| 343 | | legIk = {} |
| 344 | | for legIndex in settings.LEGS_INDEX: |
| 345 | | legs[legIndex] = Leg3Dof(legIndex, {'coxa': Coxa(), 'femur': Femur(), 'tibia': Tibia()}) |
| 346 | | legIk[legIndex] = Leg3DofIk(settings.LEGS_GEOMETRY[legIndex]) |
| 347 | | |
| 348 | | return legs, legIk |
| 349 | | |
| 350 | | def _createActuatorPool(self): |
| 351 | | driver = Veyron() |
| 352 | | pool = ServoPool(driver) |
| 353 | | |
| 354 | | for leg in self._legs.values(): |
| 355 | | |
| 356 | | # Create joints servos |
| 357 | | num = settings.LEGS_SERVOS_MAPPING[leg.index]['coxa'] |
| 358 | | servo = Servo(leg.coxa, num, **settings.SERVOS_CALIBRATION[num]) |
| 359 | | pool.add(servo) |
| 360 | | |
| 361 | | num = settings.LEGS_SERVOS_MAPPING[leg.index]['femur'] |
| 362 | | servo = Servo(leg.femur, num, **settings.SERVOS_CALIBRATION[num]) |
| 363 | | pool.add(servo) |
| 364 | | |
| 365 | | num = settings.LEGS_SERVOS_MAPPING[leg.index]['tibia'] |
| 366 | | servo = Servo(leg.tibia, num, **settings.SERVOS_CALIBRATION[num]) |
| 367 | | pool.add(servo) |
| 368 | | |
| 369 | | return pool |
| 370 | | }}} |
| 371 | | |
| 372 | | As you can see, this time, we used the {{{Servo}}} and {{{ServoPool}}} classes, which inherit, respectively, {{{Actuator}}} and {{{ActuatorPool}}} classes. |
| 373 | | |
| 374 | | In the same time, we are going to add a few more pre-defined gaits, in {{{main()}}}: |
| 375 | | |
| 376 | | {{{ |
| 377 | | #!python |
| 378 | | |
| 379 | | def main(): |
| 380 | | def addGait(gaitClass, gaitName): |
| 381 | | gait = gaitClass(gaitName, settings.GAIT_LEGS_GROUPS[gaitName], settings.GAIT_PARAMS[gaitName]) |
| 382 | | GaitManager().add(gait) |
| 383 | | |
| 384 | | addGait(GaitTripod, "tripod") |
| 385 | | addGait(GaitTetrapod, "tetrapod") |
| 386 | | addGait(GaitRiple, "riple") |
| 387 | | addGait(GaitWave, "metachronal") |
| 388 | | addGait(GaitWave, "wave") |
| 389 | | GaitManager().select("riple") |
| 390 | | }}} |
| 391 | | |
| 392 | | As we now have more than one gait, we explicitely tell which one we are going to use as default. Note that it is possible to change the current gait using some buttons of the remote control. See [UserGuideGit#Controllers|documentation]. |
| 393 | | |
| 394 | | The rest is similar to tutorial 2. |
| | 296 | Here, we will see how to use the 3D simulation stuff. |
| | 297 | |
| | 298 | {{{ |
| | 299 | #!python |
| | 300 | |
| | 301 | }}} |
| 398 | | In addition, we must modify/add a few things in the '''{{{settings.py}}}''' module: |
| 399 | | |
| 400 | | {{{ |
| 401 | | #!python |
| 402 | | |
| 403 | | # Legs / servos mapping |
| 404 | | LEGS_SERVOS_MAPPING = { |
| 405 | | 'RF': {'coxa': 0, 'femur': 1, 'tibia': 2}, |
| 406 | | 'RM': {'coxa': 4, 'femur': 5, 'tibia': 6}, |
| 407 | | 'RR': {'coxa': 8, 'femur': 9, 'tibia': 10}, |
| 408 | | 'LR': {'coxa': 15, 'femur': 14, 'tibia': 13}, |
| 409 | | 'LM': {'coxa': 19, 'femur': 18, 'tibia': 17}, |
| 410 | | 'LF': {'coxa': 23, 'femur': 22, 'tibia': 21} |
| 411 | | } |
| 412 | | |
| 413 | | SERVOS_CALIBRATION = { |
| 414 | | 0: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg RF |
| 415 | | 1: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg RF |
| 416 | | 2: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg RF |
| 417 | | |
| 418 | | 4: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg RM |
| 419 | | 5: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg RM |
| 420 | | 6: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg RM |
| 421 | | |
| 422 | | 8: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg RR |
| 423 | | 9: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg RR |
| 424 | | 10: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg RR |
| 425 | | |
| 426 | | 15: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg LR |
| 427 | | 14: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg LR |
| 428 | | 13: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg LR |
| 429 | | |
| 430 | | 19: {'offset': 0., 'pulse90': 1505, 'ratio': 1000/90.}, # coxa leg LM |
| 431 | | 18: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg LM |
| 432 | | 17: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg LM |
| 433 | | |
| 434 | | 23: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg LF |
| 435 | | 22: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg LF |
| 436 | | 21: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg LF |
| 437 | | } |
| 438 | | |
| 439 | | # Gaits |
| 440 | | GAIT_LEGS_GROUPS = { |
| 441 | | 'tripod': (('RM', 'LF', 'LR'), ('RF', 'LM', 'RR')), |
| 442 | | 'tetrapod': (('RR', 'LM'), ('RF', 'LR'), ('RM', 'LF')), |
| 443 | | 'riple': (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)), |
| 444 | | 'metachronal': (('RR',), ('LM',), ('RF',), ('LR',), ('RM',), ('LF',)), |
| 445 | | 'wave': (('RR',), ('RM',), ('RF',), ('LR',), ('LM',), ('LF',)) |
| 446 | | } |
| 447 | | |
| 448 | | GAIT_PARAMS = { |
| 449 | | 'tripod': {'length': 40., 'angle': 10., 'height': 40., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 450 | | 'tetrapod': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 451 | | 'riple': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 300.}, |
| 452 | | 'metachronal': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.}, |
| 453 | | 'wave': {'length': 40., 'angle': 10., 'height': 30., 'minLength': 4., 'minAngle': 2., 'speedMin': 50., 'speedMax': 200.} |
| 454 | | } |
| 455 | | }}} |
| 456 | | |
| 457 | | |
| 458 | | We renamed {{{LEGS_ACTUATOR_MAPPING}}} to {{{LEGS_SERVOS_MAPPING}}}, and added the {{{SERVOS_CALIBRATION}}} dict, which contains |
| 459 | | |
| 460 | | {{{GAIT_LEGS_GROUPS}}} and {{{GAIT_PARAMS}}} are now dicts, to handle all our gaits params. |
| | 305 | |
| | 306 | {{{ |
| | 307 | #!python |
| | 308 | |
| | 309 | }}} |