|
| 1 | +from dm_control import mjcf |
| 2 | +import numpy as np |
| 3 | + |
| 4 | +def create_back_legs(model, primary_axis, bone_position, bones, side_sign, |
| 5 | + bone_size, pelvic_bones, parent): |
| 6 | + |
| 7 | + pelvis = parent |
| 8 | + # Hip joint sites: |
| 9 | + scale = np.asarray([bone_size[bone] for bone in pelvic_bones]).mean() |
| 10 | + hip_pos = np.array((-.23, -.6, -.16)) * scale |
| 11 | + for side in ['_L', '_R']: |
| 12 | + pelvis.add( |
| 13 | + 'site', name='hip' + side, size=[0.011], pos=hip_pos * side_sign[side]) |
| 14 | + |
| 15 | + # Upper legs: |
| 16 | + upper_leg = {} |
| 17 | + femurs = [b for b in bones if 'Fem' in b] |
| 18 | + use_tendons = False |
| 19 | + if not use_tendons: |
| 20 | + femurs += [b for b in bones if 'Patella' in b] |
| 21 | + for side in ['_L', '_R']: |
| 22 | + body_pos = hip_pos * side_sign[side] |
| 23 | + leg = pelvis.add('body', name='upper_leg' + side, pos=body_pos) |
| 24 | + upper_leg[side] = leg |
| 25 | + for bone in [b for b in femurs if side in b]: |
| 26 | + leg.add( |
| 27 | + 'geom', |
| 28 | + name=bone, |
| 29 | + mesh=bone, |
| 30 | + pos=-bone_position['Pelvis'] - body_pos, |
| 31 | + dclass='bone') |
| 32 | + |
| 33 | + # Hip joints |
| 34 | + for dof in ['_supinate', '_abduct', '_extend']: |
| 35 | + axis = primary_axis[dof].copy() |
| 36 | + if dof != '_extend': |
| 37 | + axis *= 1. if side != '_R' else -1. |
| 38 | + leg.add('joint', name='hip' + side + dof, dclass='hip' + dof, axis=axis) |
| 39 | + |
| 40 | + # Knee sites |
| 41 | + scale = bone_size['Femoris_L'] |
| 42 | + knee_pos = np.array((-0.2, -0.27, -1.45)) * scale |
| 43 | + leg.add('site', type='cylinder', name='knee' + side, size=[0.003, .02], |
| 44 | + zaxis=(0, 1, 0), pos=knee_pos * side_sign[side]) |
| 45 | + pos = np.array((-.01, -.02, -.08)) * side_sign[side] |
| 46 | + euler = [-10 * (1. if side == '_R' else -1.), 20, 0] |
| 47 | + leg.add( |
| 48 | + 'geom', |
| 49 | + name=leg.name + '0_collision', |
| 50 | + pos=pos, |
| 51 | + size=[.04, .08], |
| 52 | + euler=euler, |
| 53 | + dclass='collision_primitive') |
| 54 | + pos = np.array((-.03, 0, -.05)) |
| 55 | + euler = [-10 * (1. if side == '_R' else -1.), 5, 0] |
| 56 | + leg.add( |
| 57 | + 'geom', |
| 58 | + name=leg.name + '1_collision', |
| 59 | + pos=pos, |
| 60 | + size=[.04, .04], |
| 61 | + euler=euler, |
| 62 | + dclass='collision_primitive') |
| 63 | + |
| 64 | + # Patella |
| 65 | + if use_tendons: |
| 66 | + # Make patella body |
| 67 | + pass |
| 68 | + |
| 69 | + # Lower legs: |
| 70 | + lower_leg = {} |
| 71 | + lower_leg_bones = [b for b in bones if 'Tibia_' in b or 'Fibula' in b] |
| 72 | + for side in ['_L', '_R']: |
| 73 | + body_pos = knee_pos * side_sign[side] |
| 74 | + leg = upper_leg[side].add('body', name='lower_leg' + side, pos=body_pos) |
| 75 | + lower_leg[side] = leg |
| 76 | + for bone in [b for b in lower_leg_bones if side in b]: |
| 77 | + leg.add( |
| 78 | + 'geom', |
| 79 | + name=bone, |
| 80 | + mesh=bone, |
| 81 | + pos=-bone_position['Pelvis'] - upper_leg[side].pos - body_pos, |
| 82 | + dclass='bone') |
| 83 | + # Knee joints |
| 84 | + leg.add('joint', name='knee' + side, dclass='knee', axis=(0, -1, 0)) |
| 85 | + |
| 86 | + # Ankle sites |
| 87 | + scale = bone_size['Tibia_L'] |
| 88 | + ankle_pos = np.array((-1.27, 0.04, -0.98)) * scale |
| 89 | + leg.add('site', type='cylinder', name='ankle' + side, size=[0.003, .013], |
| 90 | + zaxis=(0, 1, 0), pos=ankle_pos*side_sign[side]) |
| 91 | + |
| 92 | + # Feet: |
| 93 | + foot = {} |
| 94 | + foot_bones = [b for b in bones if 'tars' in b.lower() or 'tuber' in b] |
| 95 | + for side in ['_L', '_R']: |
| 96 | + body_pos = ankle_pos * side_sign[side] |
| 97 | + leg = lower_leg[side].add('body', name='foot' + side, pos=body_pos) |
| 98 | + foot[side] = leg |
| 99 | + for bone in [b for b in foot_bones if side in b]: |
| 100 | + leg.add( |
| 101 | + 'geom', |
| 102 | + name=bone, |
| 103 | + mesh=bone, |
| 104 | + pos=-bone_position['Pelvis'] - upper_leg[side].pos - |
| 105 | + lower_leg[side].pos - body_pos, |
| 106 | + dclass='bone') |
| 107 | + # Ankle joints |
| 108 | + leg.add('joint', name='ankle' + side, dclass='ankle', axis=(0, 1, 0)) |
| 109 | + pos = np.array((-.01, -.005, -.05)) * side_sign[side] |
| 110 | + leg.add( |
| 111 | + 'geom', |
| 112 | + name=leg.name + '_collision', |
| 113 | + size=[.015, .07], |
| 114 | + pos=pos, |
| 115 | + dclass='collision_primitive') |
| 116 | + |
| 117 | + # Toe sites |
| 118 | + scale = bone_size['Metatarsi_R_2'] |
| 119 | + toe_pos = np.array((-.37, -.2, -2.95)) * scale |
| 120 | + leg.add('site', type='cylinder', name='toe' + side, size=[0.003, .025], |
| 121 | + zaxis=(0, 1, 0), pos=toe_pos*side_sign[side]) |
| 122 | + |
| 123 | + # Toes: |
| 124 | + toe_bones = [b for b in bones if 'Phalange' in b] |
| 125 | + toe_geoms = [] |
| 126 | + sole_sites = [] |
| 127 | + nails = [] |
| 128 | + for side in ['_L', '_R']: |
| 129 | + body_pos = toe_pos * side_sign[side] |
| 130 | + foot_anchor = foot[side].add( |
| 131 | + 'body', name='foot_anchor' + side, pos=body_pos) |
| 132 | + foot_anchor.add( |
| 133 | + 'geom', |
| 134 | + name=foot_anchor.name, |
| 135 | + dclass='foot_primitive', |
| 136 | + type='box', |
| 137 | + size=(.005, .005, .005), |
| 138 | + contype=0, |
| 139 | + conaffinity=0) |
| 140 | + foot_anchor.add('site', name=foot_anchor.name, dclass='sensor') |
| 141 | + leg = foot_anchor.add('body', name='toe' + side) |
| 142 | + for bone in [b for b in toe_bones if side in b]: |
| 143 | + geom = leg.add( |
| 144 | + 'geom', |
| 145 | + name=bone, |
| 146 | + mesh=bone, |
| 147 | + pos=-bone_position['Pelvis'] - upper_leg[side].pos - |
| 148 | + lower_leg[side].pos - foot[side].pos - body_pos, |
| 149 | + dclass='bone') |
| 150 | + if 'B_3' in bone: |
| 151 | + nails.append(bone) |
| 152 | + geom.dclass = 'visible_bone' |
| 153 | + else: |
| 154 | + toe_geoms.append(geom) |
| 155 | + # Toe joints |
| 156 | + leg.add('joint', name='toe' + side, dclass='toe', axis=(0, 1, 0)) |
| 157 | + # Collision geoms |
| 158 | + leg.add( |
| 159 | + 'geom', |
| 160 | + name=leg.name + '0_collision', |
| 161 | + size=[0.018, 0.012], |
| 162 | + pos=[.015, 0, -.02], |
| 163 | + euler=(90, 0, 0), |
| 164 | + dclass='foot_primitive') |
| 165 | + leg.add( |
| 166 | + 'geom', |
| 167 | + name=leg.name + '1_collision', |
| 168 | + size=[0.01, 0.015], |
| 169 | + pos=[.035, 0, -.028], |
| 170 | + euler=(90, 0, 0), |
| 171 | + dclass='foot_primitive') |
| 172 | + leg.add( |
| 173 | + 'geom', |
| 174 | + name=leg.name + '2_collision', |
| 175 | + size=[0.008, 0.01], |
| 176 | + pos=[.045, 0, -.03], |
| 177 | + euler=(90, 0, 0), |
| 178 | + dclass='foot_primitive') |
| 179 | + sole = leg.add( |
| 180 | + 'site', |
| 181 | + name='sole' + side, |
| 182 | + size=(.025, .03, .008), |
| 183 | + pos=(.026, 0, -.033), |
| 184 | + type='box', |
| 185 | + dclass='sensor') |
| 186 | + |
| 187 | + sole_sites.append(sole) |
| 188 | + |
| 189 | + physics = mjcf.Physics.from_mjcf_model(model) |
| 190 | + |
| 191 | + for side in ['_L', '_R']: |
| 192 | + # lower leg: |
| 193 | + leg = lower_leg[side] |
| 194 | + leg.add( |
| 195 | + 'geom', |
| 196 | + name=leg.name + '_collision', |
| 197 | + pos=physics.bind(leg).ipos * 1.3, |
| 198 | + size=[.02, .1], |
| 199 | + quat=physics.bind(leg).iquat, |
| 200 | + dclass='collision_primitive') |
| 201 | + |
| 202 | + return nails, sole_sites |
0 commit comments