-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
189 lines (149 loc) · 5.11 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
'''
dancing cheetah simulation
link to pybullet doc:
https://docs.google.com/document/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA/edit#heading=h.mq73m9o2gcpy
'''
import pybullet as p
import pybullet_data as pd
import time
import numpy as np
from src import trajectories as traj
# settings
create_gif= True # create GIF of simulation
max_force = 5 # maximal joint force
# timing parameters (at least 250 Hz)
t_end = 6
N_steps = 4000
dt = t_end/N_steps
tsteps = np.linspace(0, t_end, N_steps)
# video parameters
fps = 12
N_v = int(t_end*fps)
width = 400
height = 300
# array that maps quaro convention indices to MiniCheetah joint numbering
jointNumberConversion = np.array(
[[5, 1, 13, 9],
[6, 2, 14, 10],
[4, 0, 12, 8]])
def set_leg_angles(angles):
'''
changes the robot joint angles according to quaro convention
Parameters
----------
angles : 3x4 np.ndarray with angles in DEG
'''
angles *= 2.0*np.pi/360.0
p.setJointMotorControlArray(
robot,
jointNumberConversion.flatten(),
p.POSITION_CONTROL,
angles.flatten(),
forces=max_force*np.ones(12))
def inverse_kinematics(coordinates):
'''
Vectorized inverse kinematics
Parameters
----------
coordinates : (3,4) numpy.ndarray, absolute coordinates for each leg
Returns
-------
angles : (3,4) numpy.ndarray
angles for each leg in DEG [[femur], [tibia], [coxa]]
'''
# local copy of coordinates variable as Python is pass by reference
coordinates = np.copy(coordinates)
x = coordinates[0]
y = coordinates[1]
z = coordinates[2]
# Mini cheetah geometry
l1 = 0.209
l2 = 0.18
g = 0
h = 0
# inverse kinematics calculation, definitions can be found in doc
B = np.sqrt(y**2 + z**2)
A = np.sqrt(B**2 - g**2) - h
gamma = np.arctan(-y/z) - np.arcsin(g/B)
C = np.sqrt(A**2 + x**2)
C1 = ( l1**2 - l2**2 + C**2)/(2*C)
C2 = (-l1**2 + l2**2 + C**2)/(2*C)
alpha1 = -np.arctan(-x/A)
alpha2 = -np.arccos(np.clip(C1/l1, -1, 1))
teta = -np.arccos(np.clip(C2/l2, -1, 1))
alpha = alpha1 + alpha2
beta = -(teta + alpha2)
angles = np.array([alpha, beta, gamma])
# convert to deg
angles *= 360.0/(2.0*np.pi)
# replace NaN with zero
angles = np.nan_to_num(angles)
return angles
# caluclate leg positions for whole simulation (closed loop!)
legPos = traj.get_optimized_gait(tsteps)
# set up simulation
try:
p.resetSimulation()
except:
pass
p.connect(p.GUI)
p.setGravity(0,0,-9.81)
p.setAdditionalSearchPath(pd.getDataPath())
p.setTimeStep(dt)
floor = p.loadURDF("plane.urdf")
robot = p.loadURDF("src/urdf_files/mini_cheetah_no_inertia.urdf", [0,0,0.4])
# set robot color
numJoints = p.getNumJoints(robot)
p.changeVisualShape(robot,-1,rgbaColor=[1,1,1,1])
for j in range(numJoints):
p.changeVisualShape(robot,j,rgbaColor=[1,1,1,1])
# image variables
images = np.zeros((N_v, height, width, 4))
cnt = 0
# Wait until robot reaches initial position (workaround)
robPos, _ = p.getBasePositionAndOrientation(robot)
angles = inverse_kinematics(legPos[0])
set_leg_angles(angles)
for n in range(100):
p.stepSimulation()
# Simulation loop
print("loop start")
for n in range(N_steps):
t = tsteps[n]
# point camera onto robot
robPos, _ = p.getBasePositionAndOrientation(robot)
p.resetDebugVisualizerCamera(cameraDistance=0.5,
cameraYaw=50, cameraPitch=-35,
cameraTargetPosition=robPos)
# calculate and set position
pos = legPos[n]
angles = inverse_kinematics(pos)
set_leg_angles(angles)
# save image every now and then
if create_gif:
if(n%(int(N_steps/(t_end*fps))) == 0):
#viewMatrix = p.computeViewMatrix(
# cameraEyePosition = robPos,
# cameraTargetPosition = [0.5, 0.2, 0],
# cameraUpVector = [0, 0, 1]
# )
viewMatrix = p.computeViewMatrixFromYawPitchRoll(
cameraTargetPosition = robPos,
distance = 0.1,
yaw = 0,
pitch = 0,
roll = 0,
upAxisIndex = 2)
images[cnt] = p.getCameraImage(width, height, viewMatrix=viewMatrix)[2]
cnt += 1
cnt = np.min((cnt, N_v-1)) # prevent out of bounds
# simulation step
p.stepSimulation()
time.sleep(dt)
print("simulation finished!")
# create GIF
if create_gif:
print("creating GIF")
from PIL import Image
imgs = [Image.fromarray(img.astype(np.uint8)) for img in images]
imgs[0].save("log.gif", save_all=True, append_images=imgs[1:], fps=fps, loop=0)