├── .gitattributes
├── .gitignore
├── MotionControl.pro
├── MotionControl.pro.user
├── MotionControler.cpp
├── MotionControler.h
├── README.TXT
└── main.cpp
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
--------------------------------------------------------------------------------
/MotionControl.pro:
--------------------------------------------------------------------------------
1 | QT += core
2 | QT -= gui
3 |
4 | TARGET = MotionControl
5 | CONFIG += console
6 | CONFIG -= app_bundle
7 |
8 | TEMPLATE = app
9 |
10 | SOURCES += main.cpp \
11 | MotionControler.cpp
12 |
13 | HEADERS += \
14 | MotionControler.h
15 |
16 |
--------------------------------------------------------------------------------
/MotionControl.pro.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EnvironmentId
7 | {65d20304-a93b-4827-8c76-30e535fa41cb}
8 |
9 |
10 | ProjectExplorer.Project.ActiveTarget
11 | 1
12 |
13 |
14 | ProjectExplorer.Project.EditorSettings
15 |
16 | true
17 | false
18 | true
19 |
20 | Cpp
21 |
22 | CppGlobal
23 |
24 |
25 |
26 | QmlJS
27 |
28 | QmlJSGlobal
29 |
30 |
31 | 2
32 | UTF-8
33 | false
34 | 4
35 | false
36 | 80
37 | true
38 | true
39 | 1
40 | true
41 | false
42 | 0
43 | true
44 | 0
45 | 8
46 | true
47 | 0
48 | true
49 | true
50 | true
51 | false
52 |
53 |
54 |
55 | ProjectExplorer.Project.PluginSettings
56 |
57 |
58 |
59 | ProjectExplorer.Project.Target.0
60 |
61 | Desktop Qt 5.5.0 MSVC2013 64bit
62 | Desktop Qt 5.5.0 MSVC2013 64bit
63 | qt.55.win64_msvc2013_64_kit
64 | 1
65 | 0
66 | 0
67 |
68 | F:/work/B_Spline/Qt_project/build-MotionControl-Desktop_Qt_5_5_0_MSVC2013_64bit-Debug
69 |
70 |
71 | true
72 | qmake
73 |
74 | QtProjectManager.QMakeBuildStep
75 | false
76 | true
77 |
78 | false
79 | false
80 | false
81 |
82 |
83 | true
84 | Make
85 |
86 | Qt4ProjectManager.MakeStep
87 |
88 | false
89 | -j8 install
90 |
91 |
92 | 2
93 | 构建
94 |
95 | ProjectExplorer.BuildSteps.Build
96 |
97 |
98 |
99 | true
100 | Make
101 |
102 | Qt4ProjectManager.MakeStep
103 |
104 | true
105 | clean
106 |
107 |
108 | 1
109 | 清理
110 |
111 | ProjectExplorer.BuildSteps.Clean
112 |
113 | 2
114 | false
115 |
116 | Debug
117 |
118 | Qt4ProjectManager.Qt4BuildConfiguration
119 | 2
120 | true
121 |
122 |
123 | F:/work/B_Spline/Qt_project/build-MotionControl-Desktop_Qt_5_5_0_MSVC2013_64bit-Release
124 |
125 |
126 | true
127 | qmake
128 |
129 | QtProjectManager.QMakeBuildStep
130 | false
131 | true
132 |
133 | false
134 | false
135 | false
136 |
137 |
138 | true
139 | Make
140 |
141 | Qt4ProjectManager.MakeStep
142 |
143 | false
144 |
145 |
146 |
147 | 2
148 | 构建
149 |
150 | ProjectExplorer.BuildSteps.Build
151 |
152 |
153 |
154 | true
155 | Make
156 |
157 | Qt4ProjectManager.MakeStep
158 |
159 | true
160 | clean
161 |
162 |
163 | 1
164 | 清理
165 |
166 | ProjectExplorer.BuildSteps.Clean
167 |
168 | 2
169 | false
170 |
171 | Release
172 |
173 | Qt4ProjectManager.Qt4BuildConfiguration
174 | 0
175 | true
176 |
177 | 2
178 |
179 |
180 | 0
181 | 部署
182 |
183 | ProjectExplorer.BuildSteps.Deploy
184 |
185 | 1
186 | 在本地部署
187 |
188 | ProjectExplorer.DefaultDeployConfiguration
189 |
190 | 1
191 |
192 |
193 |
194 | false
195 | false
196 | false
197 | false
198 | true
199 | 0.01
200 | 10
201 | true
202 | 1
203 | 25
204 |
205 | 1
206 | true
207 | false
208 | true
209 | valgrind
210 |
211 | 0
212 | 1
213 | 2
214 | 3
215 | 4
216 | 5
217 | 6
218 | 7
219 | 8
220 | 9
221 | 10
222 | 11
223 | 12
224 | 13
225 | 14
226 |
227 | 2
228 |
229 | MotionControl
230 |
231 | Qt4ProjectManager.Qt4RunConfiguration:F:/work/B_Spline/Qt_project/MotionControl/MotionControl.pro
232 |
233 | MotionControl.pro
234 | false
235 | true
236 |
237 | 3768
238 | false
239 | true
240 | false
241 | false
242 | true
243 |
244 | 1
245 |
246 |
247 |
248 | ProjectExplorer.Project.Target.1
249 |
250 | Desktop Qt 5.5.0 MinGW 32bit
251 | Desktop Qt 5.5.0 MinGW 32bit
252 | qt.55.win32_mingw492_kit
253 | 0
254 | 0
255 | 0
256 |
257 | F:/work/B_Spline/Qt_project/build-MotionControl-Desktop_Qt_5_5_0_MinGW_32bit-Debug
258 |
259 |
260 | true
261 | qmake
262 |
263 | QtProjectManager.QMakeBuildStep
264 | false
265 | true
266 |
267 | false
268 | false
269 | false
270 |
271 |
272 | true
273 | Make
274 |
275 | Qt4ProjectManager.MakeStep
276 |
277 | false
278 |
279 |
280 |
281 | 2
282 | 构建
283 |
284 | ProjectExplorer.BuildSteps.Build
285 |
286 |
287 |
288 | true
289 | Make
290 |
291 | Qt4ProjectManager.MakeStep
292 |
293 | true
294 | clean
295 |
296 |
297 | 1
298 | 清理
299 |
300 | ProjectExplorer.BuildSteps.Clean
301 |
302 | 2
303 | false
304 |
305 | Debug
306 |
307 | Qt4ProjectManager.Qt4BuildConfiguration
308 | 2
309 | true
310 |
311 |
312 | F:/work/B_Spline/Qt_project/build-MotionControl-Desktop_Qt_5_5_0_MinGW_32bit-Release
313 |
314 |
315 | true
316 | qmake
317 |
318 | QtProjectManager.QMakeBuildStep
319 | false
320 | true
321 |
322 | false
323 | false
324 | false
325 |
326 |
327 | true
328 | Make
329 |
330 | Qt4ProjectManager.MakeStep
331 |
332 | false
333 |
334 |
335 |
336 | 2
337 | 构建
338 |
339 | ProjectExplorer.BuildSteps.Build
340 |
341 |
342 |
343 | true
344 | Make
345 |
346 | Qt4ProjectManager.MakeStep
347 |
348 | true
349 | clean
350 |
351 |
352 | 1
353 | 清理
354 |
355 | ProjectExplorer.BuildSteps.Clean
356 |
357 | 2
358 | false
359 |
360 | Release
361 |
362 | Qt4ProjectManager.Qt4BuildConfiguration
363 | 0
364 | true
365 |
366 | 2
367 |
368 |
369 | 0
370 | 部署
371 |
372 | ProjectExplorer.BuildSteps.Deploy
373 |
374 | 1
375 | 在本地部署
376 |
377 | ProjectExplorer.DefaultDeployConfiguration
378 |
379 | 1
380 |
381 |
382 |
383 | false
384 | false
385 | false
386 | false
387 | true
388 | 0.01
389 | 10
390 | true
391 | 1
392 | 25
393 |
394 | 1
395 | true
396 | false
397 | true
398 | valgrind
399 |
400 | 0
401 | 1
402 | 2
403 | 3
404 | 4
405 | 5
406 | 6
407 | 7
408 | 8
409 | 9
410 | 10
411 | 11
412 | 12
413 | 13
414 | 14
415 |
416 | 2
417 |
418 | MotionControl
419 |
420 | Qt4ProjectManager.Qt4RunConfiguration:F:/work/B_Spline/Qt_project/MotionControl/MotionControl.pro
421 |
422 | MotionControl.pro
423 | false
424 | true
425 |
426 | 3768
427 | false
428 | true
429 | false
430 | false
431 | true
432 |
433 | 1
434 |
435 |
436 |
437 | ProjectExplorer.Project.TargetCount
438 | 2
439 |
440 |
441 | ProjectExplorer.Project.Updater.FileVersion
442 | 18
443 |
444 |
445 | Version
446 | 18
447 |
448 |
449 |
--------------------------------------------------------------------------------
/MotionControler.cpp:
--------------------------------------------------------------------------------
1 | #include "MotionControler.h"
2 | #include
3 | #include
4 | #include
5 |
6 | MotionControler::MotionControler()
7 | {
8 | /* 初始状态参数配置 */
9 | axisNum = 1;
10 | currentPos = QVector(axisNum + 1, 0);
11 | currentVelocity = QVector(axisNum + 1, 0);
12 | currentAcceloration = QVector(axisNum + 1, 0);
13 | currentVelocityTCP = 0;
14 | currentAccelorationTCP = 0;
15 |
16 | endPos = QVector(axisNum + 1, 0);
17 | endVelocity = QVector(axisNum + 1, 0);
18 | endVelocityTCP = 0;
19 |
20 | remainPos = QVector(axisNum + 1, 0);
21 | remainPosTCP = 0;
22 | T = 1e-3;
23 |
24 | multiper = QVector(axisNum + 1, 1);
25 | origin = QVector(axisNum + 1, 0);
26 | error = 0.01;
27 | status = free;
28 |
29 | velocityLimitTCP = 0;
30 | accelorationLimitTCP = 0;
31 |
32 | interpolationCounter = 0;
33 | timer = new QTimer();
34 | // connect(timer, SIGNAL(timeout()), this, SLOT(SendCurrentPos()));
35 | // timer->start(1);
36 | }
37 | /*!
38 | * \brief MotionControler::TPlan 指定期望时间的T形速度规划,相对运动方式
39 | * \return 插补距离
40 | */
41 | QVector MotionControler::TPlanBaseTime(qreal time)
42 | {
43 | int numOfInterpolation = (int) (time / T); /* 插补点个数为总时间除以插补周期 */
44 | QVector pos(numOfInterpolation); /* 定义数组长度为numOfInterpolation */
45 | bool succeed = false; /* 规划成功标志 */
46 | int j = 0;
47 | float delta; /* 解一元二次方程中的解的判据 */
48 | float V1; /* 匀速段的速度 */
49 | float V[2];
50 | float t1; /* 匀速段开始时间 */
51 | float t2; /* 匀速段结束时间 */
52 | while (j <= 4){
53 | j++;
54 | /*情况1:加速度-匀速-减速 先假设后验证*/
55 | delta = 4 * (accelorationLimitTCP * time + currentVelocityTCP + endVelocityTCP)
56 | * (accelorationLimitTCP * time + currentVelocityTCP + endVelocityTCP)
57 | - 8 * (currentVelocityTCP * currentVelocityTCP + endVelocityTCP * endVelocityTCP + 2 * accelorationLimitTCP * remainPosTCP);
58 | if (delta < 0 ){
59 | succeed = false;
60 | }else if (delta == 0){
61 | V1 = (accelorationLimitTCP * time + currentVelocityTCP + endVelocityTCP) / 2;
62 | if (~(V1 >= currentVelocityTCP && V1 >= endVelocityTCP
63 | && qAbs(V1) <= velocityLimitTCP
64 | && (time - (V1 - currentVelocityTCP) / accelorationLimitTCP - (endVelocityTCP - V1) / (-accelorationLimitTCP)) >= 0))
65 | {
66 | succeed = true; //有解
67 | }
68 | }else {
69 | V[0] = (2 * (accelorationLimitTCP * time + currentVelocityTCP + endVelocityTCP) + qSqrt(delta)) / 4;
70 | V[1] = (2 * (accelorationLimitTCP * time + currentVelocityTCP + endVelocityTCP) - qSqrt(delta)) / 4;
71 | if (V[0] >= currentVelocityTCP && V[0] >= endVelocityTCP
72 | && qAbs(V[0]) <= velocityLimitTCP
73 | && (time - (V[0] - currentVelocityTCP) / accelorationLimitTCP - (endVelocityTCP - V[0]) / (-accelorationLimitTCP)) >= 0)
74 | {
75 | V1 = V[0];
76 | succeed = true; //有解
77 | }else if (V[1] >= currentVelocityTCP && V[1] >= endVelocityTCP
78 | && qAbs(V[1]) <= velocityLimitTCP
79 | && (time - (V[1] - currentVelocityTCP) / accelorationLimitTCP - (endVelocityTCP - V[1]) / (-accelorationLimitTCP)) >= 0)
80 | {
81 | V1 = V[1];
82 | succeed = true;
83 | }else{
84 | succeed = false;
85 | }
86 | }
87 | if (succeed){
88 | t1 = (V1 - currentVelocityTCP) / accelorationLimitTCP;
89 | t2 = time - (endVelocityTCP - V1) / (-accelorationLimitTCP);
90 | float t = 0;
91 | for (int i = 0; i < numOfInterpolation; i++){
92 | t += T;
93 | if (t <= t1){
94 | pos[i] = currentVelocityTCP * t + 0.5 * accelorationLimitTCP * t * t;
95 | }else if (t > t1 && t <= t2){
96 | pos[i] = (0 + currentVelocityTCP * t1 + 0.5 * accelorationLimitTCP * t1 * t1)
97 | + V1 * (t - t1);
98 | }else{
99 | pos[i] = (0 + currentVelocityTCP * t1 + 0.5 * accelorationLimitTCP * t1 * t1)
100 | + V1 * (t2 - t1)
101 | + V1 * (t - t2)
102 | - 0.5 * accelorationLimitTCP * (t- t2) * (t - t2);
103 | }
104 | }
105 | break;
106 | }
107 |
108 | /*情况2:加速-匀速-加速 先假设后验证*/
109 | V1 = (2 * accelorationLimitTCP * remainPosTCP - endVelocityTCP * endVelocityTCP + currentVelocityTCP * currentVelocityTCP)
110 | / (2 * accelorationLimitTCP * time + 2 * currentVelocityTCP - 2 * endVelocityTCP);
111 | //succeed = true;
112 | if ( (V1 >= currentVelocityTCP && V1 <= endVelocityTCP && qAbs(V1) <= velocityLimitTCP
113 | && (time - (V1 - currentVelocityTCP) / accelorationLimitTCP - (endVelocityTCP - V1) / accelorationLimitTCP >= 0)) ){
114 | succeed = true;
115 | }
116 | if (succeed){
117 | t1 = (V1 - currentVelocityTCP) / accelorationLimitTCP;
118 | t2 = time - (endVelocityTCP - V1) / accelorationLimitTCP;
119 | float t = 0;
120 | for (int i = 0; i < numOfInterpolation; i++){
121 | t += T;
122 | if (t <= t1){
123 | pos[i] = currentVelocityTCP * t + 0.5 * accelorationLimitTCP * t * t;
124 | }else if (t > t1 && t <= t2){
125 | pos[i] = (0 + currentVelocityTCP * t1 + 0.5 * accelorationLimitTCP * t1 * t1)
126 | + V1 * (t - t1);
127 | }else{
128 | pos[i] = (0 + currentVelocityTCP * t1 + 0.5 * accelorationLimitTCP * t1 * t1)
129 | + V1 * (t2 - t1)
130 | + V1 * (t - t2)
131 | + 0.5 * accelorationLimitTCP * (t- t2) * (t - t2);
132 | }
133 | }
134 | break;
135 | }
136 |
137 | /*情况3:减速-匀速-加速 先假设后验证*/
138 | delta = 4 * (-accelorationLimitTCP * time + currentVelocityTCP + endVelocityTCP)
139 | * (-accelorationLimitTCP * time + currentVelocityTCP + endVelocityTCP)
140 | - 8 * (currentVelocityTCP * currentVelocityTCP + endVelocityTCP * endVelocityTCP - 2 * accelorationLimitTCP * remainPosTCP);
141 | if (delta < 0){
142 | succeed = false;
143 | }else if (delta == 0){
144 | V1 = (currentVelocityTCP + endVelocityTCP - accelorationLimitTCP *time) / 2;
145 | if (~(V1 <= currentVelocityTCP && V1 <= endVelocityTCP && qAbs(V1) <= velocityLimitTCP
146 | && time - (V1 - currentVelocityTCP)/(-accelorationLimitTCP) - (endVelocityTCP - V1) / accelorationLimitTCP >= 0)){
147 | succeed = false;
148 | }
149 | }else{
150 | V[0] = (2 * (currentVelocityTCP + endVelocityTCP - accelorationLimitTCP * time) + qSqrt(delta)) / 4;
151 |
152 | V[1] = (2 * (currentVelocityTCP + endVelocityTCP - accelorationLimitTCP * time) - qSqrt(delta)) / 4;
153 | if (V[0] <= currentVelocityTCP && V[0] <= endVelocityTCP && qAbs(V[0]) <= velocityLimitTCP
154 | && time - (V[0] - currentVelocityTCP)/(-accelorationLimitTCP) - (endVelocityTCP - V[0]) / accelorationLimitTCP >= 0){
155 | V1 = V[0];
156 | succeed = true;
157 | }else if(V[1] <= currentVelocityTCP && V[1] <= endVelocityTCP && qAbs(V[1]) <= velocityLimitTCP
158 | && time - (V[1] - currentVelocityTCP)/(-accelorationLimitTCP) - (endVelocityTCP - V[1]) / accelorationLimitTCP >= 0){
159 | V1 = V[1];
160 | succeed = true;
161 | }else{
162 | succeed = false;
163 | }
164 | }
165 | if (succeed){
166 | t1 = (V1 - currentVelocityTCP) / (-accelorationLimitTCP);
167 | t2 = time - (endVelocityTCP - V1) / accelorationLimitTCP;
168 | float t = 0;
169 | for (int i = 0; i < numOfInterpolation; i++){
170 | t += T;
171 | if (t <= t1){
172 | pos[i] = currentVelocityTCP * t - 0.5 * accelorationLimitTCP * t * t;
173 | }else if (t > t1 && t <= t2){
174 | pos[i] = (0 + currentVelocityTCP * t1 - 0.5 * accelorationLimitTCP * t1 * t1)
175 | + V1 * (t - t1);
176 | }else{
177 | pos[i] = (0 + currentVelocityTCP * t1 - 0.5 * accelorationLimitTCP * t1 * t1)
178 | + V1 * (t2 - t1)
179 | + V1 * (t - t2)
180 | + 0.5 * accelorationLimitTCP * (t- t2) * (t - t2);
181 | }
182 | }
183 | break;
184 | }
185 |
186 | /*情况4:减速-匀速-减速*/
187 | V1 = (2 * accelorationLimitTCP * remainPosTCP + endVelocityTCP * endVelocityTCP - currentVelocityTCP * currentVelocityTCP)
188 | / (2 * accelorationLimitTCP * time - 2 * currentVelocityTCP + 2 * endVelocityTCP);
189 | //succeed = true;
190 | if (V1 <= currentVelocityTCP && V1 >= endVelocityTCP && qAbs(V1) <= velocityLimitTCP
191 | && (time - (V1 - currentVelocityTCP) / (-accelorationLimitTCP) - (endVelocityTCP - V1) / (-accelorationLimitTCP) >= 0)){
192 | succeed = true;
193 | }
194 | if (succeed){
195 | t1 = (V1 - currentVelocityTCP) / (-accelorationLimitTCP);
196 | t2 = time - (endVelocityTCP - V1) / (-accelorationLimitTCP);
197 | float t = 0;
198 | for (int i = 0; i < numOfInterpolation; i++){
199 | t += T;
200 | if (t <= t1){
201 | pos[i] = currentVelocityTCP * t - 0.5 * accelorationLimitTCP * t * t;
202 | }else if (t > t1 && t <= t2){
203 | pos[i] = (0 + currentVelocityTCP * t1 - 0.5 * accelorationLimitTCP * t1 * t1)
204 | + V1 * (t - t1);
205 | }else{
206 | pos[i] = (0 + currentVelocityTCP * t1 - 0.5 * accelorationLimitTCP * t1 * t1)
207 | + V1 * (t2 - t1)
208 | + V1 * (t - t2)
209 | - 0.5 * accelorationLimitTCP * (t- t2) * (t - t2);
210 | }
211 | }
212 | break;
213 | }
214 | }
215 | if (succeed) {
216 | currentVelocityTCP = pos.first() / T;
217 | return pos;
218 | } else {
219 | return QVector();
220 | }
221 | }
222 |
223 | /*!
224 | * \brief MotionControler::TPlan 指定期望速度的T形速度规划,相对运动方式
225 | * \return 各轴下一个插补周期的目标位置
226 | */
227 | bool MotionControler::TPlanBaseVelocity()
228 | {
229 | bool succeed = false;
230 | /*情况1:加速度-减速*/
231 | if (remainPosTCP > 0
232 | && (2 * velocityLimitTCP * velocityLimitTCP - startVelocityTCP * startVelocityTCP - endVelocityTCP * endVelocityTCP) / (2 * accelorationLimitTCP) >= remainPosTCP ){
233 | succeed = true;
234 | V1 = qSqrt(accelorationLimitTCP * remainPosTCP + 0.5 * startVelocityTCP * startVelocityTCP + 0.5 * endVelocityTCP * endVelocityTCP);
235 | t1 = (V1 - startVelocityTCP) / accelorationLimitTCP;
236 | t2 = (2 * V1 - startVelocityTCP - endVelocityTCP) / accelorationLimitTCP;
237 | interpolationNum = (int) (t2 / T) - 1;
238 | interpolationType = type0;
239 | }
240 | /* 情况2: 加速-匀速-减速*/
241 | else if (remainPosTCP > 0 && (2 * velocityLimitTCP * velocityLimitTCP - startVelocityTCP * startVelocityTCP - endVelocityTCP * endVelocityTCP) / (2 * accelorationLimitTCP) < remainPosTCP ){
242 | succeed = true;
243 | t1 = (velocityLimitTCP - startVelocityTCP) / accelorationLimitTCP;
244 | t2 = t1 + (remainPosTCP -
245 | (2 * velocityLimitTCP * velocityLimitTCP - startVelocityTCP * startVelocityTCP - endVelocityTCP * endVelocityTCP)
246 | / (2 * accelorationLimitTCP)) / velocityLimitTCP;
247 | t3 = t2 + (velocityLimitTCP - endVelocityTCP) / accelorationLimitTCP;
248 | interpolationNum = (int) (t3 / T) - 1;
249 | interpolationType = type1;
250 | }
251 | /* 情况3: 减速-加速*/
252 | else if (remainPosTCP < 0 && (2 * velocityLimitTCP * velocityLimitTCP - startVelocityTCP * startVelocityTCP -endVelocityTCP * endVelocityTCP) / (2 * accelorationLimitTCP) > (-remainPosTCP)) {
253 | succeed = true;
254 | V1 = -qSqrt(-accelorationLimitTCP * remainPosTCP - 0.5 * startVelocityTCP * startVelocityTCP -0.5 * endVelocityTCP * endVelocityTCP);
255 | t1 = (V1 - startVelocityTCP) / (-accelorationLimitTCP);
256 | t2 = (-2 * V1 + startVelocityTCP + endVelocityTCP) / accelorationLimitTCP;
257 | interpolationNum = (int) (t2 / T) - 1;
258 | interpolationType = type2;
259 | }
260 |
261 | /*情况4:减速-匀速-加速*/
262 | else if (remainPosTCP < 0 && (2 * velocityLimitTCP * velocityLimitTCP - startVelocityTCP * startVelocityTCP -endVelocityTCP * endVelocityTCP) / (2 * accelorationLimitTCP) <= (-remainPosTCP)) {
263 | succeed = true;
264 | float t1 = (startVelocityTCP + velocityLimitTCP) / accelorationLimitTCP;
265 | float t2 = t1 + (remainPosTCP +
266 | (2 * velocityLimitTCP * velocityLimitTCP - startVelocityTCP * startVelocityTCP - endVelocityTCP * endVelocityTCP)
267 | / (2 * accelorationLimitTCP)) / (-velocityLimitTCP);
268 | float t3 = t2 + (endVelocityTCP + velocityLimitTCP) / accelorationLimitTCP;
269 | interpolationNum = (int) (t3 / T) - 1;
270 | interpolationType = type3;
271 | }
272 | /* 其它情况:无法规划*/
273 | else {
274 | succeed = false;
275 | }
276 | return succeed;
277 | }
278 |
279 | /*!
280 | * \brief MotionControler::Update 更新运动控制器各状态参数
281 | * 1、每个伺服周期调用一次
282 | * 2、进行运动规划
283 | */
284 | void MotionControler::Update()
285 | {
286 | if (status != free) {
287 | qreal interpolation;
288 | if (interpolationCounter == 0) { /* 首次规划 */
289 | UpdateRemainPos();
290 | TPlanBaseVelocity();
291 | interpolation = GetInterpolation(interpolationCounter);
292 | }
293 | if (interpolationCounter <= interpolationNum && interpolationCounter >= 1 && status != free) {
294 | interpolation = GetInterpolation(interpolationCounter)
295 | - GetInterpolation(interpolationCounter - 1); /* 插补距离 */
296 | } else {
297 | interpolation = 0;
298 | }
299 | UpdateCurrentPos();
300 | UpdateRemainPos();
301 | currentVelocityTCP = interpolation / T; /* 更新当前速度 */
302 | qDebug() << interpolationCounter;
303 | qDebug() << "remainPosTCP: " << remainPosTCP;
304 | qDebug() << "interpolationTable: " << GetInterpolation(interpolationCounter);
305 | qDebug() << "currentPos: " << (UpdateCurrentPos().isEmpty() ? QVector(axisNum + 1, 0) : UpdateCurrentPos());
306 | interpolationCounter++;
307 | if (interpolationCounter > interpolationNum){
308 | status = free;
309 | timer->stop();
310 | }
311 | }
312 | }
313 | /*!
314 | * \brief MotionControler::UpdateCurrentPos 更新当前位置
315 | */
316 | QVector MotionControler::UpdateCurrentPos()
317 | {
318 | qreal remainTotal = 0;
319 | for (int index = 0; index <= axisNum; index++) {
320 | remainTotal += qPow(endPos[index] - startPos[index], 2);
321 | }
322 | remainTotal = qSqrt(remainTotal);
323 | if (qAbs(remainTotal) < error) { /* 说明已经到达目标位置 */
324 | return QVector();
325 | }
326 | qreal coeficiency = GetInterpolation(interpolationCounter) / remainTotal;
327 | for (int index = 0; index <= axisNum; index++) {
328 | qreal remain = endPos[index] - startPos[index];
329 | currentPos[index] = startPos[index] + coeficiency * remain;
330 | }
331 | QVector pos(axisNum + 1);
332 | for (int index = 0; index <= axisNum; index++){
333 | pos[index] = multiper[index] * (currentPos[index] + origin[index]); /* 加上原点偏移 */
334 | }
335 | return pos;
336 | }
337 | /*!
338 | * \brief MotionControler::GetInterpolation 获取插补点
339 | * \param index
340 | * \return
341 | */
342 | qreal MotionControler::GetInterpolation(int index)
343 | {
344 | index = qBound(0, index, interpolationNum);
345 | qreal t = (index + 1) * T;
346 | switch (interpolationType) {
347 | case type0:
348 | if (t <= t1){
349 | return currentVelocityTCP * t + 0.5 * accelorationLimitTCP * t * t;
350 | }else{
351 | return currentVelocityTCP * t1 + 0.5 * accelorationLimitTCP * t1 * t1
352 | + V1 * (t - t1)
353 | - 0.5 * accelorationLimitTCP * (t - t1) * (t - t1);
354 | }
355 | break;
356 | case type1:
357 | if (t <= t1){
358 | return currentVelocityTCP * t + 0.5 * accelorationLimitTCP * t * t;
359 | }else if (t > t1 && t <= t2) {
360 | return currentVelocityTCP * t1+ 0.5 * accelorationLimitTCP * t1 * t1
361 | + velocityLimitTCP * (t - t1);
362 | }else {
363 | return currentVelocityTCP * t1+ 0.5 * accelorationLimitTCP * t1 * t1
364 | + velocityLimitTCP * (t2 - t1)
365 | + velocityLimitTCP * (t - t2) - 0.5 * accelorationLimitTCP * (t - t2) * (t - t2);
366 | }
367 | break;
368 | case type2:
369 | if (t <= t1){
370 | return currentVelocityTCP * t - 0.5 * accelorationLimitTCP * t * t;
371 | }else {
372 | return currentVelocityTCP * t1 - 0.5 * accelorationLimitTCP * t1 * t1
373 | + V1 * (t - t1) + 0.5 * accelorationLimitTCP * (t - t1) * (t - t1);
374 | }
375 | break;
376 | case type3:
377 | if (t <= t1){
378 | return currentVelocityTCP * t - 0.5 * accelorationLimitTCP * t * t;
379 | }else if (t > t1 && t <= t2){
380 | return currentVelocityTCP * t1 - 0.5 * accelorationLimitTCP * t1 * t1
381 | - velocityLimitTCP * (t - t1);
382 | }else {
383 | return currentVelocityTCP * t1 - 0.5 * accelorationLimitTCP * t1 * t1
384 | - velocityLimitTCP * (t2 - t1)
385 | - velocityLimitTCP * (t - t2) + 0.5 * accelorationLimitTCP * (t - t2) * (t - t2);
386 | }
387 | break;
388 | default:
389 | break;
390 | }
391 | return 0;
392 | }
393 |
394 | void MotionControler::MoveAbs(QVector pos)
395 | {
396 | if (status == free) { /* 取消if条件后可以运动中更改运动指令 */
397 | SetEndPos(pos);
398 | status = moveAbs;
399 | timer->start((int)T);
400 | }
401 | }
402 |
403 | void MotionControler::MoveAbs(qreal pos, int axis)
404 | {
405 | if (status == free){
406 | SetEndPos(pos, axis);
407 | status = moveAbs;
408 | timer->start((int)T);
409 | }
410 | }
411 |
412 | void MotionControler::Move(QVector pos)
413 | {
414 | for (int index = 0; index <= axisNum; index++) {
415 | pos[index] += currentPos[index];
416 | }
417 | MoveAbs(pos);
418 | status = move;
419 | }
420 |
421 | void MotionControler::Move(qreal pos, int axis)
422 | {
423 | pos += currentPos[axis];
424 | MoveAbs(pos, axis);
425 | status = move;
426 | }
427 | /*!
428 | * \brief MotionControler::RapidStop 快速停止,加速度无限大
429 | * 直接停在当前位置
430 | */
431 | void MotionControler::RapidStop()
432 | {
433 | status = free;
434 | timer->stop();
435 | }
436 | /*!
437 | * \brief MotionControler::Stop 以最大加速度减速直到停止
438 | */
439 | void MotionControler::Stop()
440 | {
441 | //计算出以最大加速度减速后停下来的位置,将其设置成endPos,执行move指令
442 | qreal stopDistance = qPow(currentVelocityTCP, 2) / (2 * accelorationLimitTCP);
443 | qreal coefficiency = stopDistance / UpdateRemainPos();
444 | QVector stopPos(axisNum + 1);
445 | for (int index = 0; index <= axisNum; index++) {
446 | stopPos[index] = currentPos[index] + coefficiency * (endPos[index] - currentPos[index]);
447 | }
448 | SetEndPos(stopPos); /* 重置终点 */
449 | }
450 | /*!
451 | * \brief MotionControler::DefPos 重定义当前轴位置
452 | */
453 | void MotionControler::DefPos(qreal pos, int axis)
454 | {
455 | origin[axis] = currentPos[axis] + origin[axis] - pos;
456 | currentPos[axis] = pos;
457 | }
458 |
459 | void MotionControler::DefPos(QVector pos)
460 | {
461 | for (int index = 0; index <= axisNum; index++){
462 | origin[index] = currentPos[index] + origin[index] - pos[index];
463 | currentPos[index] = pos[index];
464 | }
465 | }
466 | /*!
467 | * \brief MotionControler::UpdateRemainPos 更新剩余距离
468 | * \return 返回剩余距离
469 | */
470 | qreal MotionControler::UpdateRemainPos()
471 | {
472 | qreal remain = 0;
473 | for (int index = 0; index <= axisNum; index++) {
474 | remainPos[index] = endPos[index] - currentPos[index];
475 | remain += qPow(remainPos[index], 2);
476 | }
477 | remainPosTCP = qSqrt(remain);
478 | return remainPosTCP;
479 | }
480 | /*!
481 | * \brief MotionControler::SetEndPos 设置终点,会导致重新进行运动规划
482 | * \param pos
483 | */
484 | void MotionControler::SetEndPos(QVector pos)
485 | {
486 | if (endPos == pos){
487 | return;
488 | } else {
489 | status = moveAbs; /* 当MType != free时才会进行运动规划 */
490 | endPos = pos;
491 | interpolationCounter = 0;
492 | // interpolationTable = QVector(); /* 重置插值列表 */
493 | startPos = currentPos;
494 | startVelocityTCP = currentVelocityTCP;
495 | }
496 | }
497 |
498 | void MotionControler::SetEndPos(qreal pos, int axis)
499 | {
500 | if (endPos[axis] == pos) {
501 | return;
502 | } else {
503 | status = moveAbs;
504 | endPos[axis] = pos;
505 | interpolationCounter = 0;
506 | // interpolationTable = QVector();
507 | startPos = currentPos;
508 | startVelocityTCP = currentVelocityTCP;
509 |
510 | }
511 | }
512 | /*!
513 | * \brief MotionControler::SetVelocityLimitTCP 重置期望速度
514 | * 1、如果MType = free,则不会带来运动规划
515 | * 2、如果MType != free,则会重新进行运动规划
516 | * \param vel
517 | */
518 | void MotionControler::SetVelocityLimitTCP(qreal vel)
519 | {
520 | if (velocityLimitTCP == vel) {
521 | return;
522 | } else {
523 | velocityLimitTCP = vel;
524 | interpolationCounter = 0;
525 | // interpolationTable = QVector();
526 | startPos = currentPos;
527 | startVelocityTCP = currentVelocityTCP;
528 |
529 | }
530 | }
531 | /*!
532 | * \brief MotionControler::SetAccelorationLimitTCP 重置期望加速度
533 | * 1、如果MType = free,则不会带来运动规划
534 | * 2、如果MType != free,则会重新进行运动规划
535 | * 3、更新误差限
536 | * \param acc
537 | */
538 | void MotionControler::SetAccelorationLimitTCP(qreal acc)
539 | {
540 | if (accelorationLimitTCP == acc) {
541 | return;
542 | } else {
543 | accelorationLimitTCP = acc;
544 | interpolationCounter = 0;
545 | // interpolationTable = QVector();
546 | startPos = currentPos;
547 | startVelocityTCP = currentVelocityTCP;
548 | error = accelorationLimitTCP * qPow(T, 2);
549 | }
550 | }
551 | /*!
552 | * \brief MotionControler::sendCurrentPos slot,由定时器触发,
553 | * 用来激活castCurrentPos()信号,广播伺服位置
554 | */
555 | void MotionControler::SendCurrentPos()
556 | {
557 | Update();
558 | if (status != free) {
559 | // emit CastCurrentPos(UpdateCurrentPos());
560 | }
561 | }
562 |
--------------------------------------------------------------------------------
/MotionControler.h:
--------------------------------------------------------------------------------
1 | #ifndef MOTIONCONTROLER_H
2 | #define MOTIONCONTROLER_H
3 |
4 | #include
5 | #include
6 |
7 | class QTimer;
8 | /*!
9 | * \brief 运动控制器类
10 | * 1、核心是TPlanBaseVelocity()进行T形速度规划,计算出位移曲线的分段函数GetInterpolation(int index),
11 | * 2、运动指令MoveAbs()和Move()
12 | * 3.1、信号CastCurrentPos(QVector)每T时间对外广播每个伺服周期的指令位置
13 | * 3.2、亦可不使用signal,外部调用update()更新一次伺服位置后再调用GetCurrentPos()得到当前伺服周期的位置
14 | */
15 | class MotionControler : QObject
16 | {
17 | public:
18 | /* 运动状态枚举 */
19 | enum motionStatus{
20 | moveAbs,
21 | move,
22 | free,
23 | };
24 | enum curveType{
25 | type0, //加速-减速
26 | type1, //加速度-匀速-减速
27 | type2, //减速-加速度
28 | type3, //减速-匀速-加速
29 | };
30 |
31 | MotionControler();
32 |
33 | /* 运动指令 */
34 | void MoveAbs(QVector pos);
35 | void MoveAbs(qreal pos, int axis);
36 | void Move(QVector pos);
37 | void Move(qreal pos, int axis);
38 | void RapidStop();
39 | void Stop();
40 |
41 | /* 运动规划 */
42 | QVector TPlanBaseTime(qreal time);
43 | bool TPlanBaseVelocity();
44 | void Update();
45 | qreal UpdateRemainPos();
46 | QVector UpdateCurrentPos();
47 | qreal GetInterpolation(int index);
48 | inline motionStatus GetStatus() {return status;}
49 |
50 | /* 更改以下运动参数,可能会重新进行运动规划 */
51 | void SetEndPos(QVector pos);
52 | void SetEndPos(qreal pos, int axis);
53 | void SetVelocityLimitTCP(qreal vel);
54 | void SetAccelorationLimitTCP(qreal acc);
55 | //未定义、未使用
56 | void SetVelocityLimit(QVector vel);
57 | void SetAccelorationLimit(QVector acc);
58 |
59 | /* 参数设置 */
60 | inline void SetCurrentPos(QVector pos) {currentPos = pos;}
61 | inline void SetCurrentPos(qreal pos, int axis) {currentPos[axis] = pos;}
62 |
63 | inline void SetEndVelocityTCP(qreal vel) {endVelocityTCP = vel;}
64 | inline void SetEndVelocity(QVector vel) {endVelocity = vel;}
65 | inline void SetEndVelocity(qreal vel, int axis) {endVelocity[axis] = vel;}
66 | inline void SetT(qreal t) { T = t;}
67 | inline void SetError(qreal err) {error = err;} //最小建议值为accelorationLimitTCP * T * T
68 | inline void SetAxisNum(int num) {axisNum = num;}
69 |
70 | /* 定义轴位置 */
71 | void DefPos(qreal pos, int axis);
72 | void DefPos(QVector pos);
73 |
74 | /* 参数获取 */
75 | QVector GetCurrentPos() {return currentPos;}
76 | qreal GetCurrentPos(int axis) {return currentPos[axis];}
77 | QVector GetCurrentVel() {return currentVelocity;}
78 | qreal GetCurrentVelTCP() {return currentVelocityTCP;}
79 | QVector GetCurrentAcc() {return currentAcceloration;}
80 | qreal GetCurrentAccTCP() {return currentAccelorationTCP;}
81 |
82 |
83 | signals:
84 | void CastCurrentPos(QVector pos); /* 向外广播伺服位置 */
85 | //private slots:
86 | public:
87 | void SendCurrentPos(); /* 由定时器每1ms触发一次 */
88 |
89 | private:
90 | int axisNum; /* 轴个数 axisNum + 1 */
91 |
92 | QVector currentPos; /* 各轴当前位置 */
93 | qreal currentVelocityTCP; /* 当前的TCP速度 */
94 | QVector currentVelocity; /* 各轴当前速度,利用速度分解得到 */
95 | qreal currentAccelorationTCP; /* 当前合成加速度,即TCP加速度 */
96 | QVector currentAcceloration; /* 各轴当前加速度,利用加速度分解得到 */
97 |
98 | QVector startPos; /* 速度规划时的起始位置:每次规划前需要更新成当前位置 */
99 | qreal startVelocityTCP;
100 | QVector endPos; /* 终点的各轴位置 */
101 | qreal endVelocityTCP; /* 终点的TCP速度 */
102 | QVector endVelocity; /* 终点的各轴速度 */
103 |
104 | qreal remainPosTCP; /* 剩下的总路程 */
105 | QVector remainPos; /* 剩下的各轴位移 */
106 |
107 | motionStatus status; /* 当前运动状态 */
108 |
109 | QVector velocityLimit; /* 各轴速度限制 */
110 | qreal velocityLimitTCP; /* TCP速度限制 */
111 | QVector accelorationLimit; /* 各轴加速度限制 */
112 | qreal accelorationLimitTCP; /* TCP加速度限制 */
113 |
114 | QVector multiper; /* 轴增益 */
115 | QVector origin; /* 各轴原点偏移 */
116 |
117 | qreal T; /* 伺服周期 */
118 | /* 插补过程中的参数 */
119 | int interpolationCounter; /* 一次速度规划中的插值索引 */
120 | int interpolationNum; /* 一次速度规划中的插值点总个数 */
121 | int interpolationType;
122 | qreal t1, t2, t3; /* T形运动规划中间变量 */
123 | qreal V1;
124 |
125 | qreal error; /* 终点判定误差 */
126 |
127 | QTimer *timer; /* 需要在运动指令执行后开始,运动指令完成后关闭
128 | status = free时关闭
129 | status != free时开启 */
130 |
131 | };
132 |
133 | #endif // MOTIONCONTROLER_H
134 |
--------------------------------------------------------------------------------
/README.TXT:
--------------------------------------------------------------------------------
1 | class MotionControl
2 | /*!
3 | * \brief 运动控制器类
4 | * 1、核心是TPlanBaseVelocity()进行T形速度规划,计算出位移曲线的分段函数GetInterpolation(int index)
5 | * 2、运动指令
6 | * 2.1、运动指令MoveAbs()和Move()
7 | 2.2、调用终点设置函数SetEndPos(),也会导致生成一个新的运动指令,实现对终点的跟随
8 | * 3、指令位置的刷新与获取
9 | * 3.1、信号CastCurrentPos(QVector)每T时间对外广播每个伺服周期的指令位置
10 | * 3.2、亦可不使用signal,外部调用update()更新一次伺服位置后再调用GetCurrentPos()得到当前伺服周期的位置
11 | */
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | // QCoreApplication a(argc, argv);
10 |
11 | MotionControler mc;
12 | // 状态配置
13 | mc.SetAccelorationLimitTCP(50000);
14 | mc.SetVelocityLimitTCP(80);
15 | mc.SetEndVelocityTCP(0);
16 | mc.SetError(500 * 1e-6);
17 | int axisNum = 1;
18 | QVector endPos(axisNum + 1);
19 | for (int index = 0; index <= axisNum; index++) {
20 | endPos[index] = index + 1;
21 | }
22 | mc.MoveAbs(endPos);
23 | int count = 0;
24 | QString path("motionPlan.csv");
25 | QFile csvFile(path);
26 | if(!csvFile.open(QIODevice::WriteOnly)){
27 | return 0;
28 | }
29 | QTextStream csv(&csvFile);
30 | while (1) {
31 | if (mc.GetStatus() == MotionControler::free) {
32 | break;
33 | qDebug() << "test";
34 | }
35 | mc.SendCurrentPos();
36 | // csv << mc.UpdateRemainPos() << endl;
37 | count++;
38 | if (count == 10){
39 | mc.SetAccelorationLimitTCP(5000);
40 | // break;
41 | // mc.MoveAbs(QVector(mc.axisNum + 1, 1));
42 | }
43 |
44 | }
45 | qDebug() << endl;
46 | qDebug() << "total interpolation points number: " << count;
47 | qDebug() << "finish to motion planning";
48 | qDebug() << endl;
49 | // return a.exec();
50 | return 0;
51 | }
52 |
53 |
--------------------------------------------------------------------------------