| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012 |
- // 伺服驱动选型工具 - 核心计算逻辑
- class ServoSizer {
- constructor() {
- this.currentType = 'ballscrew';
- this.chart = null;
- // 确保在 DOM 完全加载后初始化
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', () => {
- this.init();
- });
- } else {
- this.init();
- }
- }
- init() {
- // 检查必要的 DOM 元素是否存在
- const requiredElements = [
- 'transmissionType', 'dynamicParameters', 'calculateBtn',
- 'resetBtn', 'exportBtn', 'resultsDisplay'
- ];
-
- for (const elementId of requiredElements) {
- if (!document.getElementById(elementId)) {
- console.error(`Required element #${elementId} not found`);
- return;
- }
- }
-
- this.bindEvents();
- this.updateParametersForm();
- this.loadDefaults();
- }
- bindEvents() {
- // 传动类型切换
- const transmissionSelect = document.getElementById('transmissionType');
- if (transmissionSelect) {
- transmissionSelect.addEventListener('change', (e) => {
- this.currentType = e.target.value;
- this.updateParametersForm();
- this.clearResults();
- });
- }
- // 计算按钮
- const calculateBtn = document.getElementById('calculateBtn');
- if (calculateBtn) {
- calculateBtn.addEventListener('click', () => {
- this.calculate();
- });
- }
- // 重置按钮
- const resetBtn = document.getElementById('resetBtn');
- if (resetBtn) {
- resetBtn.addEventListener('click', () => {
- this.resetForm();
- });
- }
- // 导出按钮
- const exportBtn = document.getElementById('exportBtn');
- if (exportBtn) {
- exportBtn.addEventListener('click', () => {
- this.exportResults();
- });
- }
- // 保存配置按钮
- const saveConfigBtn = document.getElementById('saveConfigBtn');
- if (saveConfigBtn) {
- saveConfigBtn.addEventListener('click', () => {
- this.saveConfiguration();
- });
- }
- // 加载配置按钮
- const loadConfigBtn = document.getElementById('loadConfigBtn');
- if (loadConfigBtn) {
- loadConfigBtn.addEventListener('click', () => {
- this.loadConfiguration();
- });
- }
- }
- validateInput(input) {
- const value = parseFloat(input.value);
- const min = parseFloat(input.min) || -Infinity;
- const max = parseFloat(input.max) || Infinity;
- const step = parseFloat(input.step) || 1;
-
- // 检查是否为空值
- if (input.value.trim() === '') {
- input.classList.add('error');
- this.showValidationMessage(input, '此字段为必填项');
- return false;
- }
-
- // 检查数值有效性
- if (isNaN(value)) {
- input.classList.add('error');
- this.showValidationMessage(input, '请输入有效数字');
- return false;
- }
-
- // 检查范围
- if (value < min || value > max) {
- input.classList.add('error');
- this.showValidationMessage(input, `值应在 ${min} 到 ${max} 之间`);
- return false;
- }
-
- // 检查步长(可选)
- if (step > 0 && Math.abs((value - min) % step) > 1e-10) {
- // 对于小数步长,允许一定的精度误差
- const roundedValue = Math.round(value / step) * step;
- if (Math.abs(value - roundedValue) > 1e-10) {
- input.classList.add('error');
- this.showValidationMessage(input, `值应为 ${step} 的倍数`);
- return false;
- }
- }
-
- input.classList.remove('error');
- this.hideValidationMessage(input);
- return true;
- }
- showValidationMessage(input, message) {
- // 移除现有的验证消息
- this.hideValidationMessage(input);
-
- // 创建验证消息元素
- const messageEl = document.createElement('div');
- messageEl.className = 'validation-message';
- messageEl.textContent = message;
- messageEl.style.cssText = `
- color: #e74c3c;
- font-size: 12px;
- margin-top: 5px;
- display: block;
- `;
-
- // 插入到输入框后面
- input.parentNode.insertBefore(messageEl, input.nextSibling);
- }
- hideValidationMessage(input) {
- const existingMessage = input.parentNode.querySelector('.validation-message');
- if (existingMessage) {
- existingMessage.remove();
- }
- }
- loadDefaults() {
- // 默认值已经在HTML中设置
- }
- // 获取特定传动类型的参数表单
- getParameterForm(type) {
- const forms = {
- ballscrew: `
- <h4>丝杠参数</h4>
- <div class="form-group">
- <label for="screwDiameter">丝杠直径 (mm):</label>
- <input type="number" id="screwDiameter" class="form-control" value="20" min="1" step="0.1">
- </div>
- <div class="form-group">
- <label for="screwLead">丝杠导程 (mm):</label>
- <input type="number" id="screwLead" class="form-control" value="5" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="travelDistance">行程距离 (mm):</label>
- <input type="number" id="travelDistance" class="form-control" value="500" min="1" step="1">
- </div>
- <div class="form-group">
- <label for="loadMass">负载质量 (kg):</label>
- <input type="number" id="loadMass" class="form-control" value="10" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="maxSpeed">最大速度 (mm/s):</label>
- <input type="number" id="maxSpeed" class="form-control" value="100" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="accelerationTime">加速时间 (s):</label>
- <input type="number" id="accelerationTime" class="form-control" value="0.5" min="0.01" step="0.01">
- </div>
- <div class="form-group">
- <label for="frictionCoeff">摩擦系数:</label>
- <input type="number" id="frictionCoeff" class="form-control" value="0.01" min="0" max="1" step="0.001">
- </div>
- <div class="form-group">
- <label for="efficiency">传动效率:</label>
- <input type="number" id="efficiency" class="form-control" value="0.9" min="0.1" max="1" step="0.01">
- </div>
- `,
- timingBelt: `
- <h4>同步带参数</h4>
- <div class="form-group">
- <label for="pulleyDiameter">滑轮直径 (mm):</label>
- <input type="number" id="pulleyDiameter" class="form-control" value="50" min="1" step="0.1">
- </div>
- <div class="form-group">
- <label for="loadMass">负载质量 (kg):</label>
- <input type="number" id="loadMass" class="form-control" value="5" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="maxSpeed">最大线速度 (mm/s):</label>
- <input type="number" id="maxSpeed" class="form-control" value="200" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="accelerationTime">加速时间 (s):</label>
- <input type="number" id="accelerationTime" class="form-control" value="0.3" min="0.01" step="0.01">
- </div>
- <div class="form-group">
- <label for="frictionCoeff">摩擦系数:</label>
- <input type="number" id="frictionCoeff" class="form-control" value="0.02" min="0" max="1" step="0.001">
- </div>
- <div class="form-group">
- <label for="efficiency">传动效率:</label>
- <input type="number" id="efficiency" class="form-control" value="0.95" min="0.1" max="1" step="0.01">
- </div>
- `,
- gearbox: `
- <h4>减速机参数</h4>
- <div class="form-group">
- <label for="gearRatio">减速比:</label>
- <input type="number" id="gearRatio" class="form-control" value="10" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="loadInertia">负载惯量 (kg·m²):</label>
- <input type="number" id="loadInertia" class="form-control" value="0.01" min="0.0001" step="0.0001">
- </div>
- <div class="form-group">
- <label for="loadTorque">负载转矩 (N·m):</label>
- <input type="number" id="loadTorque" class="form-control" value="5" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="maxSpeed">输出轴最大转速 (RPM):</label>
- <input type="number" id="maxSpeed" class="form-control" value="100" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="accelerationTime">加速时间 (s):</label>
- <input type="number" id="accelerationTime" class="form-control" value="0.2" min="0.01" step="0.01">
- </div>
- <div class="form-group">
- <label for="efficiency">传动效率:</label>
- <input type="number" id="efficiency" class="form-control" value="0.9" min="0.1" max="1" step="0.01">
- </div>
- `,
- rotaryTable: `
- <h4>转盘参数</h4>
- <div class="form-group">
- <label for="tableMass">转盘质量 (kg):</label>
- <input type="number" id="tableMass" class="form-control" value="20" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="tableRadius">转盘半径 (mm):</label>
- <input type="number" id="tableRadius" class="form-control" value="150" min="1" step="0.1">
- </div>
- <div class="form-group">
- <label for="maxSpeed">最大转速 (RPM):</label>
- <input type="number" id="maxSpeed" class="form-control" value="60" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="accelerationTime">加速时间 (s):</label>
- <input type="number" id="accelerationTime" class="form-control" value="1.0" min="0.01" step="0.01">
- </div>
- <div class="form-group">
- <label for="frictionCoeff">摩擦系数:</label>
- <input type="number" id="frictionCoeff" class="form-control" value="0.01" min="0" max="1" step="0.001">
- </div>
- <div class="form-group">
- <label for="efficiency">传动效率:</label>
- <input type="number" id="efficiency" class="form-control" value="0.95" min="0.1" max="1" step="0.01">
- </div>
- `,
- winder: `
- <h4>收放卷参数</h4>
- <div class="form-group">
- <label for="materialDensity">材料密度 (kg/m³):</label>
- <input type="number" id="materialDensity" class="form-control" value="7800" min="100" step="100">
- </div>
- <div class="form-group">
- <label for="materialWidth">材料宽度 (mm):</label>
- <input type="number" id="materialWidth" class="form-control" value="100" min="1" step="1">
- </div>
- <div class="form-group">
- <label for="initialDiameter">初始直径 (mm):</label>
- <input type="number" id="initialDiameter" class="form-control" value="50" min="1" step="0.1">
- </div>
- <div class="form-group">
- <label for="finalDiameter">最终直径 (mm):</label>
- <input type="number" id="finalDiameter" class="form-control" value="200" min="1" step="0.1">
- </div>
- <div class="form-group">
- <label for="lineSpeed">线速度 (mm/s):</label>
- <input type="number" id="lineSpeed" class="form-control" value="100" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="tension">张力 (N):</label>
- <input type="number" id="tension" class="form-control" value="50" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="accelerationTime">加速时间 (s):</label>
- <input type="number" id="accelerationTime" class="form-control" value="0.5" min="0.01" step="0.01">
- </div>
- <div class="form-group">
- <label for="efficiency">传动效率:</label>
- <input type="number" id="efficiency" class="form-control" value="0.85" min="0.1" max="1" step="0.01">
- </div>
- `,
- directDrive: `
- <h4>直接驱动参数</h4>
- <div class="form-group">
- <label for="loadInertia">负载惯量 (kg·m²):</label>
- <input type="number" id="loadInertia" class="form-control" value="0.005" min="0.0001" step="0.0001">
- </div>
- <div class="form-group">
- <label for="frictionTorque">摩擦转矩 (N·m):</label>
- <input type="number" id="frictionTorque" class="form-control" value="0.1" min="0.001" step="0.001">
- </div>
- <div class="form-group">
- <label for="maxSpeed">最大转速 (RPM):</label>
- <input type="number" id="maxSpeed" class="form-control" value="300" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="accelerationTime">加速时间 (s):</label>
- <input type="number" id="accelerationTime" class="form-control" value="0.1" min="0.01" step="0.01">
- </div>
- <!-- 直接驱动通常没有传动效率和摩擦系数,使用默认值 -->
- <input type="hidden" id="frictionCoeff" value="0.0">
- <input type="hidden" id="efficiency" value="1.0">
- `,
- combined: `
- <h4>组合传动参数</h4>
- <div class="form-group">
- <label for="primaryType">主要传动类型:</label>
- <select id="primaryType" class="form-control">
- <option value="ballscrew">丝杠</option>
- <option value="timingBelt">同步带</option>
- <option value="gearbox">减速机</option>
- </select>
- </div>
- <div class="form-group">
- <label for="secondaryType">次要传动类型:</label>
- <select id="secondaryType" class="form-control">
- <option value="gearbox">减速机</option>
- <option value="timingBelt">同步带</option>
- </select>
- </div>
- <div class="form-group">
- <label for="combinedLoadMass">组合负载质量 (kg):</label>
- <input type="number" id="combinedLoadMass" class="form-control" value="15" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="maxSpeed">最大速度:</label>
- <input type="number" id="maxSpeed" class="form-control" value="80" min="0.1" step="0.1">
- </div>
- <div class="form-group">
- <label for="accelerationTime">加速时间 (s):</label>
- <input type="number" id="accelerationTime" class="form-control" value="0.4" min="0.01" step="0.01">
- </div>
- <div class="form-group">
- <label for="frictionCoeff">摩擦系数:</label>
- <input type="number" id="frictionCoeff" class="form-control" value="0.015" min="0" max="1" step="0.001">
- </div>
- <div class="form-group">
- <label for="efficiency">传动效率:</label>
- <input type="number" id="efficiency" class="form-control" value="0.85" min="0.1" max="1" step="0.01">
- </div>
- `
- };
- return forms[type] || forms.ballscrew;
- }
- updateParametersForm() {
- const dynamicParams = document.getElementById('dynamicParameters');
- if (dynamicParams) {
- dynamicParams.innerHTML = this.getParameterForm(this.currentType);
-
- // 绑定输入验证
- document.querySelectorAll('#dynamicParameters input[type="number"]').forEach(input => {
- input.addEventListener('input', () => {
- this.validateInput(input);
- });
- });
- }
- }
- // 安全的数值计算函数
- safeNumber(value, defaultValue = 0) {
- const num = parseFloat(value);
- return isNaN(num) || !isFinite(num) ? defaultValue : num;
- }
- // 丝杠计算
- calculateBallScrew(params) {
- const {
- loadMass, screwDiameter, screwLead, frictionCoeff, efficiency,
- maxSpeed, accelerationTime, travelDistance
- } = params;
- // 转换为标准单位
- const lead = this.safeNumber(screwLead, 5) / 1000; // mm to m
- const diameter = this.safeNumber(screwDiameter, 20) / 1000; // mm to m
- const travel = this.safeNumber(travelDistance, 500) / 1000; // mm to m
- const mass = this.safeNumber(loadMass, 10);
- const speed = this.safeNumber(maxSpeed, 100);
- const accelTime = Math.max(this.safeNumber(accelerationTime, 0.5), 0.001); // 避免除零
- const friction = this.safeNumber(frictionCoeff, 0.01);
- const eff = Math.max(this.safeNumber(efficiency, 0.9), 0.01); // 避免除零
-
- // 1. 负载转矩计算
- const gravity = 9.81;
- const frictionForce = mass * gravity * friction;
- const frictionTorque = (frictionForce * diameter) / 2;
-
- // 推力转矩
- const thrustTorque = (mass * gravity * lead) / (2 * Math.PI);
- const totalTorque = (thrustTorque + frictionTorque) / eff;
-
- // 2. 转速计算
- const maxRpm = (speed * 60) / (lead * 1000); // mm/s to rpm
-
- // 3. 惯量计算
- // 丝杠惯量 (实心圆柱体)
- const screwInertia = (Math.PI * 7800 * Math.pow(diameter, 4) * travel) / 32;
- // 负载折算到电机轴的惯量
- const loadInertia = mass * Math.pow(lead / (2 * Math.PI), 2);
- const totalInertia = Math.max(screwInertia + loadInertia, 1e-6); // 避免零惯量
-
- // 4. 加速度转矩
- const angularAccel = (Math.max(maxRpm, 0) * 2 * Math.PI / 60) / accelTime;
- const accelTorque = totalInertia * angularAccel;
-
- // 5. 峰值转矩
- const peakTorque = totalTorque + accelTorque;
-
- // 6. 功率计算
- const power = (Math.max(peakTorque, 0) * Math.max(maxRpm, 0) * 2 * Math.PI) / 60;
-
- return {
- speedRange: { min: 0, max: Math.max(maxRpm, 0) },
- torque: { continuous: Math.max(totalTorque, 0), peak: Math.max(peakTorque, 0) },
- inertia: { motor: 0.001, load: totalInertia, ratio: totalInertia / 0.001 },
- power: { required: Math.max(power, 0), rated: Math.max(power, 0) * 1.2 }
- };
- }
- // 同步带计算
- calculateTimingBelt(params) {
- const {
- loadMass, pulleyDiameter, frictionCoeff, efficiency,
- maxSpeed, accelerationTime
- } = params;
- const radius = this.safeNumber(pulleyDiameter, 50) / 2000; // mm to m
- const mass = this.safeNumber(loadMass, 5);
- const speed = this.safeNumber(maxSpeed, 200);
- const accelTime = Math.max(this.safeNumber(accelerationTime, 0.3), 0.001);
- const friction = this.safeNumber(frictionCoeff, 0.01);
- const eff = Math.max(this.safeNumber(efficiency, 0.9), 0.01);
-
- // 负载转矩
- const gravity = 9.81;
- const frictionForce = mass * gravity * friction;
- const loadTorque = (mass * gravity * radius + frictionForce * radius) / eff;
-
- // 转速
- const maxRpm = (speed * 60) / (Math.PI * this.safeNumber(pulleyDiameter, 50));
-
- // 惯量计算 - 更精确的模型
- // 滑轮惯量 (实心圆柱) - 假设滑轮材料为铝(密度2700 kg/m³),厚度5mm
- const pulleyThickness = 0.005; // 5mm
- const pulleyDensity = 2700; // 铝的密度 kg/m³
- const pulleyVolume = Math.PI * Math.pow(radius, 2) * pulleyThickness;
- const pulleyMass = pulleyDensity * pulleyVolume;
- const pulleyInertia = 0.5 * pulleyMass * Math.pow(radius, 2);
-
- // 负载惯量
- const loadInertia = mass * Math.pow(radius, 2);
- const totalInertia = Math.max(pulleyInertia + loadInertia, 1e-6);
-
- // 加速度转矩
- const angularAccel = (Math.max(maxRpm, 0) * 2 * Math.PI / 60) / accelTime;
- const accelTorque = totalInertia * angularAccel;
-
- const peakTorque = loadTorque + accelTorque;
- const power = (Math.max(peakTorque, 0) * Math.max(maxRpm, 0) * 2 * Math.PI) / 60;
-
- return {
- speedRange: { min: 0, max: Math.max(maxRpm, 0) },
- torque: { continuous: Math.max(loadTorque, 0), peak: Math.max(peakTorque, 0) },
- inertia: { motor: 0.001, load: totalInertia, ratio: totalInertia / 0.001 },
- power: { required: Math.max(power, 0), rated: Math.max(power, 0) * 1.2 }
- };
- }
- // 减速机计算
- calculateGearbox(params) {
- const {
- loadInertia, loadTorque, gearRatio, efficiency,
- maxSpeed, accelerationTime
- } = params;
- const inertia = this.safeNumber(loadInertia, 0.01);
- const torque = this.safeNumber(loadTorque, 5);
- const ratio = Math.max(this.safeNumber(gearRatio, 10), 0.01);
- const eff = Math.max(this.safeNumber(efficiency, 0.9), 0.01);
- const speed = this.safeNumber(maxSpeed, 100);
- const accelTime = Math.max(this.safeNumber(accelerationTime, 0.2), 0.001);
-
- // 折算到电机侧
- const reflectedInertia = inertia / Math.pow(ratio, 2);
- const reflectedTorque = torque / (ratio * eff);
-
- // 电机转速
- const motorRpm = speed * ratio;
-
- // 加速度转矩
- const angularAccel = (Math.max(motorRpm, 0) * 2 * Math.PI / 60) / accelTime;
- const accelTorque = Math.max(reflectedInertia, 1e-6) * angularAccel;
-
- const peakTorque = reflectedTorque + accelTorque;
- const power = (Math.max(peakTorque, 0) * Math.max(motorRpm, 0) * 2 * Math.PI) / 60;
-
- return {
- speedRange: { min: 0, max: Math.max(motorRpm, 0) },
- torque: { continuous: Math.max(reflectedTorque, 0), peak: Math.max(peakTorque, 0) },
- inertia: { motor: 0.001, load: Math.max(reflectedInertia, 1e-6), ratio: Math.max(reflectedInertia, 1e-6) / 0.001 },
- power: { required: Math.max(power, 0), rated: Math.max(power, 0) * 1.2 }
- };
- }
- // 转盘计算
- calculateRotaryTable(params) {
- const {
- tableMass, tableRadius, frictionCoeff, efficiency,
- maxSpeed, accelerationTime
- } = params;
- const mass = this.safeNumber(tableMass, 20);
- const radius = this.safeNumber(tableRadius, 150) / 1000; // mm to m
- const friction = this.safeNumber(frictionCoeff, 0.01);
- const eff = Math.max(this.safeNumber(efficiency, 0.9), 0.01);
- const speed = this.safeNumber(maxSpeed, 60);
- const accelTime = Math.max(this.safeNumber(accelerationTime, 1.0), 0.001);
-
- // 转盘惯量 (实心圆盘)
- const tableInertia = 0.5 * mass * Math.pow(radius, 2);
-
- // 摩擦转矩
- const gravity = 9.81;
- const frictionTorque = mass * gravity * friction * radius;
-
- // 转速
- const maxRpm = speed;
-
- // 加速度转矩
- const angularAccel = (Math.max(maxRpm, 0) * 2 * Math.PI / 60) / accelTime;
- const accelTorque = Math.max(tableInertia, 1e-6) * angularAccel;
-
- const peakTorque = (frictionTorque + accelTorque) / eff;
- const power = (Math.max(peakTorque, 0) * Math.max(maxRpm, 0) * 2 * Math.PI) / 60;
-
- return {
- speedRange: { min: 0, max: Math.max(maxRpm, 0) },
- torque: { continuous: Math.max(frictionTorque / eff, 0), peak: Math.max(peakTorque, 0) },
- inertia: { motor: 0.001, load: Math.max(tableInertia, 1e-6), ratio: Math.max(tableInertia, 1e-6) / 0.001 },
- power: { required: Math.max(power, 0), rated: Math.max(power, 0) * 1.2 }
- };
- }
- // 收放卷计算
- calculateWinder(params) {
- const {
- materialDensity, materialWidth, initialDiameter, finalDiameter,
- lineSpeed, tension, accelerationTime
- } = params;
- const density = this.safeNumber(materialDensity, 7800);
- const width = this.safeNumber(materialWidth, 100) / 1000;
- const initialRadius = this.safeNumber(initialDiameter, 50) / 2000; // mm to m
- const finalRadius = this.safeNumber(finalDiameter, 200) / 2000;
- const speed = this.safeNumber(lineSpeed, 100);
- const tensionVal = this.safeNumber(tension, 50);
- const accelTime = Math.max(this.safeNumber(accelerationTime, 0.5), 0.001);
-
- // 卷筒惯量 (空心圆柱)
- const finalMass = density * Math.PI * (Math.pow(finalRadius, 2) - Math.pow(initialRadius, 2)) * width;
- const finalInertia = 0.5 * Math.max(finalMass, 0.001) * (Math.pow(finalRadius, 2) + Math.pow(initialRadius, 2));
-
- // 张力转矩
- const tensionTorque = tensionVal * finalRadius;
-
- // 转速范围
- const minRpm = (speed * 60) / (Math.PI * this.safeNumber(finalDiameter, 200));
- const maxRpm = (speed * 60) / (Math.PI * this.safeNumber(initialDiameter, 50));
-
- // 加速度转矩 (使用最大惯量)
- const angularAccel = (Math.max(maxRpm, 0) * 2 * Math.PI / 60) / accelTime;
- const accelTorque = Math.max(finalInertia, 1e-6) * angularAccel;
-
- const peakTorque = tensionTorque + accelTorque;
- const power = (Math.max(peakTorque, 0) * Math.max(maxRpm, 0) * 2 * Math.PI) / 60;
-
- return {
- speedRange: { min: Math.max(minRpm, 0), max: Math.max(maxRpm, 0) },
- torque: { continuous: Math.max(tensionTorque, 0), peak: Math.max(peakTorque, 0) },
- inertia: { motor: 0.001, load: Math.max(finalInertia, 1e-6), ratio: Math.max(finalInertia, 1e-6) / 0.001 },
- power: { required: Math.max(power, 0), rated: Math.max(power, 0) * 1.2 }
- };
- }
- // 直接驱动计算
- calculateDirectDrive(params) {
- const {
- loadInertia, frictionTorque, maxSpeed, accelerationTime
- } = params;
- const inertia = this.safeNumber(loadInertia, 0.005);
- const friction = this.safeNumber(frictionTorque, 0.1);
- const speed = this.safeNumber(maxSpeed, 300);
- const accelTime = Math.max(this.safeNumber(accelerationTime, 0.1), 0.001);
-
- // 直接驱动,无传动比
- const motorRpm = speed;
-
- // 加速度转矩
- const angularAccel = (Math.max(motorRpm, 0) * 2 * Math.PI / 60) / accelTime;
- const accelTorque = Math.max(inertia, 1e-6) * angularAccel;
-
- const peakTorque = friction + accelTorque;
- const power = (Math.max(peakTorque, 0) * Math.max(motorRpm, 0) * 2 * Math.PI) / 60;
-
- return {
- speedRange: { min: 0, max: Math.max(motorRpm, 0) },
- torque: { continuous: Math.max(friction, 0), peak: Math.max(peakTorque, 0) },
- inertia: { motor: 0.001, load: Math.max(inertia, 1e-6), ratio: Math.max(inertia, 1e-6) / 0.001 },
- power: { required: Math.max(power, 0), rated: Math.max(power, 0) * 1.2 }
- };
- }
- // 组合传动计算(简化版)
- calculateCombined(params) {
- const {
- combinedLoadMass, maxSpeed, accelerationTime, frictionCoeff, efficiency
- } = params;
- const mass = this.safeNumber(combinedLoadMass, 15);
- const speed = this.safeNumber(maxSpeed, 80);
- const accelTime = Math.max(this.safeNumber(accelerationTime, 0.4), 0.001);
- const friction = this.safeNumber(frictionCoeff, 0.01);
- const eff = Math.max(this.safeNumber(efficiency, 0.9), 0.01);
- const gravity = 9.81;
- const loadTorque = mass * gravity * 0.1; // 简化假设
- const maxRpm = speed;
-
- const loadInertia = mass * 0.01; // 简化假设
- const angularAccel = (Math.max(maxRpm, 0) * 2 * Math.PI / 60) / accelTime;
- const accelTorque = Math.max(loadInertia, 1e-6) * angularAccel;
-
- const continuousTorque = loadTorque / eff;
- const peakTorque = (loadTorque + accelTorque) / eff;
- const power = (Math.max(peakTorque, 0) * Math.max(maxRpm, 0) * 2 * Math.PI) / 60;
-
- return {
- speedRange: { min: 0, max: Math.max(maxRpm, 0) },
- torque: { continuous: Math.max(continuousTorque, 0), peak: Math.max(peakTorque, 0) },
- inertia: { motor: 0.001, load: Math.max(loadInertia, 1e-6), ratio: Math.max(loadInertia, 1e-6) / 0.001 },
- power: { required: Math.max(power, 0), rated: Math.max(power, 0) * 1.2 }
- };
- }
- getFormValues() {
- const values = {};
-
- // 获取所有输入值
- document.querySelectorAll('#dynamicParameters input, #dynamicParameters select').forEach(input => {
- const id = input.id;
- if (input.type === 'number') {
- values[id] = this.safeNumber(input.value, 0);
- } else {
- values[id] = input.value;
- }
- });
-
- // 获取通用参数
- const safetyFactorEl = document.getElementById('safetyFactor');
- const inertiaRatioEl = document.getElementById('inertiaRatio');
-
- if (safetyFactorEl) values.safetyFactor = this.safeNumber(safetyFactorEl.value, 1.5);
- if (inertiaRatioEl) values.inertiaRatio = this.safeNumber(inertiaRatioEl.value, 10);
-
- return values;
- }
- calculate() {
- const params = this.getFormValues();
-
- // 验证所有输入
- let isValid = true;
- document.querySelectorAll('input[type="number"]').forEach(input => {
- if (!this.validateInput(input)) {
- isValid = false;
- }
- });
-
- if (!isValid) {
- this.showAlert('请检查输入参数是否有效', 'error');
- return;
- }
-
- let results;
- try {
- switch (this.currentType) {
- case 'ballscrew':
- results = this.calculateBallScrew(params);
- break;
- case 'timingBelt':
- results = this.calculateTimingBelt(params);
- break;
- case 'gearbox':
- results = this.calculateGearbox(params);
- break;
- case 'rotaryTable':
- results = this.calculateRotaryTable(params);
- break;
- case 'winder':
- results = this.calculateWinder(params);
- break;
- case 'directDrive':
- results = this.calculateDirectDrive(params);
- break;
- case 'combined':
- results = this.calculateCombined(params);
- break;
- default:
- throw new Error('未知的传动类型');
- }
-
- // 应用安全系数
- results.torque.continuous *= params.safetyFactor;
- results.torque.peak *= params.safetyFactor;
- results.power.rated *= params.safetyFactor;
-
- // 检查惯量比警告
- const inertiaWarning = results.inertia.ratio > params.inertiaRatio;
-
- this.displayResults(results, inertiaWarning);
- this.updateChart(results);
- this.showAlert('计算完成!', 'success');
-
- } catch (error) {
- console.error('计算错误:', error);
- this.showAlert('计算出错: ' + error.message, 'error');
- }
- }
- displayResults(results, inertiaWarning) {
- const resultsDiv = document.getElementById('resultsDisplay');
- const warningDiv = document.getElementById('warningMessage');
- const errorDiv = document.getElementById('errorMessage');
-
- if (!resultsDiv) return;
-
- // 隐藏错误消息
- if (errorDiv) errorDiv.classList.add('hidden');
-
- resultsDiv.innerHTML = `
- <div class="results-grid">
- <div class="result-card">
- <div class="result-label">转速范围 (RPM)</div>
- <div class="result-value">${results.speedRange.min.toFixed(1)} - ${results.speedRange.max.toFixed(1)}</div>
- </div>
- <div class="result-card">
- <div class="result-label">连续转矩 (N·m)</div>
- <div class="result-value">${results.torque.continuous.toFixed(3)}</div>
- </div>
- <div class="result-card">
- <div class="result-label">峰值转矩 (N·m)</div>
- <div class="result-value">${results.torque.peak.toFixed(3)}</div>
- </div>
- <div class="result-card">
- <div class="result-label">负载惯量 (kg·m²)</div>
- <div class="result-value">${results.inertia.load.toExponential(3)}</div>
- </div>
- <div class="result-card">
- <div class="result-label">惯量比</div>
- <div class="result-value">${results.inertia.ratio.toFixed(1)}</div>
- </div>
- <div class="result-card">
- <div class="result-label">额定功率 (W)</div>
- <div class="result-value">${results.power.rated.toFixed(1)}</div>
- </div>
- </div>
- `;
-
- // 显示惯量比警告
- if (warningDiv) {
- if (inertiaWarning) {
- warningDiv.textContent = `⚠️ 警告:惯量比 (${results.inertia.ratio.toFixed(1)}) 超过允许值,建议选择更大惯量的电机或添加减速机。`;
- warningDiv.classList.remove('hidden');
- } else {
- warningDiv.classList.add('hidden');
- }
- }
-
- const resultsCard = document.getElementById('resultsCard');
- if (resultsCard) resultsCard.style.display = 'block';
- }
- updateChart(results) {
- const chartCanvas = document.getElementById('performanceChart');
- if (!chartCanvas) return;
-
- // 检查 Chart.js 是否可用
- if (typeof Chart === 'undefined') {
- console.warn('Chart.js not loaded, skipping chart rendering');
- return;
- }
-
- const ctx = chartCanvas.getContext('2d');
-
- // 销毁现有图表
- if (this.chart) {
- this.chart.destroy();
- }
-
- // 创建新图表
- this.chart = new Chart(ctx, {
- type: 'bar',
- data: {
- labels: ['连续转矩', '峰值转矩', '额定功率'],
- datasets: [{
- label: '性能指标',
- data: [
- results.torque.continuous,
- results.torque.peak,
- results.power.rated
- ],
- backgroundColor: [
- 'rgba(54, 162, 235, 0.8)',
- 'rgba(255, 99, 132, 0.8)',
- 'rgba(75, 192, 192, 0.8)'
- ],
- borderColor: [
- 'rgba(54, 162, 235, 1)',
- 'rgba(255, 99, 132, 1)',
- 'rgba(75, 192, 192, 1)'
- ],
- borderWidth: 1
- }]
- },
- options: {
- responsive: true,
- maintainAspectRatio: false,
- scales: {
- y: {
- beginAtZero: true,
- title: {
- display: true,
- text: '数值'
- }
- }
- },
- plugins: {
- legend: {
- display: false
- },
- tooltip: {
- callbacks: {
- label: function(context) {
- let label = context.dataset.label || '';
- if (label) {
- label += ': ';
- }
- if (context.parsed.y !== null) {
- label += context.parsed.y.toFixed(3);
- if (context.dataIndex === 2) {
- label += ' W';
- } else {
- label += ' N·m';
- }
- }
- return label;
- }
- }
- }
- }
- }
- });
- }
- clearResults() {
- const resultsDiv = document.getElementById('resultsDisplay');
- const warningDiv = document.getElementById('warningMessage');
- const errorDiv = document.getElementById('errorMessage');
-
- if (resultsDiv) {
- resultsDiv.innerHTML = '<p class="placeholder">请输入参数并点击计算获取结果</p>';
- }
- if (warningDiv) warningDiv.classList.add('hidden');
- if (errorDiv) errorDiv.classList.add('hidden');
-
- // 销毁图表
- if (this.chart) {
- this.chart.destroy();
- this.chart = null;
- }
- }
- resetForm() {
- // 重置所有输入框
- document.querySelectorAll('input[type="number"]').forEach(input => {
- input.value = input.defaultValue || '';
- input.classList.remove('error');
- });
-
- // 重置选择框
- const transmissionSelect = document.getElementById('transmissionType');
- if (transmissionSelect) {
- transmissionSelect.selectedIndex = 0;
- this.currentType = 'ballscrew';
- this.updateParametersForm();
- }
-
- this.clearResults();
- this.showAlert('表单已重置', 'info');
- }
- exportResults() {
- const resultsDiv = document.getElementById('resultsDisplay');
- if (!resultsDiv || resultsDiv.querySelector('.placeholder')) {
- this.showAlert('请先进行计算', 'warning');
- return;
- }
-
- const resultsText = resultsDiv.innerText;
- const blob = new Blob([resultsText], { type: 'text/plain' });
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `servo_sizing_results_${new Date().toISOString().slice(0, 10)}.txt`;
- document.body.appendChild(a);
- a.click();
- document.body.removeChild(a);
- URL.revokeObjectURL(url);
-
- this.showAlert('结果已导出', 'success');
- }
- showAlert(message, type = 'info') {
- const alertContainer = document.getElementById('alertContainer');
- if (!alertContainer) return;
-
- const alertDiv = document.createElement('div');
- alertDiv.className = `alert alert-${type}`;
- alertDiv.textContent = message;
- alertContainer.appendChild(alertDiv);
-
- setTimeout(() => {
- alertDiv.remove();
- }, 3000);
- }
- }
- // 主题切换功能
- function toggleTheme() {
- const body = document.body;
- const themeToggle = document.getElementById('themeToggle');
-
- if (body.classList.contains('dark-mode')) {
- body.classList.remove('dark-mode');
- localStorage.setItem('theme', 'light');
- themeToggle.innerHTML = '<span class="theme-icon">🌙</span>';
- } else {
- body.classList.add('dark-mode');
- localStorage.setItem('theme', 'dark');
- themeToggle.innerHTML = '<span class="theme-icon">☀️</span>';
- }
- }
- // 初始化主题
- function initTheme() {
- const savedTheme = localStorage.getItem('theme') || 'light';
- const body = document.body;
- const themeToggle = document.getElementById('themeToggle');
-
- if (savedTheme === 'dark') {
- body.classList.add('dark-mode');
- if (themeToggle) themeToggle.innerHTML = '<span class="theme-icon">☀️</span>';
- } else {
- body.classList.remove('dark-mode');
- if (themeToggle) themeToggle.innerHTML = '<span class="theme-icon">🌙</span>';
- }
- }
- // 初始化应用 - 确保在 DOM 加载完成后执行
- document.addEventListener('DOMContentLoaded', () => {
- new ServoSizer();
- initTheme();
-
- // 绑定主题切换按钮事件
- const themeToggle = document.getElementById('themeToggle');
- if (themeToggle) {
- themeToggle.addEventListener('click', toggleTheme);
- }
- });
|