new_scipt.m 11 KB

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