多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

基于Matlab的凸轮设计与仿真:绘制多款凸轮轮廓曲线

基于Matlab的凸轮设计与仿真:绘制多款凸轮轮廓曲线 做机械设计、参加工训赛或者搞自动化产线的人应该都有过被凸轮支配的恐惧。基圆半径、压力角、滚子半径、偏距再加上推程、回程、远休止、近休止手工画轮廓又慢又容易错改一个参数就得全部重来。我最近把整套流程搬到 Matlab 里从运动规律计算、多款常见凸轮廓线绘制到压力角和曲率校核全部参数化写成了脚本。这篇就以“基于 Matlab 的凸轮设计与仿真绘制多款凸轮轮廓曲线”为题把从机械原理课本到可跑通代码的过程完整拆一遍适合正在做课程设计、准备竞赛或者需要在项目里快速出凸轮方案的朋友参考。先说结论如果你只是临时画一个凸轮用 CAD 敲点也行但如果你要反复调参数、对比多种从动件形式、验证轮廓是否可用那 Matlab 脚本能帮你把一晚上的手工作业压缩到几分钟。下面我按自己的设计流程来写从运动规律到四种凸轮轮廓再到仿真检查一步步来。1. 整体设计思路为什么凸轮设计可以完全参数化1.1 凸轮的本质一个“运动规律发生器”凸轮机构说白了就是一个把旋转运动变成预期往复运动的转换器。凸轮每转一圈从动件按你设定的规律完成“上升—停止—下降—停止”的动作。真正决定凸轮长什么样的不是凸轮本身而是从动件的位移曲线 S(δ)也就是从动件位移随凸轮转角的变化关系。这条位移曲线选什么形式直接决定了机构的动力学表现。比如低速轻载场合用等速运动规律就行因为加工简单、计算方便但速度一高等速规律在行程起点和终点会有无穷大的加速度突变也就是刚性冲击实际机构会出现明显振动和噪声。所以我做设计时永远先定运动规律再谈轮廓曲线这个顺序不能反。Matlab 的好处是只要把运动规律写成函数凸轮轮廓就跟着变想换规律只改一个参数。1.2 反转法把动态问题变成静态绘图问题凸轮转动时从动件一边上升一边和凸轮保持接触直接分析接触点轨迹很麻烦。机械原理课本里的反转法解决的就是这件事给整个机构加一个与凸轮角速度大小相等、方向相反的角速度凸轮就“静止”了从动件连同它的导路则绕着凸轮回转中心反向转动。这样从动件尖端的运动轨迹就是凸轮的理论轮廓曲线。这个方法听起来抽象但写代码时特别香因为它把动态接触问题转化成了纯几何坐标计算。我们在 Matlab 里只需要让凸轮转角 δ 从 0 扫到 2π每步都算出从动件尖端在反转后的坐标连成线就是轮廓。后面所有凸轮轮廓公式本质都是反转法的解析表达没有例外。1.3 脚本化设计的目标输参数出图纸既然核心就是“运动规律 反转法”那整个设计流程完全可以封装成参数化脚本。我的基本思路是用一组变量定义几何参数基圆半径、滚子半径、偏距、从动件行程、各运动角用分段函数计算任意转角下的位移、类速度 ds/dδ按不同的从动件形式套用对应的轮廓坐标公式绘制轮廓、基圆、偏距圆并叠加压力角、曲率半径校核最后加一个简单动画验证运动过程没有干涉。这样一套脚本放在那儿换个参数重新跑一遍所有图自动更新。我实际用下来最大的感受是手工画图时不敢轻易改基圆半径因为改一次就得重画一遍脚本化之后基圆半径从一个变量改起轮廓、压力角、曲率半径联动变化敢大胆寻优了。2. 核心数学基础运动规律和轮廓坐标方程2.1 四类常用运动规律及选型从动件运动规律我常用四类等速、等加速等减速、余弦加速度简谐运动、正弦加速度摆线运动。它们各自的位移公式差别很大速度和加速度特性也不同。运动规律位移表达式推程tδ/δ0速度特性加速度特性冲击类型适用场合等速s h·t恒定端点无穷大刚性冲击低速轻载等加速等减速前半2h·t²后半 h-2h(1-t)²连续端点及中点有限突变柔性冲击中速中载余弦加速度s h/2·(1-cos(πt))连续端点不为零有突变柔性冲击中高速正弦加速度s h·(t - sin(2πt)/(2π))连续端点为零处处连续无冲击高速实际项目中如果没有特殊要求我一般优先选正弦加速度因为它加速度曲线没有突变高速运行时振动最小只是最大加速度偏大对凸轮和从动件之间的接触应力要求高一些。低速场合用等速规律也完全可以但要注意推程回程拼接处必须用圆弧过渡否则轮廓会出现明显尖角。2.2 盘形凸轮廓线的三套基本公式有了位移 S(δ) 和类速度 dS/dδ轮廓坐标就有了统一框架。以凸轮逆时针转动、从动件导路竖直布置为例常用坐标公式如下。对心直动尖底从动件理论轮廓就是尖底轨迹x (r0 S)·cosδ y (r0 S)·sinδ对心直动滚子从动件理论轮廓同上但实际轮廓是理论轮廓的等距线dx/dδ -(r0S)·sinδ (dS/dδ)·cosδ dy/dδ (r0S)·cosδ (dS/dδ)·sinδ L sqrt((dx/dδ)² (dy/dδ)²) x_r x - rT·(dy/dδ) / L y_r y rT·(dx/dδ) / L这里取的是朝凸轮内侧的法向偏移所以是减号方向滚子圆半径 rT 沿法线方向“削”掉一圈得到的就是实际工作轮廓。偏置直动从动件需要先算初始接触点在导路方向上的投影距离s0 sqrt(r0² - e²) x e·cosδ (s0 S)·sinδ y (s0 S)·cosδ - e·sinδ其中 e 是偏距正负号决定了导路偏在回转中心的哪一侧。这个公式我推导时重点检查过 δ0 的初始位置计算结果和几何模型完全对得上。平底从动件的轮廓公式更特殊一点它是尖底理论轮廓沿圆周切向偏移一个类速度量得到的x (r0 S)·cosδ - (dS/dδ)·sinδ y (r0 S)·sinδ (dS/dδ)·cosδ因为平底从动件的接触点在平底上会随 dS/dδ 不断移动这个偏移量实际上就是接触点相对导路中心线的距离后面做平底长度校核时还要用到它。3. Matlab 实战一次生成四款凸轮廓线3.1 运动规律函数的封装我先写了一个局部运动规律计算函数 localMotion输入当前转角、行程段结构体和起始角输出相对位移和类速度。这样推程、回程、休止段都能复用代码结构非常清晰。function [s_local, ds_local] localMotion(delta, seg) % 计算某一行程段内的相对位移和类速度 ds/ddelta % delta: 当前凸轮转角 % seg: 行程段结构体含 start, stop, h, law, base t (delta - seg.start) / (seg.stop - seg.start); t min(max(t, 0), 1); % 防止边界溢出 switch seg.law case rest s_local 0; ds_local 0; case constant % 等速 s_local seg.h * t; ds_local seg.h / (seg.stop - seg.start); case parabolic % 等加速等减速 if t 0.5 s_local seg.h * 2 * t^2; ds_local seg.h * 4 * t / (seg.stop - seg.start); else s_local seg.h * (1 - 2 * (1 - t)^2); ds_local seg.h * 4 * (1 - t) / (seg.stop - seg.start); end case cosine % 余弦加速度 s_local seg.h / 2 * (1 - cos(pi * t)); ds_local seg.h * pi / (2 * (seg.stop - seg.start)) * sin(pi * t); case sine % 正弦加速度 s_local seg.h * (t - sin(2 * pi * t) / (2 * pi)); ds_local seg.h / (seg.stop - seg.start) * (1 - cos(2 * pi * t)); otherwise error(未知运动规律: %s, seg.law); end end注意回程段我把 h 设为负值这样同一套公式可以直接复用。比如推程 h30回程 h-30回程段的相对位移就会从 0 变到 -30叠加起始位移 30 后实际从动件位置就从 30 回到 0。这个“局部相对位移 段起始位移”的思路让代码里不再需要为回程单独写一套公式。3.2 主脚本参数、分段和位移计算主脚本里我用结构体数组把凸轮一转分成四段推程、远休止、回程、近休止。这样一眼就能看出工作循环的布局后续改角分配也非常方便。%% 基本参数 r0 50; % 基圆半径 mm rT 8; % 滚子半径 mm e 0; % 偏距 mm0为对心改12为偏置 h 30; % 从动件总行程 mm method sine; % 运动规律rest/constant/parabolic/cosine/sine %% 运动角分配弧度 deltaPush 120 * pi / 180; deltaHold 40 * pi / 180; deltaReturn 120 * pi / 180; deltaRest 80 * pi / 180; %% 构造四段行程 seg(1) struct(start, 0, stop, deltaPush, ... h, h, law, method, base, 0); seg(2) struct(start, deltaPush, stop, deltaPush deltaHold, ... h, 0, law, rest, base, h); seg(3) struct(start, deltaPush deltaHold, ... stop, deltaPush deltaHold deltaReturn, ... h, -h, law, method, base, h); seg(4) struct(start, deltaPush deltaHold deltaReturn, ... stop, 2 * pi, ... h, 0, law, rest, base, 0); %% 计算位移 S 和类速度 dS N 2000; delta linspace(0, 2 * pi, N); S zeros(N, 1); dS zeros(N, 1); for k 1:N for j 1:numel(seg) if delta(k) seg(j).start delta(k) seg(j).stop [s_local, ds_local] localMotion(delta(k), seg(j)); S(k) seg(j).base s_local; dS(k) ds_local; break; end end end我习惯把采样点 N 设到 2000 以上。点数太少轮廓在行程切换处会出现肉眼可见的折线感后面做动画时也不够顺滑。2000 个点在普通电脑上计算加绘图也就是零点几秒的事完全没必要省。3.3 对心尖底与滚子从动件凸轮对心直动从动件是最基础的结构理论廓线公式最直接。把 S 和 dS 代进轮廓坐标公式就能画出尖底理论轮廓再套等距线公式就是滚子的实际轮廓。%% 对心尖底理论轮廓 x_tip (r0 S) .* cos(delta); y_tip (r0 S) .* sin(delta); %% 对心滚子实际轮廓等距线 dx_tip -(r0 S) .* sin(delta) dS .* cos(delta); dy_tip (r0 S) .* cos(delta) dS .* sin(delta); L sqrt(dx_tip.^2 dy_tip.^2); x_roll x_tip - rT .* dy_tip ./ L; y_roll y_tip rT .* dx_tip ./ L; %% 绘图 figure(Color, w); plot(x_tip, y_tip, r--, LineWidth, 1.2); hold on; plot(x_roll, y_roll, b-, LineWidth, 2); th linspace(0, 2*pi, 200); plot(r0*cos(th), r0*sin(th), k:, LineWidth, 1); axis equal; grid on; legend(理论轮廓, 实际轮廓, 基圆, Location, best); title(对心直动滚子从动件盘形凸轮);这里有个容易踩坑的地方L 是理论轮廓切向量模长理论上不会为 0但如果基圆半径和偏距搭配不合理行程切换点附近可能出现极小值。我在写脚本时加过一行判断if min(L) 1e-6 warning(轮廓导数为零请检查基圆半径和运动规律); end这一行看起来简单却帮我避开了好几次程序崩溃。3.4 偏置直动从动件凸轮偏置的目的很明确通过让导路偏离回转中心把推程压力角压下来。但偏距方向不能拍脑袋定得遵守一个基本判断凸轮逆时针转动时导路应偏向凸轮回转中心的右侧凸轮顺时针转动时则偏向左侧。方向搞反压力角不减反增机构反而更吃力。偏置轮廓的初始位置计算要用 s0 sqrt(r0² - e²)而不是直接用 r0。这是很多初学者容易忽略的细节因为偏置后从动件最低位置时尖底并不在凸轮正上方而是在导路上与基圆相切的位置这个切点沿导路方向到回转中心的距离就是 s0。代码如下%% 偏置参数 e 12; % 偏距正值为导路偏右 %% 偏置直动从动件理论轮廓 s0 sqrt(r0^2 - e^2); x_offset e * cos(delta) (s0 S) .* sin(delta); y_offset (s0 S) .* cos(delta) - e * sin(delta); %% 偏置滚子实际轮廓 dx_off -e * sin(delta) (s0 S) .* cos(delta) dS .* sin(delta); dy_off -(s0 S) .* sin(delta) dS .* cos(delta) - e * cos(delta); L_off sqrt(dx_off.^2 dy_off.^2); x_off_roll x_offset - rT .* dy_off ./ L_off; y_off_roll y_offset rT .* dx_off ./ L_off;画图时我习惯把偏距圆也画进去也就是以回转中心为圆心、半径 e 的圆。滚子中心或者说从动件导路中心线始终与这个圆相切看动画时会非常直观。3.5 平底从动件凸轮平底从动件没有滚子实际工作面是凸轮轮廓与平底所有切线位置的包络。它的优势是接触面积大、承载能力强结构也简单但轮廓公式和前面不太一样。%% 平底从动件工作轮廓 x_flat (r0 S) .* cos(delta) - dS .* sin(delta); y_flat (r0 S) .* sin(delta) dS .* cos(delta); %% 绘制平底从动件凸轮 figure(Color, w); plot(x_flat, y_flat, b-, LineWidth, 2); hold on; plot(r0*cos(th), r0*sin(th), k:, LineWidth, 1); axis equal; grid on; title(平底从动件盘形凸轮轮廓);平底从动件有个额外要求平底必须有足够长度保证接触点始终落在平底范围内。接触点相对导路中心线的偏移量就是 |dS/dδ|所以平底总长至少要是最大 |dS/dδ| 的两倍再留 5 到 10 毫米的安全裕量。我一般直接这样算flatLen 2 * max(abs(dS)) 10; fprintf(平底最小长度建议%.1f mm\n, flatLen);接触点偏移量超出平底长度的时候凸轮会“啃”到平底边缘实际机构中就是异响和磨损这个校核不能省。4. 仿真验证与轮廓质量检查4.1 位移、速度曲线先验证运动规律轮廓画得再好运动规律错了也白搭所以我总是先画位移、类速度曲线确认分段拼接正确再去看轮廓。类速度曲线尤其能暴露问题如果推程终点类速度不为零说明运动规律在拼接处有速度跳变整个机构高速运行时会有冲击。画曲线就三行figure(Color, w); plot(delta*180/pi, S, b-, LineWidth, 1.5); hold on; plot(delta*180/pi, dS, r--, LineWidth, 1.2); xlabel(凸轮转角 δ(°)); ylabel(位移 s(mm) / 类速度 ds/dδ); legend(位移, 类速度); grid on;如果位移曲线在推程、回程之间平滑过渡类速度曲线连续且端点归零那运动规律基本没问题。用正弦加速度规律时类速度两端都会平滑归零看起来非常舒服。4.2 压力角校核基圆半径和偏距的取舍压力角是凸轮设计最重要的校核指标之一。直动从动件压力角公式为tanα |dS/dδ - e| / (s0 S) 偏置时 tanα |dS/dδ| / (r0 S) 对心时推荐控制在推程 30° 以内回程可以放宽到 70°80°。压力角太大从动件会在导路里卡死或严重磨损机构根本没法用。我在脚本里加了逐点压力角计算并把最大压力角打印出来alpha atan(abs(dS - e) ./ (s0 S)) * 180 / pi; fprintf(最大压力角%.2f°\n, max(alpha));实际调试中我发现压力角超限时最优先的手段是增大基圆半径 r0其次才是调整偏距 e。基圆半径增大会让轮廓整体外移压力角会明显下降但凸轮尺寸变大、转动惯量也随之增加需要在紧凑性和受力之间平衡。调基圆半径比改运动规律快得多往往改一个数就够。4.3 曲率半径检查滚子半径的“雷区”滚子从动件实际轮廓是理论轮廓的等距线如果理论轮廓某处曲率半径小于滚子半径实际轮廓会出现尖点甚至自交也就是“过切”加工出来直接废掉。所以必须计算理论轮廓的曲率半径 ρρ ((x² y²)^(3/2)) / |xy - yx|Matlab 实现需要二阶导数而我们的位移是解析函数二阶导可以解析求也可以数值差分。我在脚本里用的解析式加数值检查关键代码如下%% 数值差分求二阶导数用S和dS dx dx_tip; dy dy_tip; ddx gradient(dx, delta); ddy gradient(dy, delta); rho (dx.^2 dy.^2).^(1.5) ./ abs(dx .* ddy - dy .* ddx); minRho min(rho); fprintf(理论轮廓最小曲率半径%.2f mm\n, minRho);这里用的是 MATLAB 的 gradient 函数做数值差分步长足够密时精度够用。然后把最小曲率半径跟滚子半径比较一般要求 ρ_min 1.2rT否则就要减小滚子或增大基圆。检查结果我通常直接加进绘图标题里方便后续对比参数。4.4 动态验证让凸轮转起来静态轮廓没问题之后我会画一个简单动画把滚子圆或者平底贴着轮廓转一圈从动件同步上下运动确认整个周期内没有干涉。这个动画不追求高大上关键是让人眼确认运动过程正常。figure(Color, w); hold on; axis equal; grid on; plot(x_roll, y_roll, b-, LineWidth, 2); plot(r0*cos(th), r0*sin(th), k:, LineWidth, 1); h_roller rectangle(Curvature, [1 1], FaceColor, [0.9 0.8 0.2]); h_rod plot([0 0], [0 0], k-, LineWidth, 2); for k 1:60:N % 滚子中心位置 xc x_roll(k); yc y_roll(k); % 滚子圆 set(h_roller, Position, [xc-rT, yc-rT, 2*rT, 2*rT]); % 从动件推杆 set(h_rod, XData, [0 0], YData, [0, S(k)]); drawnow; pause(0.01); end这个动画看起来简单但实际效果很好特别是观察偏置凸轮在推程和回程时滚子与轮廓的接触位置变化能很快发现偏距方向是否正确。制作动画时我踩过一个坑如果坐标轴没有设置 axis equal凸轮会被拉成椭圆动态效果看起来像“变形”实际是显示比例问题不是轮廓算错了务必先加 axis equal。5. 常见问题与排查技巧实录5.1 问题速查表我自己反复跑这套脚本把最容易踩的几个问题整理成一个速查表给后来者避坑现象根本原因排查与解决实际轮廓出现尖点或自交理论轮廓曲率半径小于滚子半径减小 rT必要时同时增大 r0压力角超过 30°基圆半径太小或偏距方向不对增大 r0或把 e 改成相反符号位移曲线在拼接处速度突跳运动规律选择不当或分段范围重叠检查 stop/start 边界换用正弦加速度轮廓看着像被拉伸变形绘图时没有 axis equal加上 axis equal再保存图片程序报错L 出现 NaN基圆半径或偏距导致切向量模长为零检查 r0 动画卡顿且轮廓不光滑采样点 N 太少把 N 增大到 2000 以上平底从动件轮廓“咬边”平底长度不够接触点超出范围按 2×max(abs(dS))裕量 设计平底长度5.2 一个偏置方向装反的真实案例去年搭一个凸轮送料机构时我为了减小压力角给从动件加了 10mm 偏距但没注意转向把导路偏到了左侧。跑完脚本一看最大压力角从 32° 不减反增到 46°整个机构在软件里明显卡滞。后来翻出反转法重新推了一遍才想起来凸轮逆时针旋转时偏置方向要顺着推程的切向也就是右侧才能把推程压力角压下来。这个问题如果不做仿真光靠手工画图很难发现等样机加工出来再改就晚了这也是为什么我始终建议把压力角校核写进脚本每次改参数自动打印结果。5.3 等速规律导致的轮廓“折角”问题有一次我偷懒把运动规律设成 constant想着反正是低速机构。位移曲线倒是光滑但类速度曲线在推程起点和终点直接跳变导致轮廓在这些位置出现明显折角。用放大镜看轮廓局部折角处实际对应一个速度突变运行时滚子和凸轮的接触应力瞬间增大。后来我把推程和回程都换成了正弦加速度折角立刻消失机构在仿真里的噪声和振动也明显改善。这个经验告诉我们凸轮设计的功夫一半在运动规律选择上轮廓曲线只是运动规律的几何投影。5.4 滚子半径选大导致的自交轮廓滚子半径不是越大越好。我最初想把滚子做大一些提高耐磨性rT 取到 15mm基圆只有 40mm。脚本里最小曲率半径算出来只有 9mm明显小于滚子半径实际轮廓直接出现了自交环。用 plot 画出来之后交点清晰可见加工肯定报废。最后按 ρ_min 1.2rT 的反向约束把滚子半径降到 8mm基圆升到 50mm自交消除压力角也在允许范围内。所以我现在设计时一定先算出理论轮廓的最小曲率半径再决定滚子尺寸而不是反过来。结语一些实际调试的小体会整套脚本跑下来我最深的体会是用 Matlab 做凸轮设计真正省时间的不是“画图”这个动作而是参数联动检查和错误早发现。手工方法里改一次基圆半径意味着从压力角到轮廓全部重新来过脚本化之后这只是改一个变量几秒钟就能看到整套结果。另外一个实用小技巧把运动规律名称作为字符串参数传进去比如 method 字段写成 sine 或 constant这样对比不同运动规律对轮廓的影响只需改一行字特别适合课程设计和竞赛前期方案比选。如果你后续想继续深入可以往两个方向扩展一个是把 Simulink 的 Simscape 模型接进来用刚体动力学仿真验证加速度曲线和驱动力矩另一个是直接导出轮廓坐标到 CAD 软件用点坐标生成样条曲线出加工图纸。轮廓曲线算出来之后加工其实已经不是难题真正的设计难点始终都在运动规律选择、尺寸综合和参数校核这些前期环节上。
返回列表