Master Thesis Code
by Simon Moser
Loading...
Searching...
No Matches
animateQuat.m
Go to the documentation of this file.
1% =========================================================================== %
2%> @brief animates a quaternion vector
3%>
4%> animateQuat(quat) animates the orientation data quat. The animation is
5%> done in a new figure window with a poseplot. The data must be provided
6%> either as a Nx4 numeric vector or as Nx1 quaternion vector.
7%>
8%> animateQuat(quat, options) allows to specify additional options for the
9%> animation.
10%>
11%> animateQuat(quat1, quat2, ..., quatN) animates multiple orientation data
12%> sets in the same figure window.
13%>
14%> @param quat - Nx4 numeric vector or Nx1 quaternion vector
15%> @param options (optional) - struct with optional input arguments
16%> - names - cell array with names for the orientation data (default: 1:N)
17%> - freq - Sampling frequency of the data [Hz] (default: 200)
18%> - fps - Desired Frames per second [Hz] (default: 30)
19%> - speedup - Speedup factor of the animation (default: 1)
20%> - title - Title of the figure (default: "Orientation Animation")
21%> - position - Position of the figure window (default: [0,0,0.5,0.5])
22%>
23%> @retval none
24%>
25%> @file animateQuat.m
26%>
27%> @copyright see the file @ref LICENSE in the root directory of the repository
28% =========================================================================== %
29
30function animateQuat(quat, options)
31
32%% argument checking
33arguments (Repeating)
34 quat (:,:) {mustBeNonmissing}
35end
36
37arguments
38 options.names (:,1) string = string.empty(1,0)
39 options.freq (1,1) double = 200;
40 options.fps (1,1) double = 30;
41 options.speedup (1,1) double = 1;
42 options.title (1,1) string = "Orientation Animation"
43 options.position = [0,0,0.5,0.5]
44end
45N_quat = numel(quat);
46N_samples = 0;
47
48% check if quaternion vector is provided
49% define max sample size
50for i=1:N_quat
51 if ~isa(quat{i}, 'quaternion')
52 if size(quat{i}, 2) ~= 4
53 error('Quaternion vector must be Nx4');
54 else
55 quat{i} = quaternion(quat{i});
56 end
57 end
58
59 % max sample size
60 N_samples = max(N_samples, numel(quat{i}));
61end
62
63% check if names are provided
64if isempty(options.names) || numel(options.names) ~= N_quat
65 options.names = string(1:N_quat);
66end
67
68%% set up parameters
69% smoothed fps
70smoothed_fps = options.fps;
71
72% set up timer
73t = timer('ExecutionMode', 'fixedRate', 'Period', round(1/options.fps,3), 'TimerFcn', @timer_callback);
74t.UserData = 1;
75
76%% create figure
77fig = figure('Name', options.title, 'NumberTitle', 'off', 'MenuBar', 'none', 'ToolBar', 'figure', 'Units','normalized',"Position",options.position);
78for i=1:N_quat
79 subplot(1,N_quat,i);
80 pp(i) = poseplot();
81 title(options.names(i));
82end
83
84% add a close request function to the figure
85fig.CloseRequestFcn = @my_closereq;
86
87% add a time passed indicator to the bottom left of the figure
88text_passed = uicontrol('Style', 'text', 'String', sprintf('Time passed: %.2f s', 0), 'Units', 'normalized', 'Position', [0.01 0.01 0.3 0.05], 'FontSize', 12, 'FontWeight', 'bold');
89
90% add a fps indicator to the bottom right of the figure
91text_fps = uicontrol('Style', 'text', 'String', sprintf('FPS: %d', options.fps), 'Units', 'normalized', 'Position', [0.69 0.01 0.3 0.05], 'FontSize', 12, 'FontWeight', 'bold');
92
93% add a line to the top of the figure that indicates the current time
94line_curr_time = annotation('line', [0 0], [1,1], 'Units', 'normalized', 'LineWidth', 5, 'Color', 'r');
95
96% set up animation
97start(t);
98
99%% functions
100% timer callback function
101 function timer_callback(~, ~)
102 if t.UserData > N_samples
103 stop(t);
104 else
105 % update poseplot
106 for i=1:N_quat
107 if t.UserData < numel(quat{i})
108 pp(i).Orientation = quat{i}(t.UserData);
109 else
110 pp(i).PatchFaceColor = 'r';
111 end
112 end
113
114 % update time passed indicator
115 text_passed.String = sprintf('Time passed: %.2f s', t.UserData/options.freq);
116
117 % update frequency indicator
118 curr_fps = 1/(t.InstantPeriod);
119 if isnan(curr_fps)
120 curr_fps = options.fps;
121 end
122
123 % Smooth the FPS value using an IIR filter
124 alpha = 0.05; % Smoothing factor
125 smoothed_fps = alpha * round(curr_fps) + (1 - alpha) * smoothed_fps;
126 text_fps.String = sprintf('FPS: %d', round(smoothed_fps));
127
128 % calculate steps to skip to keep up with the desired frequency
129 skip = round(options.speedup * options.freq/curr_fps);
130
131 % update current time indicator
132 line_curr_time.X = [0, t.UserData/N_samples];
133
134 % update counter
135 t.UserData = t.UserData + skip;
136 end
137 end
138
139% close request function
140 function my_closereq(~,~)
141 stop(t);
142 delete(t);
143 delete(fig);
144 end
145
146end
function animateQuat(in quat, in options)
function timer_callback(in ignoredArg, in ignoredArg)
function my_closereq(in ignoredArg, in ignoredArg)