| 17 | | Have a look at [[source:py4bot/examples/hexapod|py4bot/examples/hexapod/]] to see how to build a simple 3DoF hexapod. |
| | 17 | As '''Py4bot''' is just a framework, it is up to you to write the application matching your rogot. But don't worry, it is very easy. |
| | 18 | |
| | 19 | For this example, we are going to setup an application for a 3DoF hexapod. This hexapod will use a [http://www.dfrobot.com/wiki/index.php/Veyron_Servo_Driver_(24-Channel)_(SKU:DRI0029) Veryon servo driver], from DFRobot, as this driver is fully supported by Py4bot. To control this hexapod, we are going to use a [http://www.thrustmaster.com/en_IN/products/firestorm-dual-analog-3 Thrustmaster Firestorm Dual Analog 3] gamepad. |
| | 20 | |
| | 21 | All usefull classes are available from the '''{{{api.py}}}''' module. So, we just have to import things from here. Let's create a '''{{{hexapod.py}}}''' file to put our code, and import what we are going to use in this tutorial: |
| | 22 | |
| | 23 | {{{ |
| | 24 | #!python |
| | 25 | |
| | 26 | # -*- coding: utf-8 -*- |
| | 27 | |
| | 28 | from py4bot.api import Logger |
| | 29 | from py4bot.api import GaitFactory, GaitManager, GaitSequencer |
| | 30 | from py4bot.api import Robot, Body |
| | 31 | from py4bot.api import ActuatorPool, ServoPool, Veyron |
| | 32 | from py4bot.api import Leg3DofIk, Leg3Dof, Coxa, Femur, Tibia |
| | 33 | from py4bot.api import RemoteControl, FrontendFactory |
| | 34 | from py4bot.api import MapperSet, MapperSetValue, MapperWalk |
| | 35 | }}} |
| | 36 | |
| | 37 | Now, let's create the robot! A multi-legs robot is mainly build from a body, and several legs. In most cases, the defaut body provided by Py4bot is OK, but in any case, we need to create legs. The second thing we also need to create is the ''actuator pool'', which contain all legs joints. In our example, joints are standard servos. So, here is what the main robot class looks like: |
| | 38 | |
| | 39 | {{{ |
| | 40 | #!python |
| | 41 | |
| | 42 | import settings |
| | 43 | |
| | 44 | |
| | 45 | class Hexapod(Robot): |
| | 46 | def _createLegs(self): |
| | 47 | legIk = Leg4DofIk(settings.LEGS_GEOMETRY) |
| | 48 | |
| | 49 | legs = {} |
| | 50 | legIk = {} |
| | 51 | for legIndex in settings.LEGS_INDEX: |
| | 52 | legs[legIndex] = Leg4Dof(legIndex, {'coxa': Coxa(), 'femur': Femur(), 'tibia': Tibia()}) |
| | 53 | legIk[legIndex] = Leg4DofIk(settings.LEGS_GEOMETRY[legIndex]) |
| | 54 | |
| | 55 | return legs, legIk |
| | 56 | |
| | 57 | def _createActuatorPool(self): |
| | 58 | driver = Veyron("/dev/ttyACM0", 57600) |
| | 59 | |
| | 60 | pool = ServoPool(driver) |
| | 61 | for leg in self._legs.values(): |
| | 62 | |
| | 63 | # Create joints actuators |
| | 64 | num = settings.LEGS_SERVOS_MAPPING[leg.index]['coxa'] |
| | 65 | servo = pool.create(leg.coxa, num, **settings.SERVOS_CALIBRATION[num]) |
| | 66 | pool.add(servo) |
| | 67 | |
| | 68 | num = settings.LEGS_SERVOS_MAPPING[leg.index]['femur'] |
| | 69 | servo = pool.create(leg.femur, num, **settings.SERVOS_CALIBRATION[num]) |
| | 70 | pool.add(servo) |
| | 71 | |
| | 72 | num = settings.LEGS_SERVOS_MAPPING[leg.index]['tibia'] |
| | 73 | servo = pool.create(leg.tibia, num, **settings.SERVOS_CALIBRATION[num]) |
| | 74 | pool.add(servo) |
| | 75 | |
| | 76 | return pool |
| | 77 | }}} |
| | 78 | |
| | 79 | |
| | 80 | As you can see, we just implemented 2 virtual methods, '''{{{_createLegs()}}}''' and '''{{{_createActuatorPool()}}}'''. Also note that we used some values from the '''{{{settings.py}}}''' module. This module is just a way to centralise the configuration of our hexapod. For now, it should contain s omething like: |
| | 81 | |
| | 82 | {{{ |
| | 83 | #!python |
| | 84 | |
| | 85 | # -*- coding: utf-8 -*- |
| | 86 | |
| | 87 | import math |
| | 88 | |
| | 89 | from py4bot.api import config |
| | 90 | |
| | 91 | |
| | 92 | # Legs index |
| | 93 | LEGS_INDEX = ('RF', 'RM', 'RR', 'LR', 'LM', 'LF') |
| | 94 | |
| | 95 | # Legs geometry |
| | 96 | LEGS_GEOMETRY = { |
| | 97 | 'RM': {'coxa': 25, 'femur': 45, 'tibia': 50}, |
| | 98 | 'RF': {'coxa': 25, 'femur': 45, 'tibia': 50}, |
| | 99 | 'LF': {'coxa': 25, 'femur': 45, 'tibia': 50}, |
| | 100 | 'LM': {'coxa': 25, 'femur': 45, 'tibia': 50}, |
| | 101 | 'LR': {'coxa': 25, 'femur': 45, 'tibia': 50}, |
| | 102 | 'RR': {'coxa': 25, 'femur': 45, 'tibia': 50} |
| | 103 | } |
| | 104 | |
| | 105 | # Legs origin |
| | 106 | LEGS_ORIGIN = { |
| | 107 | 'RM': {'x': 50., 'y': 0., 'gamma0' : 0.}, |
| | 108 | 'RF': {'x': 35., 'y': 80., 'gamma0' : 30.}, |
| | 109 | 'LF': {'x': -35., 'y': 80., 'gamma0' : 150.}, |
| | 110 | 'LM': {'x': -50., 'y': 0., 'gamma0' : 180.}, |
| | 111 | 'LR': {'x': -35., 'y': -80., 'gamma0' : 210.}, |
| | 112 | 'RR': {'x': 35., 'y': -80., 'gamma0' : 330.}, |
| | 113 | } |
| | 114 | config.initOrigin(LEGS_INDEX, LEGS_ORIGIN) |
| | 115 | |
| | 116 | # Legs (feet) neutral position (femur horizontal, tibia vertical) |
| | 117 | LEGS_NEUTRAL = { |
| | 118 | 'RM': { |
| | 119 | 'l': LEGS_GEOMETRY['RM']['coxa'] + LEGS_GEOMETRY['RM']['femur'], |
| | 120 | 'z': LEGS_GEOMETRY['RM']['tibia'] |
| | 121 | }, |
| | 122 | 'RF': { |
| | 123 | 'l': LEGS_GEOMETRY['RF']['coxa'] + LEGS_GEOMETRY['RF']['femur'], |
| | 124 | 'z': LEGS_GEOMETRY['RF']['tibia'] |
| | 125 | }, |
| | 126 | 'LF': { |
| | 127 | 'l': LEGS_GEOMETRY['LF']['coxa'] + LEGS_GEOMETRY['LF']['femur'], |
| | 128 | 'z': LEGS_GEOMETRY['LF']['tibia'] |
| | 129 | }, |
| | 130 | 'LM': { |
| | 131 | 'l': LEGS_GEOMETRY['LM']['coxa'] + LEGS_GEOMETRY['LM']['femur'], |
| | 132 | 'z': LEGS_GEOMETRY['LM']['tibia'] |
| | 133 | }, |
| | 134 | 'LR': { |
| | 135 | 'l': LEGS_GEOMETRY['LR']['coxa'] + LEGS_GEOMETRY['LR']['femur'], |
| | 136 | 'z': LEGS_GEOMETRY['LR']['tibia'] |
| | 137 | }, |
| | 138 | 'RR': { |
| | 139 | 'l': LEGS_GEOMETRY['RR']['coxa'] + LEGS_GEOMETRY['RR']['femur'], |
| | 140 | 'z': LEGS_GEOMETRY['RR']['tibia'] |
| | 141 | } |
| | 142 | } |
| | 143 | config.initNeutral(LEGS_INDEX, LEGS_NEUTRAL) |
| | 144 | |
| | 145 | # Legs / servos mapping |
| | 146 | LEGS_SERVOS_MAPPING = { |
| | 147 | 'RF': {'coxa': 0, 'femur': 1, 'tibia': 2}, |
| | 148 | 'RM': {'coxa': 4, 'femur': 5, 'tibia': 6}, |
| | 149 | 'RR': {'coxa': 8, 'femur': 9, 'tibia': 10}, |
| | 150 | 'LR': {'coxa': 15, 'femur': 14, 'tibia': 13}, |
| | 151 | 'LM': {'coxa': 19, 'femur': 18, 'tibia': 17}, |
| | 152 | 'LF': {'coxa': 23, 'femur': 22, 'tibia': 21} |
| | 153 | } |
| | 154 | |
| | 155 | # Servos calibration |
| | 156 | SERVOS_CALIBRATION = { |
| | 157 | 0: {'pulse90': 1500, 'ratio': 1000./90.}, # tibia leg RF |
| | 158 | 1: {'pulse90': 1500, 'ratio': 1000./90.}, # femur leg RF |
| | 159 | 2: {'pulse90': 1500, 'ratio': 1000./90.}, # coxa leg RF |
| | 160 | 3: {'pulse90': 1500, 'ratio': 1000./90.}, # free |
| | 161 | |
| | 162 | 4: {'pulse90': 1500, 'ratio': 1000./90.}, # tibia leg RM |
| | 163 | 5: {'pulse90': 1500, 'ratio': 1000./90.}, # femur leg RM |
| | 164 | 6: {'pulse90': 1500, 'ratio': 1000./90.}, # coxa leg RM |
| | 165 | 7: {'pulse90': 1500, 'ratio': 1000./90.}, # free |
| | 166 | |
| | 167 | 8: {'pulse90': 1500, 'ratio': 1000./90.}, # tibia leg RR |
| | 168 | 9: {'pulse90': 1500, 'ratio': 1000./90.}, # femur leg RR |
| | 169 | 10: {'pulse90': 1500, 'ratio': 1000./90.}, # coxa leg RR |
| | 170 | 11: {'pulse90': 1500, 'ratio': 1000./90.}, # free |
| | 171 | |
| | 172 | 12: {'pulse90': 1500, 'ratio': 1000./90.}, # free |
| | 173 | 13: {'pulse90': 1500, 'ratio': 1000./90.}, # tibia leg LR |
| | 174 | 14: {'pulse90': 1500, 'ratio': 1000./90.}, # femur leg LR |
| | 175 | 15: {'pulse90': 1500, 'ratio': 1000./90.}, # coxa leg LR |
| | 176 | |
| | 177 | 16: {'pulse90': 1500, 'ratio': 1000./90.}, # free |
| | 178 | 17: {'pulse90': 1500, 'ratio': 1000./90.}, # tibia leg LM |
| | 179 | 18: {'pulse90': 1500, 'ratio': 1000./90.}, # femur leg LM |
| | 180 | 19: {'pulse90': 1500, 'ratio': 1000./90.}, # coxa leg LM |
| | 181 | |
| | 182 | 20: {'pulse90': 1500, 'ratio': 1000./90.}, # free |
| | 183 | 21: {'pulse90': 1500, 'ratio': 1000./90.}, # tibia leg RM |
| | 184 | 22: {'pulse90': 1500, 'ratio': 1000./90.}, # femur leg RM |
| | 185 | 23: {'pulse90': 1500, 'ratio': 1000./90.}, # coxa leg RM |
| | 186 | } |
| | 187 | }}} |
| | 188 | |
| | 189 | |
| | 190 | |
| | 191 | |
| | 192 | |
| | 193 | |
| | 194 | |
| | 195 | |
| | 196 | |
| | 197 | |
| | 198 | ''Note: have a look at [[source:py4bot/examples/hexapod|py4bot/examples/cronos/]] to see how to build a 4DoF hexapod.'' |