-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSlithering_Snake_GJM.py
246 lines (205 loc) · 7.38 KB
/
Slithering_Snake_GJM.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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
'''
steps:
~set elements:n_elem,start,direction,normal,base_length,base_radius,density,youngs_modulus,shear_modulus
~Adding damping
~Adding force
~Adding callbacks
~system finalization
~run simulation
'''
import os
import numpy as np
import elastica as ea
from continuum_snake_postprocessing import (
plot_snake_velocity,
plot_video,
compute_projected_velocity,
plot_curvature,
)
class SnakeSimulator(
ea.BaseSystemCollection,ea.Constraints,ea.Forcing,ea.Damping,ea.CallBacks
):
pass
def run_snake(
b_coeff, PLOT_FIGURE=False, SAVE_FIGURE=False, SAVE_VIDEO=False, SAVE_RESULTS=False
):
snake_sim = SnakeSimulator()
#Elements
period = 3 #应该指的是蛇肌肉活动的周期?????
final_time = (11.0+0.01) * period #final_time = 5.0 * period
n_elem = 50
start = np.zeros((3,))
direction = np.array([0.0, 0.0, 1.0])
normal = np.array([0.0, 1.0, 0.0])
base_length = 0.35
base_radius = base_length * 0.011
density = 1000
E = 1e6
poisson_ratio = 0.5
shear_modulus = E / (poisson_ratio + 1.0)
shearable_rod = ea.CosseratRod.straight_rod(
n_elem,
start,
direction,
normal,
base_length,
base_radius,
density,
youngs_modulus=E,
shear_modulus=shear_modulus,
)
snake_sim.append(shearable_rod)
#Adding damping 阻尼力
damping_constant = 2e-3
time_step = 1e-4
snake_sim.dampen(shearable_rod).using(
ea.AnalyticalLinearDamper,
damping_constant=damping_constant,
time_step=time_step,
)
#Adding force
#forces
gravitational_acc = -9.80665
snake_sim.add_forcing_to(shearable_rod).using(
ea.GravityForces, acc_gravity=np.array([0.0, gravitational_acc, 0.0])
)
# muscle torques
wave_length = b_coeff[-1]
snake_sim.add_forcing_to(shearable_rod).using(
ea.MuscleTorques,
base_length=base_length,
b_coeff=b_coeff[:-1],
period=period,
wave_number=2.0 * np.pi / (wave_length),
phase_shift=0.0,
rest_lengths=shearable_rod.rest_lengths,
ramp_up_time=period,
direction=normal,
with_spline=True,
)
# friction forces
origin_plane = np.array([0.0, -base_radius, 0.0])
normal_plane = normal
slip_velocity_tol = 1e-8
froude = 0.1
mu = base_length / (period * period * np.abs(gravitational_acc) * froude)#这是什么公式,为什么跟period有关,mu应该是摩擦系数
kinetic_mu_array = np.array(
[mu, 1.5 * mu, 2.0 * mu]#anisotropic
) # [forward, backward, sideways]
static_mu_array = np.zeros(kinetic_mu_array.shape)
snake_sim.add_forcing_to(shearable_rod).using(
ea.AnisotropicFrictionalPlane,
k=1.0,
nu=1e-6,
plane_origin=origin_plane,
plane_normal=normal_plane,
slip_velocity_tol=slip_velocity_tol,
static_mu_array=static_mu_array,
kinetic_mu_array=kinetic_mu_array,
)
#Elemets for Callbacks
total_steps = int(final_time / time_step)
rendering_fps = 60
step_skip = int(1.0 / (rendering_fps * time_step))
#call backs
class ContinuumSnakeCallBack(ea.CallBackBaseClass):
"""
Call back function for continuum snake
"""
def __init__(self, step_skip: int, callback_params: dict):
ea.CallBackBaseClass.__init__(self)
self.every = step_skip
self.callback_params = callback_params
def make_callback(self, system, time, current_step: int):
if current_step % self.every == 0:
self.callback_params["time"].append(time)
self.callback_params["step"].append(current_step)
self.callback_params["position"].append(
system.position_collection.copy()
)
self.callback_params["velocity"].append(
system.velocity_collection.copy()
)
self.callback_params["avg_velocity"].append(
system.compute_velocity_center_of_mass()
)
self.callback_params["center_of_mass"].append(
system.compute_position_center_of_mass()
)
self.callback_params["curvature"].append(system.kappa.copy())
return
pp_list = ea.defaultdict(list)
snake_sim.collect_diagnostics(shearable_rod).using(
ContinuumSnakeCallBack, step_skip=step_skip, callback_params=pp_list
)
snake_sim.finalize()
timestepper = ea.PositionVerlet()
ea.integrate(timestepper, snake_sim, final_time, total_steps)
if PLOT_FIGURE:
filename_plot = "continuum_snake_velocity.png"
plot_snake_velocity(pp_list, period, filename_plot, SAVE_FIGURE)
plot_curvature(pp_list, shearable_rod.rest_lengths, period, SAVE_FIGURE)
if SAVE_VIDEO:
filename_video = "continuum_snake.mp4"
plot_video(
pp_list,
video_name=filename_video,
fps=rendering_fps,
xlim=(0, 4),
ylim=(-1, 1),
)
if SAVE_RESULTS:
import pickle
filename = "continuum_snake.dat"
file = open(filename, "wb")
pickle.dump(pp_list, file)
file.close()
# Compute the average forward velocity. These will be used for optimization.
[_, _, avg_forward, avg_lateral] = compute_projected_velocity(pp_list, period)
return avg_forward, avg_lateral, pp_list
if __name__ == "__main__":
# Options
PLOT_FIGURE = True
SAVE_FIGURE = True
SAVE_VIDEO = True
SAVE_RESULTS = False
CMA_OPTION = False
if CMA_OPTION:
import cma
SAVE_OPTIMIZED_COEFFICIENTS = False
def optimize_snake(spline_coefficient):
[avg_forward, _, _] = run_snake(
spline_coefficient,
PLOT_FIGURE=False,
SAVE_FIGURE=False,
SAVE_VIDEO=False,
SAVE_RESULTS=False,
)
return -avg_forward
# Optimize snake for forward velocity. In cma.fmin first input is function
# to be optimized, second input is initial guess for coefficients you are optimizing
# for and third input is standard deviation you initially set.
optimized_spline_coefficients = cma.fmin(optimize_snake, 7 * [0], 0.5)
# Save the optimized coefficients to a file
filename_data = "optimized_coefficients.txt"
if SAVE_OPTIMIZED_COEFFICIENTS:
assert filename_data != "", "provide a file name for coefficients"
np.savetxt(filename_data, optimized_spline_coefficients, delimiter=",")
else:
# Add muscle forces on the rod
if os.path.exists("optimized_coefficients.txt"):
t_coeff_optimized = np.genfromtxt(
"optimized_coefficients.txt", delimiter=","
)
else:
wave_length = 1.0
t_coeff_optimized = np.array(
[3.4e-3, 3.3e-3, 4.2e-3, 2.6e-3, 3.6e-3, 3.5e-3]
)
t_coeff_optimized = np.hstack((t_coeff_optimized, wave_length))
# run the simulation
[avg_forward, avg_lateral, pp_list] = run_snake(
t_coeff_optimized, PLOT_FIGURE, SAVE_FIGURE, SAVE_VIDEO, SAVE_RESULTS
)
print("average forward velocity:", avg_forward)
print("average forward lateral:", avg_lateral)