1
|
#open <conv>
|
2
|
const k_f_1 = -0.870303;
|
3
|
const k_f_2 = -31.9978;
|
4
|
const k_f_3 = -1.1566;
|
5
|
const k_f_4 = -2.78873;
|
6
|
|
7
|
const k_i = -0.44721; (* servo control integral gain *)
|
8
|
const k_phidot = 25.0; (* turn target speed gain *)
|
9
|
const k_thetadot = 7.5; (* forward target speed gain *)
|
10
|
|
11
|
const battery_gain = 0.001089;
|
12
|
const battery_offset = 0.625;
|
13
|
|
14
|
const cmd_max = 100.;
|
15
|
const deg2rad = 0.01745329238;
|
16
|
const exec_period = 0.00400000019;
|
17
|
|
18
|
const a_d = 0.8;
|
19
|
const a_r = 0.996;
|
20
|
|
21
|
|
22
|
|
23
|
node discrete_integrator(exec_period, in : real)
|
24
|
returns (out: real);
|
25
|
let
|
26
|
out = 0. -> pre (exec_period * in + out);
|
27
|
tel
|
28
|
|
29
|
node low_pass_filter(a, in: real)
|
30
|
returns (out : real);
|
31
|
let
|
32
|
out = (1.-a)*in -> (1.-a)*in + (pre out) * a;
|
33
|
tel
|
34
|
|
35
|
node sat(min, max, in : real)
|
36
|
returns (out: real);
|
37
|
let
|
38
|
out = if in <= min then min else (if in>= max then max else in);
|
39
|
tel
|
40
|
|
41
|
node cal_reference(cmd_forward, cmd_turn : real)
|
42
|
returns (pwm_turn, theta_ref, x_11_ref,x_12_ref,x_13_ref,x_14_ref : real);
|
43
|
var theta_dot_ref: real;
|
44
|
let
|
45
|
theta_dot_ref = low_pass_filter(a_r,k_thetadot*cmd_forward/cmd_max);
|
46
|
theta_ref=x_11_ref;
|
47
|
x_11_ref = discrete_integrator(exec_period,theta_dot_ref);
|
48
|
x_12_ref = 0.;
|
49
|
x_13_ref = theta_dot_ref;
|
50
|
x_14_ref = 0.;
|
51
|
pwm_turn = cmd_turn*k_phidot/cmd_max;
|
52
|
tel
|
53
|
|
54
|
node cal_x1 (gyro, gyro_offset, theta_m_l, theta_m_r:real)
|
55
|
returns(theta, x_11,x_12,x_13,x_14 : real);
|
56
|
var psidot, psi, theta_l, theta_r: real;
|
57
|
let
|
58
|
psidot = (gyro - gyro_offset)*deg2rad;
|
59
|
psi = discrete_integrator(exec_period,psidot);
|
60
|
theta_l= theta_m_l*deg2rad+ psi;
|
61
|
theta_r = theta_m_r*deg2rad + psi;
|
62
|
theta = (theta_l+theta_r)/2.;
|
63
|
x_11 = theta;
|
64
|
x_12 = psi;
|
65
|
x_13 = (low_pass_filter(a_d,theta) - (0. -> pre(low_pass_filter(a_d,theta))))/exec_period;
|
66
|
x_14 = psidot;
|
67
|
tel;
|
68
|
|
69
|
node cal_pwm(theta_m_l, theta_m_r, pwm_turn, err, battery : real)
|
70
|
returns(pwm_l, pwm_r, anti_windup : real);
|
71
|
var fwd, theta_diff : real;
|
72
|
let
|
73
|
fwd = cmd_max * (err/(battery*battery_gain-battery_offset));
|
74
|
pwm_l = sat(-100.,100.,fwd+pwm_turn);
|
75
|
theta_diff = theta_m_l - theta_m_r;
|
76
|
pwm_r = sat(-100.,100.,fwd-pwm_turn+12.0*theta_diff);
|
77
|
anti_windup= pwm_l - fwd+pwm_turn;
|
78
|
tel;
|
79
|
|
80
|
node lego_anti_windup (in1, in2, in3, in4, cntA, cntB, cntC, battery_voltage : int; gyro_offset : real)
|
81
|
returns (speedA, speedB, speedC : int);
|
82
|
var gyro, cmd_forward, cmd_turn, theta_m_l, theta_m_r, pwm_turn, theta_ref, x_11_ref, x_12_ref, x_13_ref, x_14_ref, theta, x_11, x_12, x_13, x_14, errtheta, err, pwm_l, pwm_r, anti_windup: real;
|
83
|
let
|
84
|
cmd_forward = if in2 <= 25 then -100. else 0.;
|
85
|
cmd_turn = 0.;
|
86
|
gyro = int_to_real(in3);
|
87
|
theta_m_l = int_to_real(cntC);
|
88
|
theta_m_r = int_to_real(cntB);
|
89
|
|
90
|
(pwm_turn, theta_ref, x_11_ref, x_12_ref, x_13_ref, x_14_ref) = cal_reference(cmd_forward, cmd_turn);
|
91
|
|
92
|
(theta, x_11, x_12, x_13, x_14) = cal_x1(gyro, gyro_offset, theta_m_l, theta_m_r);
|
93
|
|
94
|
errtheta = discrete_integrator(exec_period, (theta_ref-theta)*k_i + 0. -> pre(anti_windup*0.1));
|
95
|
|
96
|
err = errtheta + k_f_1*(x_11_ref-x_11) + k_f_2*(x_12_ref-x_12)+ k_f_3*(x_13_ref-x_13) +k_f_4*(x_14_ref-x_14);
|
97
|
|
98
|
(pwm_l,pwm_r, anti_windup) = cal_pwm(theta_m_l, theta_m_r, pwm_turn, err, int_to_real(battery_voltage));
|
99
|
|
100
|
speedA = 0;
|
101
|
speedB = real_to_int(pwm_r);
|
102
|
speedC = real_to_int(pwm_l);
|
103
|
tel
|
104
|
|
105
|
|
106
|
node lego_anti_windup_real (in1, in2, in3, in4, cntA, cntB, cntC, battery_voltage : real; gyro_offset : real)
|
107
|
returns (speedA, speedB, speedC : real);
|
108
|
var gyro, cmd_forward, cmd_turn, theta_m_l, theta_m_r, pwm_turn, theta_ref, x_11_ref, x_12_ref, x_13_ref, x_14_ref, theta, x_11, x_12, x_13, x_14, errtheta, err, pwm_l, pwm_r, anti_windup: real;
|
109
|
let
|
110
|
cmd_forward = if in2 <= 25. then -100. else 0.;
|
111
|
cmd_turn = 0.;
|
112
|
gyro = in3;
|
113
|
theta_m_l = cntC;
|
114
|
theta_m_r = cntB;
|
115
|
|
116
|
(pwm_turn, theta_ref, x_11_ref, x_12_ref, x_13_ref, x_14_ref) = cal_reference(cmd_forward, cmd_turn);
|
117
|
|
118
|
(theta, x_11, x_12, x_13, x_14) = cal_x1(gyro, gyro_offset, theta_m_l, theta_m_r);
|
119
|
|
120
|
errtheta = discrete_integrator(exec_period, (theta_ref-theta)*k_i + 0. -> pre(anti_windup*0.1));
|
121
|
|
122
|
err = errtheta + k_f_1*(x_11_ref-x_11) + k_f_2*(x_12_ref-x_12)+ k_f_3*(x_13_ref-x_13) +k_f_4*(x_14_ref-x_14);
|
123
|
|
124
|
(pwm_l,pwm_r, anti_windup) = cal_pwm(theta_m_l, theta_m_r, pwm_turn, err, battery_voltage);
|
125
|
|
126
|
speedA = 0.;
|
127
|
speedB = pwm_r;
|
128
|
speedC = pwm_l;
|
129
|
tel
|
130
|
|
131
|
|
132
|
|
133
|
(*
|
134
|
node automate(in1, in2, in3, in4, cntA, cntB, cntC, battery_voltage : int)
|
135
|
returns (speedA, speedB, speedC : int);
|
136
|
var
|
137
|
cnt : int; gyro_offset : real;
|
138
|
let
|
139
|
cnt = 1 -> pre(cnt) +1;
|
140
|
gyro_offset = int_to_real(in3) -> int_to_real(in3)/int_to_real(cnt) + (int_to_real(cnt-1)/int_to_real(cnt))*pre(gyro_offset);
|
141
|
(speedA, speedB, speedC) = if cnt <= 250 then (0, 0, 0) else top(in1, in2, in3, in4, cntA, cntB, cntC, battery_voltage, gyro_offset);
|
142
|
tel
|
143
|
*)
|