運動學(xué)仿真:四桿與曲柄滑塊gif動畫)
在機械原理課程里四桿機構(gòu)是最經(jīng)典的運動學(xué)分析對象但我見過很多同學(xué)卡在同一步位置方程能列出來手算也能算幾個特殊位置可是一旦要把整周運動畫成位移曲線、看清連桿的真實軌跡或者讓機構(gòu)真正“動起來”就不知道下一步怎么辦了。這篇文章想給出一個明確判斷用 Matlab 做連桿機構(gòu)運動學(xué)仿真的真正門檻不在于編程而在于把機構(gòu)簡圖轉(zhuǎn)化成可求解的數(shù)學(xué)方程。只要你掌握了閉環(huán)矢量方程、逐幀繪圖、gif 動畫輸出這條主線曲柄滑塊、四桿、五桿、六桿在你眼里都會是同一道題的三種變形。讀完本文你可以獨立復(fù)現(xiàn)曲柄滑塊機構(gòu)和鉸鏈四桿機構(gòu)的完整運動學(xué)仿真并且生成動態(tài) gif為后續(xù)做六桿機構(gòu)、機構(gòu)優(yōu)化和 Simscape 動力學(xué)分析打好底子。1. 為什么用 Matlab 做連桿機構(gòu)運動學(xué)仿真做機構(gòu)運動學(xué)仿真可選方案很多Adams、SolidWorks Motion、Simulink Simscape都自帶可視化。但 Matlab 純腳本方案到目前為止仍然有不可替代的價值。第一它讓你面對數(shù)學(xué)本身。在 Adams 或 SolidWorks 里你拖幾個約束、點一下仿真就能看到動畫但內(nèi)部的位置方程是怎么解出來的對使用者來說是黑盒。Matlab 里你必須自己把機構(gòu)幾何關(guān)系寫成方程再自己解方程。這個過程看起來多繞了一步實際上恰恰是理解機構(gòu)運動學(xué)最快的一條路。第二它的自動化能力強。Matlab 的矩陣運算讓“一個循環(huán)跑 200 個位置”變得極其自然。你不再需要手動取點也不需要像 CAD 軟件那樣逐個位置做幾何約束而是用一段腳本批量計算整周運動。第三它的繪圖和 gif 輸出鏈路非常成熟。逐幀生成圖片、用getframe捕獲、再通過imwrite合成 gif這套流程可以復(fù)用到任何仿真結(jié)果上不局限于連桿機構(gòu)也可以用于齒輪嚙合、凸輪輪廓、機械臂軌跡等項目。所以本文的定位不是“用 Matlab 替代專業(yè)機械仿真軟件”而是先用 Matlab 把機構(gòu)運動分析的數(shù)學(xué)原理講透。Computed Aided Engineering 工具再強大也無法替代你對機構(gòu)本身的理解。2. 連桿機構(gòu)運動學(xué)基礎(chǔ)從四桿到滑塊的本質(zhì)2.1 運動學(xué)與動力學(xué)的邊界機構(gòu)學(xué)里運動學(xué)研究的是位置、速度、加速度與時間或輸入角度的關(guān)系不涉及力和質(zhì)量。動力學(xué)則研究力、力矩、質(zhì)量與運動之間的因果關(guān)系??梢赃@樣類比運動學(xué)像錄像分析你只看運動員的肢體軌跡、速度變化動力學(xué)像肌肉發(fā)力分析你要研究哪些力產(chǎn)生了這些運動。連桿機構(gòu)仿真通常先做運動學(xué)得到運動規(guī)律后再做動力學(xué)。本文只覆蓋運動學(xué)但代碼框架對動力學(xué)擴展同樣有效。2.2 平面機構(gòu)的自由度平面機構(gòu)自由度用 Grübler-Kutzbach 公式計算F 3(n - 1) - 2P_L - P_H其中n是構(gòu)件數(shù)P_L是低副數(shù)轉(zhuǎn)動副、移動副P_H是高副數(shù)。四桿機構(gòu)n4, P_L4得到F1只需要一個輸入就能確定整個機構(gòu)運動。曲柄滑塊機構(gòu)n4, P_L4三個轉(zhuǎn)動副、一個移動副自由度也是 1。純鉸鏈五桿機構(gòu)n5, P_L5F2需要兩個輸入才能確定運動這就是五桿比四桿復(fù)雜的原因。六桿機構(gòu)典型瓦特六桿n6, P_L7F1但它的閉環(huán)更多求解時往往要拆成多個閉環(huán)依次求解。理解自由度是寫仿真代碼的第一步。自由度為 1 時你遍歷輸入角度就能生成機構(gòu)的完整運動自由度為 2 時你需要在兩個輸入之間建立某種約束否則動畫會“亂動”。2.3 平面連桿機構(gòu)的閉環(huán)矢量方程平面連桿機構(gòu)可以看成一系列矢量首尾相接形成的閉環(huán)。以鉸鏈四桿機構(gòu)為例A 為固定鉸D 為固定鉸AB 是曲柄BC 是連桿CD 是搖桿閉環(huán)矢量方程為AB BC AD DC寫成復(fù)數(shù)形式a*e^(i*theta1) b*e^(i*theta2) d c*e^(i*theta3)實部和虛部分別相等得到兩個位置方程。已知輸入角theta1未知數(shù)是theta2和theta3兩個方程兩個未知數(shù)可解。曲柄滑塊機構(gòu)其實是四桿機構(gòu)的變體當(dāng)搖桿長度趨于無窮大時搖桿末端的圓弧軌跡退化為直線就得到滑塊。因此曲柄滑塊的解析解更簡單適合零基礎(chǔ)入門。2.4 Grashof 條件不是任意四桿都能讓曲柄整周回轉(zhuǎn)。設(shè)四桿長度為a, b, c, d其中s為最短桿l為最長桿如果滿足s l 其余兩桿之和并且最短桿為機架或與機架相鄰則存在整周回轉(zhuǎn)構(gòu)件。這就是 Grashof 條件。最短桿為連架桿時得到曲柄搖桿機構(gòu)。最短桿為機架時得到雙曲柄機構(gòu)。最短桿為連桿時得到雙搖桿機構(gòu)。寫仿真代碼之前先檢查 Grashof 條件可以避免在某個角度出現(xiàn)“根號內(nèi)為負(fù)”或“arccos 越界”的尷尬錯誤。3. 環(huán)境準(zhǔn)備與仿真主流程3.1 環(huán)境要求本文代碼全部使用 Matlab 基礎(chǔ)函數(shù)不需要 Simulink也不需要額外的工具箱。理論上 R2016b 之后的版本都能運行。如果用 R2020a 之后的版本可以使用exportgraphics輸出 gif本文默認(rèn)采用兼容性最好的getframe imwrite方案。操作系統(tǒng)不限Windows、macOS、Linux 均可。需要注意兩點動畫捕獲getframe需要圖形界面環(huán)境不建議在完全 headless 的服務(wù)器上直接運行。中文注釋在部分舊版 Matlab 編輯器里可能亂碼建議源碼文件統(tǒng)一保存為 UTF-8 編碼或者直接使用英文注釋。3.2 仿真主流程后面的示例都遵守同一個主流程確定機構(gòu)拓?fù)浜蜅U長參數(shù)。根據(jù)閉環(huán)矢量方程建立位置求解公式。遍歷輸入角度逐幀求解未知角度或滑塊位移。在需要時對時間求導(dǎo)得到速度和加速度。每一幀重繪機構(gòu)簡圖捕獲畫面寫入 gif。把這個流程記熟后面的四桿、五桿、六桿只是位置方程更多、迭代更復(fù)雜主線不變。4. 示例一曲柄滑塊機構(gòu)仿真解析法 gif4.1 數(shù)學(xué)模型曲柄滑塊機構(gòu)中設(shè)曲柄長度r連桿長度l曲柄轉(zhuǎn)角theta滑塊位移x。幾何關(guān)系為x r*cos(theta) sqrt(l^2 - r^2*sin(theta)^2)對時間求導(dǎo)得到滑塊速度v -r*omega*sin(theta) - (r^2*omega*sin(theta)*cos(theta)) / sqrt(l^2 - r^2*sin(theta)^2)加速度可以直接繼續(xù)求導(dǎo)也可以像本文代碼一樣用gradient數(shù)值微分。解析式容易寫錯數(shù)值微分適合驗證。4.2 完整代碼保存為slider_crank.m% 文件: slider_crank.m % 曲柄滑塊機構(gòu)運動學(xué)仿真輸出 gif 動畫 clear; clc; close all; % 參數(shù)定義 r 0.10; % 曲柄長度 m l 0.30; % 連桿長度 m omega 2*pi; % 曲柄角速度 rad/s約每秒一轉(zhuǎn) N 200; % 一個周期采樣點數(shù) theta linspace(0, 2*pi, N); % 曲柄轉(zhuǎn)角 t theta / omega; % 對應(yīng)時間 dt t(2) - t(1); % 時間步長 % 位置解析解 x r*cos(theta) sqrt(l^2 - r^2*sin(theta).^2); % 速度解析解 v -r*omega*sin(theta) ... - (r^2*omega*sin(theta).*cos(theta)) ./ sqrt(l^2 - r^2*sin(theta).^2); % 加速度數(shù)值微分驗證 a gradient(v, dt); % 創(chuàng)建畫布 figure(Position, [100 100 900 420]); for i 1:N % 左圖機構(gòu)動畫 subplot(1, 2, 1); cla; hold on; axis equal; xlim([-0.45 0.45]); ylim([-0.35 0.35]); xA 0; yA 0; % 曲柄固定鉸 xB r*cos(theta(i)); yB r*sin(theta(i)); % 曲柄與連桿連接點 xC x(i); yC 0; % 滑塊位置 % 曲柄 plot([xA xB], [yA yB], b-o, LineWidth, 2); % 連桿 plot([xB xC], [yB yC], r-o, LineWidth, 2); % 滑塊矩形 rect_pos [xC-0.02 -0.02; xC0.02 -0.02; xC0.02 0.02; xC-0.02 0.02]; patch(Vertices, rect_pos, Faces, [1 2 3 4], ... FaceColor, [0.7 0.7 0.7], EdgeColor, k); % 滑道 plot([-0.45 xC], [0 0], k--); % 固定鉸標(biāo)記 plot(xA, yA, ko, MarkerFaceColor, k); title(sprintf(t %.3f s, t(i))); xlabel(x (m)); ylabel(y (m)); % 右圖滑塊位移曲線 subplot(1, 2, 2); plot(t(1:i), x(1:i), b-, LineWidth, 1.5); xlim([0 t(end)]); ylim([min(x) max(x)]); xlabel(時間 (s)); ylabel(滑塊位移 x (m)); title(位移曲線); grid on; % 捕獲當(dāng)前幀寫入 gif drawnow; frame getframe(gcf); im frame2im(frame); [imind, cm] rgb2ind(im, 256); if i 1 imwrite(imind, cm, slider_crank.gif, gif, ... Loopcount, inf, DelayTime, 0.03); else imwrite(imind, cm, slider_crank.gif, gif, ... WriteMode, append, DelayTime, 0.03); end end disp(動畫已保存為 slider_crank.gif);4.3 代碼邏輯說明位置解只用了一行x r*cos(theta) sqrt(l^2 - r^2*sin(theta).^2)這就是解析法的好處。速度求導(dǎo)容易出錯所以代碼里保留了完整的解析表達(dá)式。加速度用gradient(v, dt)做數(shù)值微分是一種快速校驗手段如果解析速度公式寫錯加速度曲線會出現(xiàn)明顯跳變。動畫部分我用了cla清空坐標(biāo)區(qū)再重新繪制。這種方式簡單直接缺點是性能一般。如果采樣點數(shù)較大可以改用先創(chuàng)建圖形對象、再更新XData/YData的方式后面第 9 節(jié)會說明。4.4 運行結(jié)果與驗證直接運行腳本會在當(dāng)前目錄生成slider_crank.gif。用瀏覽器或圖片查看器打開可以看到曲柄帶動連桿推動滑塊往復(fù)運動。從運動學(xué)角度驗證幾個特征滑塊位移范圍應(yīng)該在[l-r, lr] [0.2, 0.4]之間?;瑝K速度在位移中點附近最大在兩端接近 0。一個周期內(nèi)滑塊往復(fù)一次位移曲線與單缸發(fā)動機活塞運動規(guī)律一致。如果位移范圍不對優(yōu)先檢查r和l的定義如果 gif 文件沒有正常生成檢查當(dāng)前目錄是否可寫、循環(huán)里是否匹配了if i 1和else分支。5. 示例二鉸鏈四桿機構(gòu)仿真數(shù)值解 軌跡繪制5.1 數(shù)學(xué)模型鉸鏈四桿機構(gòu)的位置求解比曲柄滑塊復(fù)雜一些因為theta2和theta3不能直接顯式解出但可以通過代數(shù)消元得到解析表達(dá)式。設(shè)固定鉸 A 為(0,0)D 為(d,0)。曲柄 AB 長度為a連桿 BC 長度為b搖桿 CD 長度為c。由矢量閉環(huán)B (a*cos(theta1), a*sin(theta1))C 點既要滿足C B b*(cos(theta2), sin(theta2))又要滿足|C - D| c。展開后得到A*cos(theta2) B*sin(theta2) K其中A xB - d B yB K (c^2 - (xB-d)^2 - yB^2 - b^2) / (2*b)兩邊同除R sqrt(A^2 B^2)化為cos(theta2 - phi) K / R phi atan2(B, A)于是theta2 phi ± acos(K / R)兩個解對應(yīng)機構(gòu)的兩種裝配模式通常稱為“開式”和“交叉式”。在動畫中必須保證每一幀選擇同一個裝配模式否則機構(gòu)會出現(xiàn)瞬間翻轉(zhuǎn)。最簡單的策略是讓當(dāng)前幀的解與上一幀的角度差值最小。求出theta2后C 點坐標(biāo)已知搖桿角度theta3 atan2(yC, xC - d)5.2 完整代碼保存為four_bar.m% 文件: four_bar.m % 鉸鏈四桿機構(gòu)運動學(xué)仿真輸出 gif 動畫和搖桿擺角曲線 clear; clc; close all; % 桿長參數(shù) a 0.10; % 曲柄 AB b 0.30; % 連桿 BC c 0.25; % 搖桿 CD d 0.28; % 機架 AD % Grashof 條件檢查 s min([a b c d]); l max([a b c d]); rest sum([a b c d]) - s - l; if s l rest 1e-10 disp(滿足 Grashof 條件曲柄可以整周回轉(zhuǎn)。); else disp(不滿足 Grashof 條件機構(gòu)可能存在裝配死角。); end omega 2*pi; % 曲柄角速度 N 200; theta1 linspace(0, 2*pi, N); t theta1 / omega; dt t(2) - t(1); theta2 zeros(1, N); theta3 zeros(1, N); xC_all zeros(1, N); yC_all zeros(1, N); % 初始猜測選擇開式裝配模式 theta2_prev 0.5; for i 1:N xB a * cos(theta1(i)); yB a * sin(theta1(i)); A xB - d; B yB; K (c^2 - (xB-d)^2 - yB^2 - b^2) / (2*b); R sqrt(A^2 B^2); phi atan2(B, A); % 判斷裝配是否可達(dá) if abs(K / R) 1 error(theta1 %.2f 時機構(gòu)無法裝配請檢查桿長參數(shù), theta1(i)); end alpha acos(K / R); cand1 phi alpha; cand2 phi - alpha; % 選擇與上一幀角度差值最小的解保持裝配模式連續(xù) [~, idx] min(abs([cand1 cand2] - theta2_prev)); cand [cand1 cand2]; theta2(i) cand(idx); theta2_prev theta2(i); % 由 theta2 計算 C 點坐標(biāo) xC_all(i) xB b*cos(theta2(i)); yC_all(i) yB b*sin(theta2(i)); % 搖桿角度DC 從 D 指向 C theta3(i) atan2(yC_all(i), xC_all(i) - d); end % 角速度數(shù)值微分 omega3 gradient(theta3, dt); % 繪制動畫 figure(Position, [100 100 950 430]); for i 1:N % 左圖機構(gòu)動畫 subplot(1, 2, 1); cla; hold on; axis equal; xlim([-0.15 0.55]); ylim([-0.35 0.35]); xB a*cos(theta1(i)); yB a*sin(theta1(i)); xC xC_all(i); yC yC_all(i); % 固定鉸 plot(0, 0, ko, MarkerFaceColor, k); plot(d, 0, ko, MarkerFaceColor, k); % 曲柄 AB plot([0 xB], [0 yB], b-o, LineWidth, 2); % 連桿 BC plot([xB xC], [yB yC], r-o, LineWidth, 2); % 搖桿 CD plot([d xC], [0 yC], g-o, LineWidth, 2); % C 點運動軌跡 plot(xC_all(1:i), yC_all(1:i), m., MarkerSize, 4); title(sprintf(t %.3f s, t(i))); xlabel(x (m)); ylabel(y (m)); % 右圖搖桿擺角和角速度 subplot(1, 2, 2); yyaxis left; plot(t(1:i), theta3(1:i)*180/pi, g-, LineWidth, 1.5); ylabel(搖桿擺角 (deg)); yyaxis right; plot(t(1:i), omega3(1:i), r--, LineWidth, 1.2); ylabel(搖桿角速度 (rad/s)); xlabel(時間 (s)); xlim([0 t(end)]); grid on; title(搖桿運動曲線); drawnow; frame getframe(gcf); im frame2im(frame); [imind, cm] rgb2ind(im, 256); if i 1 imwrite(imind, cm, four_bar.gif, gif, ... Loopcount, inf, DelayTime, 0.03); else imwrite(imind, cm, four_bar.gif, gif, ... WriteMode, append, DelayTime, 0.03); end end disp(動畫已保存為 four_bar.gif);5.3 運行結(jié)果與驗證運行后生成four_bar.gif。左圖是機構(gòu)動畫C 點會畫出一條閉合的連桿曲線這條曲線在機械原理中叫“連桿曲線”是四桿機構(gòu)最重要的輸出軌跡之一。右圖同時顯示搖桿擺角與搖桿角速度。驗證要點曲柄轉(zhuǎn)角從 0 到 360 度變化時搖桿擺動角度應(yīng)該是連續(xù)周期變化不會出現(xiàn)突變。搖桿角速度曲線在換向點附近接近 0符合實際物理規(guī)律。如果動畫在某幀突然翻轉(zhuǎn)說明裝配模式選擇邏輯失效應(yīng)檢查theta2_prev的初始值以及角度連續(xù)性判斷。這段代碼展示了一個重要思路當(dāng)位置方程不能直接顯式求解時先消元化成A*cos(theta2) B*sin(theta2) K的形式再求解。這個思路比直接調(diào)用fsolve更穩(wěn)定也不需要優(yōu)化工具箱適合零基礎(chǔ)復(fù)現(xiàn)。6. 通用 gif 輸出封裝與動畫繪制技巧前面兩個示例都重復(fù)了一段 gif 寫入代碼。在實際項目中建議封裝成獨立函數(shù)避免每個仿真腳本都復(fù)制一遍。保存為save_gif.mfunction save_gif(fig, filename, frame_idx, delay) % 將當(dāng)前 figure 保存為 gif % fig: figure 句柄 % filename: 輸出文件名 % frame_idx: 當(dāng)前幀序號第 1 幀創(chuàng)建文件后續(xù)幀追加 % delay: 幀間延遲單位秒 frame getframe(fig); im frame2im(frame); [imind, cm] rgb2ind(im, 256); if frame_idx 1 imwrite(imind, cm, filename, gif, ... Loopcount, inf, DelayTime, delay); else imwrite(imind, cm, filename, gif, ... WriteMode, append, DelayTime, delay); end end調(diào)用方式% 在動畫循環(huán)內(nèi) save_gif(gcf, my_sim.gif, i, 0.03);如果你的 Matlab 版本是 R2020a 及以上還可以使用更簡潔的exportgraphicsexportgraphics(gcf, my_sim.gif, Append, i ~ 1, Resolution, 100);兩種方式的區(qū)別方式版本要求優(yōu)點注意點getframe imwrite兼容舊版跨版本穩(wěn)定可精確控制 DelayTime需要先rgb2ind轉(zhuǎn)索引圖exportgraphicsR2020a代碼短分辨率高支持矢量格式追加模式依賴Append參數(shù)舊版不可用動畫繪制的幾個通用技巧每一幀都要固定xlim和ylim否則畫面會隨機構(gòu)位置縮放而抖動。axis equal要放在xlim之前避免坐標(biāo)軸比例失真。DelayTime適合設(shè)為 0.02 到 0.1 秒。太小時動畫閃動太大時看起來卡頓。如果一幀里既要畫機構(gòu)又要畫曲線優(yōu)先用subplot分開展示。7. 從四桿到五桿、六桿通用化建模思路7.1 五桿機構(gòu)自由度是關(guān)鍵純鉸鏈五桿機構(gòu)的自由度是 2因此嚴(yán)格意義上不能像四桿機構(gòu)那樣只給一個曲柄輸入就得到確定運動。實際工程中的單自由度五桿機構(gòu)通常通過以下方式實現(xiàn)引入一個移動副例如五桿加滑塊自由度降為 1。兩個輸入之間增加齒輪或帶傳動約束形成“齒輪五桿機構(gòu)”。讓兩個輸入保持固定比例關(guān)系例如曲柄同步旋轉(zhuǎn)。仿真這類機構(gòu)時閉合矢量方程仍然是核心只是未知角度從 2 個變成 3 個或更多需要把多個環(huán)路方程聯(lián)立成一個方程組再用牛頓-拉夫森迭代求解。7.2 六桿機構(gòu)的閉環(huán)拆分典型六桿機構(gòu)如瓦特六桿、史蒂芬森六桿通常由兩個閉環(huán)組成。求解策略有兩種順序求解先解第一個四桿環(huán)再把結(jié)果作為第二個環(huán)的已知條件。編程簡單但不是所有六桿都能拆成標(biāo)準(zhǔn)四桿。聯(lián)立求解把所有閉環(huán)的位置方程寫成F(X) 0的形式用牛頓迭代一次性求解所有未知角度。通用性強但需要給出合適的初值。聯(lián)立求解的偽代碼框架如下% 偽代碼多閉環(huán)牛頓-拉夫森迭代 % X 為未知角度向量例如 [theta2; theta3; theta5; theta6] % F(X) 為位置殘差向量每個閉環(huán)提供實部、虛部兩個方程 function X solve_mechanism(X0, params, tol) X X0; for k 1:100 F closed_loop_residual(X, params); J closed_loop_jacobian(X, params); dX J \ (-F); X X dX; if norm(dX) tol break; end end end這里的核心工作量在求 Jacobian。如果手動推導(dǎo)太繁瑣可以用 MATLAB 的符號工具箱生成 Jacobian 的解析表達(dá)式再轉(zhuǎn)成數(shù)值函數(shù)這是一條很實用的工程路徑。7.3 從四桿到六桿本質(zhì)沒有變四桿機構(gòu)用“已知一個角度求兩個角度”的消元法五桿、六桿用“已知若干輸入求多個未知角度”的牛頓迭代。數(shù)學(xué)形式從二維擴展到多維但思路一致列出閉環(huán)矢量方程實部虛部分別為等式解非線性方程組逐幀更新輸出動畫。這就是我在文章開頭說的“同一道題的三種變形”。8. 常見問題與排查方法仿真代碼跑不通時優(yōu)先看模型問題而不是語法問題。下面是連桿機構(gòu)仿真中最常見的幾類問題。問題現(xiàn)象可能原因排查方式解決方案gif 文件只有一幀循環(huán)里只在i1時寫入了 gif檢查else分支是否寫入了WriteMode,append后續(xù)幀必須使用追加模式寫入gif 動畫閃動或不流暢DelayTime太小或采樣點過少查看循環(huán)幀數(shù)和文件播放速度增加 N或調(diào)大DelayTime到 0.05 以上四桿機構(gòu)運行到某角度報錯不滿足 Grashof 條件或abs(K/R)1打印報錯前的角度檢查桿長調(diào)整桿長或讓機構(gòu)在可達(dá)范圍內(nèi)運動動畫中機構(gòu)出現(xiàn)翻轉(zhuǎn)跳變theta2選擇了另一個代數(shù)解觀察跳變發(fā)生位置檢查解選擇邏輯用上一幀角度比較取差值最小的解中文注釋亂碼文件編碼與編輯器編碼不一致檢查編輯器 Preference 中的編碼設(shè)置保存為 UTF-8或改用英文注釋矩陣維度不匹配用了向量整體運算又混入了標(biāo)量索引查看報錯行號檢查數(shù)組尺寸統(tǒng)一用theta(i)單點計算或整體向量計算動畫運行很慢每幀cla后重新創(chuàng)建圖形對象觀察 CPU 占用降低 N改用更新XData/YData