| 385 | | == Complex example == |
| 386 | | |
| 387 | | Have a look at [[source:py4bot/examples/cronos|py4bot/examples/cronos]], which contain the code for my 4DoF hexapod |
| | 384 | |
| | 385 | == Real robot example == |
| | 386 | |
| | 387 | Ok, a simulated robot is cool, but a real one is much more fun! |
| | 388 | |
| | 389 | Let's say that you built you own cool 3DoF hexapod, like these: |
| | 390 | |
| | 391 | * http://www.thingiverse.com/thing:1338781 |
| | 392 | * http://www.thingiverse.com/thing:920882 |
| | 393 | * http://www.thingiverse.com/thing:879555 |
| | 394 | * http://www.thingiverse.com/thing:31569 |
| | 395 | * http://www.thingiverse.com/thing:1603 |
| | 396 | * http://www.thingiverse.com/thing:1604 |
| | 397 | * http://www.thingiverse.com/thing:1080281 |
| | 398 | * http://www.thingiverse.com/thing:585 (this is an octopod; I didn't yet implement gaits for such robot, but it is possible) |
| | 399 | |
| | 400 | 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. |
| | 401 | |
| | 402 | Let's modify our {{{Hexapod}}} class: |
| | 403 | |
| | 404 | {{{ |
| | 405 | #!python |
| | 406 | |
| | 407 | import settings |
| | 408 | |
| | 409 | |
| | 410 | class Hexapod(Robot): |
| | 411 | def _createLegs(self): |
| | 412 | legs = {} |
| | 413 | legIk = {} |
| | 414 | for legIndex in settings.LEGS_INDEX: |
| | 415 | legs[legIndex] = Leg3Dof(legIndex, {'coxa': Coxa(), 'femur': Femur(), 'tibia': Tibia()}) |
| | 416 | legIk[legIndex] = Leg3DofIk(settings.LEGS_GEOMETRY[legIndex]) |
| | 417 | |
| | 418 | return legs, legIk |
| | 419 | |
| | 420 | def _createActuatorPool(self): |
| | 421 | driver = Veyron() |
| | 422 | pool = ServoPool(driver) |
| | 423 | |
| | 424 | for leg in self._legs.values(): |
| | 425 | |
| | 426 | # Create joints servos |
| | 427 | num = settings.LEGS_SERVOS_MAPPING[leg.index]['coxa'] |
| | 428 | servo = Servo(leg.coxa, num) |
| | 429 | pool.add(servo) |
| | 430 | |
| | 431 | num = settings.LEGS_SERVOS_MAPPING[leg.index]['femur'] |
| | 432 | servo = Servo(leg.femur, num) |
| | 433 | pool.add(servo) |
| | 434 | |
| | 435 | num = settings.LEGS_SERVOS_MAPPING[leg.index]['tibia'] |
| | 436 | servo = Servo(leg.tibia, num) |
| | 437 | pool.add(servo) |
| | 438 | return pool |
| | 439 | }}} |
| | 440 | |
| | 441 | In addition, we must add a few things in the '''{{{settings.py}}}''' module: |
| | 442 | |
| | 443 | {{{ |
| | 444 | #!python |
| | 445 | |
| | 446 | SERVOS_CALIBRATION = { |
| | 447 | 0: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg RF |
| | 448 | 1: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg RF |
| | 449 | 2: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg RF |
| | 450 | 3: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # unused |
| | 451 | 4: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg RM |
| | 452 | 5: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg RM |
| | 453 | 6: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg RM |
| | 454 | 7: {'offset': 0., 'pulse90': 1505, 'ratio': 1000/90.}, # unused |
| | 455 | 8: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg RR |
| | 456 | 9: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg RR |
| | 457 | 10: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg RR |
| | 458 | 11: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # unused |
| | 459 | 12: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # unused |
| | 460 | 13: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg LR |
| | 461 | 14: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg LR |
| | 462 | 15: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg LR |
| | 463 | 16: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # unused |
| | 464 | 17: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg LM |
| | 465 | 18: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg LM |
| | 466 | 19: {'offset': 0., 'pulse90': 1505, 'ratio': 1000/90.}, # coxa leg LM |
| | 467 | 20: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # unused |
| | 468 | 21: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # tibia leg LF |
| | 469 | 22: {'offset': -90., 'pulse90': 1500, 'ratio': 1000/90.}, # femur leg LF |
| | 470 | 23: {'offset': 0., 'pulse90': 1500, 'ratio': 1000/90.}, # coxa leg LF |
| | 471 | } |
| | 472 | }}} |
| | 473 | |
| | 474 | {{{SERVOS_CALIBRATION}}} dict contains: |
| | 475 | |
| | 476 | * {{{offset}}} is the angle between the servo reference and the real angle. See the [[FAQ#Howisgeometrydefined|FAQ]] for the real angles definition; |
| | 477 | * {{{pulse90}}} is the pulse value for the neutral position of the servo, which is usually 90°; |
| | 478 | * {{{ratio}}} is the pulse width per degree. |
| | 479 | |
| | 480 | Offsets may vary, depending how you mount the servos. Same, ratio sign may have to be inverted on one side, if you have a symetrical design; all angle are always computed using trigonometric direction (CCW). |
| | 481 | |
| | 482 | There is a graphical tool called '''{{{py4bot-gui-calibration.py}}}''' to help you calibrate your servos, and generate this dict. |