new_scipt.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. clear ;%清除工作区的缓存变量
  2. close all; % 关闭当前的所有窗口
  3. clc; %清除命令行的数据
  4. g = 9.7833;
  5. %尝试读取csv文件
  6. data_file = csvread('LoggedData3.csv',1 ,0);
  7. %把陀螺仪数据,加速度数据拿出来
  8. gyr_data = data_file(:, 6:8) *pi/180;
  9. acc_data = data_file(:, 3:5) * g;
  10. time_stamp = data_file(:, 4) * 0.001;
  11. board_pos = data_file(:, 12:14)';
  12. %参数设置
  13. data_size = size(gyr_data,1);
  14. dt = 1/100;
  15. %当地重力加速度
  16. %设置过程噪声
  17. % 状态量为【姿态误差,速度误差,位置误差】
  18. % 相应的过程噪声协方差
  19. sigma_omega = 1e-2; sigma_a = 1e-2;
  20. % 观测噪声协方差,只观测速度误差
  21. sigma_v = 1e-2;
  22. R = diag([sigma_v sigma_v sigma_v*0.1]).^2;
  23. R_xy = diag([sigma_v sigma_v sigma_v sigma_v sigma_v sigma_v]).^2;
  24. %初始化姿态矩阵
  25. %先根据加速度计算俯仰角,翻滚角,航向角
  26. pitch = asin(-acc_data(1,1)/g);
  27. roll = atan2(acc_data(1,2), acc_data(1,3));
  28. yaw = 0;
  29. C_prev = [cos(yaw)*cos(pitch), -sin(yaw)*cos(roll)+cos(yaw)*sin(pitch)*sin(roll), sin(yaw)*sin(roll)+ cos(yaw)*sin(pitch)*cos(roll);
  30. sin(yaw)*cos(pitch), cos(yaw)*cos(roll)+sin(yaw)*sin(pitch)*sin(roll), -cos(yaw)*sin(roll)+sin(yaw)*sin(pitch)* cos(roll);
  31. -sin(pitch), cos(pitch)* sin(roll), cos(pitch)*cos(roll);];
  32. C = C_prev;
  33. acc_n = zeros(3, data_size);
  34. acc_n(:,1) = C*acc_data(1,:)'-[0,0,g]';
  35. vel_n = zeros(3, data_size);
  36. vel_n_norm = zeros(1,data_size);
  37. pos_n = zeros(3, data_size);
  38. P = zeros(9,9);
  39. H = [zeros(3,3), zeros(3,3), eye(3);
  40. ];
  41. H_xy= [zeros(3,3), zeros(3,3), eye(3);
  42. zeros(3,3),eye(3),zeros(3,3);
  43. ];
  44. gyr_norm = nan(1,data_size);
  45. acc_norm = nan(1,data_size);
  46. zupt = zeros(1,data_size);
  47. pitch_data = nan(1,data_size);
  48. roll_data = nan(1, data_size);
  49. yaw_data = nan(1, data_size);
  50. C_buff = zeros(3,3,data_size);
  51. C_buff(:,:,1) = C;
  52. last_zupt = 0;
  53. mini_update = 0;
  54. step_pos = zeros(3,1);
  55. has_zupt = 0;
  56. zupt_pos.x = 0;
  57. zupt_pos.y = 0;
  58. zupt_pos.z = 0;
  59. zupt_pos.yaw = 0;
  60. last_step_xy = [0;0];
  61. last_step_xy_tmp = [0;0];
  62. pos_result = zeros(3,data_size);
  63. last_pos = [0,0,0]';
  64. last_zupt_index = 30;
  65. %以下为记录输出所用
  66. last_record = 0;
  67. output_signal = 0;
  68. output_return = 0;
  69. stand_num = 0;
  70. vel_local = zeros(2, data_size);
  71. last_running = 1;
  72. gyr_norm_flag = 10000;
  73. output_time = [];
  74. output_index = 1;
  75. running_status = 0;
  76. for i = 2 : data_size
  77. %姿态矩阵更新, 其实有没有陀螺仪零片都没多大问题
  78. % w= gyrData - gyrBias
  79. w = gyr_data(i,:)';
  80. %陀螺仪K时刻求模,分析数据时候用
  81. gyr_norm(i) = norm(w);
  82. %当前时刻陀螺仪生成的叉乘矩阵,姿态矩阵迭代需要
  83. temp = [0, -w(3), w(2);
  84. w(3), 0, -w(1);
  85. -w(2), w(1), 0;]* dt;
  86. % 姿态矩阵迭代的经典公示了,也可以用其他的迭代公式
  87. C= C_prev * (2*eye(3)+temp)/(2*eye(3) - temp);
  88. %速度位置初步更新
  89. acc = acc_data(i,:)';
  90. %加速度计,分析数据时候用
  91. acc_norm(i) = norm(acc);
  92. %acc_n为当地的坐标系下的加速度表示,并减去了自身的重力加速度计
  93. acc_n(:,i) = C * acc;
  94. %导航坐标系下的速度向量迭代公式
  95. vel_n(:,i) = vel_n(:, i-1) + (acc_n(:,i)- [0,0,g]')*dt;
  96. %导航坐标系下的位置更新公式
  97. pos_n(:,i) = pos_n(:,i-1) + vel_n(:,i) *dt ;
  98. %状态转移矩阵
  99. S = [0, -acc_n(3,i), acc_n(2,i);
  100. acc_n(3,i), 0, -acc_n(1,i);
  101. -acc_n(2,i), acc_n(1,i), 0;];
  102. %状态向量的顺序为[delta_pitch, delta_roll, delta_yaw,
  103. % delta_px, delta_py, delta_pz,]
  104. % delta_vx, delta_vy, delta_vz,]
  105. % xk = F*x(k-1);
  106. % 式子的意义 第一行代表 姿态角的误差预测没有改变
  107. % 第二行代表 当前的位置误差 = 上一个时刻位置误差 + 上一个时刻速度误差*时间
  108. % 第三行代表 当前的速度误差 = 上一个时刻速度误差 - 加速度X姿态角误差*时间
  109. % 简单来说是由于姿态误差引起的加速度测量误差,再乘以时间,就得到额外的速度误差
  110. F = [eye(3), zeros(3,3), zeros(3,3);
  111. zeros(3,3), eye(3), dt*eye(3);
  112. -dt*S, zeros(3,3), eye(3)];
  113. %过程噪声的协方差矩阵
  114. Q = diag([sigma_omega sigma_omega sigma_omega sigma_a sigma_a sigma_a sigma_a sigma_a sigma_a]*dt).^2;
  115. %卡尔曼里面的协方差矩阵迭代公式了
  116. P = F*P*F' + Q;
  117. % 这里说明一下, if(norm(w)< 1.0) 是来判断IMU触碰到地上用的
  118. % 一般走路 用不着达到1.0,0.35就可以了,但是剧烈运动是达到1.0的
  119. % 用固定阈值来判断不是恰当的,可以根据前面一段(t-k:k) 陀螺仪数据是预测
  120. % 或者根据一步间的IMU数据来衡量跑步还是普通走路
  121. % 这里为了方便测试,用固定值1.0来算好了
  122. if(i > 9)
  123. max_window = max(gyr_norm(i-5:i));
  124. min_window = min(gyr_norm(i-5:i));
  125. end
  126. output_return = 0;
  127. yaw_data(i) = atan2(C(2,1),C(1,1));
  128. pitch_data(i) = asin(-C(3,1));
  129. roll_data(i) = atan2(C(3,2),C(3,3));
  130. pos_result(:,i) = pos_n(:,i) - last_pos;
  131. if(i - last_zupt_index > 5 && gyr_norm(i) - max(gyr_norm(i-5:i-1)) < - 5.0)
  132. running_status = 1;
  133. end
  134. if(gyr_norm(i) - gyr_norm(i-1) > 2.0)
  135. running_status = 0;
  136. end
  137. if( (((gyr_norm(i)< 0.6) && (i > 15) && ((max_window - gyr_norm(i)) < 0.6))...
  138. || ((gyr_norm(i)< 2.0) && (i > 15) &&(i- last_zupt_index > 25) && (max_window - min_window) > 6.0 - 0.04 * (i- last_zupt_index-25) ) )...
  139. )
  140. if(last_zupt == 1)
  141. stand_num = stand_num + 1;
  142. output_signal = 1;
  143. %用来记录零速的时刻, 可以忽略
  144. zupt(i) = 0.7;
  145. %计算卡尔曼滤波增益,公式公式
  146. % 说明一下H矩阵为观测矩阵,在线性系统下就是值1.观测量需要用到哪一个就在zeros(1,9)中对应的位置为1
  147. K = P*H'/(H*P*H' + R);
  148. delta_x = K * [vel_n(:,i)];
  149. P = P - K*H*P;
  150. %姿态矩阵补偿
  151. C_fix = [0, -delta_x(3), delta_x(2);
  152. delta_x(3), 0, -delta_x(1);
  153. -delta_x(2), delta_x(1), 0];
  154. %姿态矩阵补偿
  155. C = ((2*eye(3)-C_fix)/(2*eye(3) + C_fix))* C;
  156. %位置补偿
  157. pos_n(:,i) = pos_n(:,i) - delta_x(4:6);
  158. vel_n(:,i) = vel_n(:,i) - delta_x(7:9);
  159. %防止脚地上的时候,Z方向的速度过快
  160. yaw = 0.0;
  161. pitch = asin(-C(3,1));
  162. roll = roll_data(i);
  163. C = [cos(pitch),sin(pitch)*sin(roll), sin(pitch)*cos(roll);
  164. 0.0, cos(roll), -1*sin(roll);
  165. -sin(pitch), cos(pitch)* sin(roll), cos(pitch)*cos(roll);];
  166. last_pos = pos_n(:, i);
  167. %记录一步一步的位置移动
  168. end
  169. last_zupt = 1;
  170. last_running = i;
  171. else
  172. gyr_norm_flag = 10000;
  173. if(last_zupt == 1)
  174. last_zupt_index = i-1;
  175. last_zupt = 0;
  176. end
  177. if(output_signal == 1 && pos_result(3,i) < -0.01 )
  178. max_val = abs(pos_result(1,i));
  179. max_index = 1;
  180. for k = 2:3
  181. if(max_val < abs(pos_result(k, i)))
  182. max_index = k;
  183. end
  184. end
  185. if abs(pos_result(max_index,i)) < 0.3
  186. if i - last_running > 30
  187. disp(["MOVE_RUNNING"]);
  188. output_return = 7;
  189. last_running = i;
  190. end
  191. else
  192. if(max_index == 1)
  193. if(pos_result(max_index, i) < 0)
  194. disp(["MOVE_FORWARD"]);
  195. else
  196. disp(["MOVE_BACKWARD"]);
  197. end
  198. elseif max_index == 2
  199. if(pos_result(max_index, i) < 0)
  200. disp(["MOVE_LEFT"]);
  201. else
  202. disp(["MOVE_RIGTH"]);
  203. end
  204. else
  205. disp(["MOVE_JUMP"]);
  206. end
  207. output_signal = 0;
  208. output_time(output_index) = i;
  209. output_index = output_index + 1;
  210. end
  211. end
  212. end
  213. if(output_signal == 1 && stand_num > 100)
  214. output_signal = 0;
  215. output_return = 9;
  216. stand_num = 0;
  217. disp(["MOVE_stand"]);
  218. end
  219. %计算速度的均方值
  220. vel_n_norm(i) = norm(vel_n(:, i));
  221. %保持协方差矩阵的对称性
  222. P = (P+P')/2;
  223. C_prev = C;
  224. vel_local(:,i) = [cos(yaw_data(i)), -sin(yaw_data(i)) ;
  225. sin(yaw_data(i)), cos(yaw_data(i))]*vel_n(1:2, i);
  226. C_buff(:,:,i) = C;
  227. %输出
  228. end
  229. % 其实做这种游戏的姿态估计,能大概判断第K步相对于第K-1偏移多少就好(方向,x,y位置)
  230. % 例如判断左、右、前、后,移动的情况,可以根据
  231. % theta_yaw = yaw(k)-yaw(k-1);
  232. % R = sqrt((pos_n(1,k)- pos_n(1,k-1))^2 + (pos_n(2,k)- pos_n(2,k-1))^2 )
  233. % [x, y] =[cos(theta),sin(theta)]*R;就可以根据XY的符号判断左右前后了
  234. % 跳的动作根据v_z, p_z来判断,初步是可以的;
  235. figure('NumberTitle', 'off', 'Name', 'Offset pos');
  236. hold on;
  237. plot(pos_result(1,:), 'r');
  238. plot(pos_result(2,:), 'g');
  239. plot(pos_result(3,:), 'b');
  240. plot(output_time,pos_result(3,output_time),'k*');
  241. hold on;
  242. grid;
  243. xlabel('sample');
  244. ylabel('m');
  245. title('Offset pos');
  246. legend('X', 'Y', 'Z');
  247. figure('NumberTitle', 'off', 'Name', 'Linear Velocity');
  248. hold on;
  249. plot(vel_n(1,:), 'r');
  250. plot(vel_n(2,:), 'g');
  251. plot(vel_n(3,:), 'b');
  252. plot(output_time,vel_n(3,output_time),'k*');
  253. grid;
  254. xlabel('sample');
  255. ylabel('m/s');
  256. title('local velocity');
  257. legend('X', 'Y', 'Z');
  258. figure('NumberTitle', 'off', 'Name', 'Linear Position');
  259. hold on;
  260. plot(pos_n(1,:), 'r');
  261. plot(pos_n(2,:), 'g');
  262. plot(pos_n(3,:), 'b');
  263. grid;
  264. xlabel('sample');
  265. ylabel('m');
  266. title('local position');
  267. legend('X', 'Y', 'Z');
  268. % figure
  269. % plot3(pos_n(1,:), pos_n(2,:), pos_n(3,:));
  270. %
  271. % pose_diff = step_pos(1:2, 2:end) - step_pos(1:2, 1:end-1);
  272. % figure
  273. % plot( step_pos(2,:))
  274. %
  275. figure('Name', 'IMU zupt')
  276. plot(gyr_norm(1,:),'r')
  277. hold on
  278. plot((acc_norm(1,:)-9.8)/5,'g');
  279. index = find(zupt > 0);
  280. plot(index,gyr_norm(index),'ko')
  281. grid on
  282. figure
  283. plot3(pos_n(1,:), pos_n(2,:), pos_n(3, :),'r');grid on
  284. figure('NumberTitle', 'off', 'Name', 'IMU vel');
  285. hold on;
  286. plot(vel_local(1,:), 'r');
  287. plot(vel_local(2,:), 'g');
  288. figure;
  289. hold on;
  290. plot(pitch_data, 'r')
  291. plot(roll_data, 'b')
  292. plot(output_time, roll_data(output_time), 'k*')
  293. %% Animation
  294. %% The animation code was stolen from xioTechnologies.
  295. %% https://github.com/xioTechnologies/Gait-Tracking-With-x-IMU
  296. % L = data_size;
  297. % SamplePlotFreq = 4;
  298. % Spin = 120;
  299. % SixDofAnimation(pos_result(1:3,:)', C_buff, ...
  300. % 'SamplePlotFreq', SamplePlotFreq, 'Trail', 'All',...
  301. % 'Position', [9 39 1280 768],...
  302. % 'View', [(100:(Spin/(L-1)):(100+Spin))', 10*ones(L, 1)],...
  303. % 'AxisLength', 0.1, 'ShowArrowHead', false, ...
  304. % 'Xlabel', 'X (m)', 'Ylabel', 'Y (m)', 'Zlabel', 'Z (m)',...
  305. % 'ShowLegend', false,...
  306. % 'CreateVideo', false);