// SliderCrankMechanism.cpp #include "FourBarMechanism/SliderCrankMechanism.h" #include #include #include // ==================== MechanismParametersExt 实现 ==================== MechanismParametersExt::MechanismParametersExt() : CrankLength(1.0), ConnectingRodLength(3.0), SliderOffset(0.5), InputValue(0.0), AngularVelocity(1.0), SolutionMode(SolutionMode::Auto), CrankAngleRange1(0.0, 0.0), CrankAngleRange2(0.0, 0.0) {} // ==================== SliderCrankMechanism 实现 ==================== SliderCrankMechanism::SliderCrankMechanism() : name("曲柄滑块机构 (逆解)") { parameters.CrankLength = 1.0; parameters.ConnectingRodLength = 3.0; parameters.SliderOffset = 0.5; parameters.InputValue = 0.0; parameters.AngularVelocity = 1.0; parameters.SolutionMode = SolutionMode::Auto; } // 辅助方法 double SliderCrankMechanism::degreesToRadians(double degrees) const { return degrees * M_PI / 180.0; } double SliderCrankMechanism::radiansToDegrees(double radians) const { return radians * 180.0 / M_PI; } std::string SliderCrankMechanism::formatDouble(double value, int precision) const { char buffer[32]; snprintf(buffer, sizeof(buffer), "%.*f", precision, value); return std::string(buffer); } double SliderCrankMechanism::clamp(double value, double min, double max) const { if (value < min) return min; if (value > max) return max; return value; } // 基本属性访问 std::string SliderCrankMechanism::getName() const { return name; } MechanismType SliderCrankMechanism::getType() const { return MechanismType::CrankSlider; // 使用相同的机构类型 } MechanismParametersExt SliderCrankMechanism::getParameters() const { return parameters; } void SliderCrankMechanism::setName(const std::string &newName) { name = newName; } void SliderCrankMechanism::setParameters(const MechanismParametersExt ¶ms) { parameters = params; } void SliderCrankMechanism::setLink(double crankLength, double rodLength, double sliderOffset) { parameters.CrankLength = crankLength; parameters.ConnectingRodLength = rodLength; parameters.SliderOffset = sliderOffset; } void SliderCrankMechanism::setSolutionMode(SolutionMode mode) { parameters.SolutionMode = mode; } // 计算滑块范围 std::pair SliderCrankMechanism::calculateSliderRange() { double L1 = parameters.CrankLength; double L2 = parameters.ConnectingRodLength; double h = parameters.SliderOffset; // 检查Grashof条件 if ((L1 + L2) < std::abs(h)) return std::make_pair(0.0, 0.0); double maxX = 0.0; if ((L1 + L2) * (L1 + L2) > h * h) { maxX = std::sqrt((L1 + L2) * (L1 + L2) - h * h); } double minX = 0.0; if ((L2 - L1) * (L2 - L1) > h * h) { minX = std::sqrt((L2 - L1) * (L2 - L1) - h * h); } else { minX = -std::sqrt((L1 + L2) * (L1 + L2) - h * h); } // 计算曲柄角度范围 if ((L1 + L2) * (L1 + L2) > h * h) { double theta_max = M_PI - std::asin(h / (L1 + L2)); double theta_min; if ((L2 - L1) * (L2 - L1) > h * h) { theta_min = std::asin(h / (L1 + L2)); } else { theta_min = -M_PI + std::asin(h / (L1 + L2)); } parameters.CrankAngleRange1 = std::make_pair(theta_min, theta_max); parameters.CrankAngleRange2 = std::make_pair(-theta_max, -theta_min); } return std::make_pair(minX, maxX); } // 主要计算函数(逆解) MechanismState SliderCrankMechanism::calculate(double sliderX) { parameters.InputValue = sliderX; double crankLength = parameters.CrankLength; double rodLength = parameters.ConnectingRodLength; double sliderOffset = parameters.SliderOffset; auto solutionMode = parameters.SolutionMode; Vector2D A(0.0, 0.0); Vector2D S(sliderX, sliderOffset); MechanismState state; state.InputValue = sliderX; try { // 计算A到S的向量和距离 Vector2D AS_vec = S - A; double AS_distance = AS_vec.length(); // 检查机构是否可以装配 if (AS_distance > crankLength + rodLength || AS_distance < std::abs(crankLength - rodLength)) { state.ErrorMessage = "滑块位置 " + formatDouble(sliderX) + " 导致机构无法装配"; return state; } // 使用余弦定理计算角度 double cosTheta = (crankLength * crankLength + AS_distance * AS_distance - rodLength * rodLength) / (2.0 * crankLength * AS_distance); cosTheta = clamp(cosTheta, -1.0, 1.0); double theta = std::acos(cosTheta); // 计算基准角度 double alpha = std::atan2(AS_vec.Y, AS_vec.X); // 计算两个可能的解 double angle1 = alpha + theta; double angle2 = alpha - theta; Vector2D B1 = A + Vector2D( crankLength * std::cos(angle1), crankLength * std::sin(angle1)); Vector2D B2 = A + Vector2D( crankLength * std::cos(angle2), crankLength * std::sin(angle2)); Vector2D B, B_alt; // 默认选择解1 B = B1; B_alt = B2; // 根据解模式选择 if (solutionMode == SolutionMode::Solution2) { B = B2; B_alt = B1; } else if (solutionMode == SolutionMode::Auto) { if (!trajectoryB.empty()) { Vector2D lastB = trajectoryB.back(); double dist1 = Vector2D::Distance(B1, lastB); double dist2 = Vector2D::Distance(B2, lastB); if (dist2 < dist1) { B = B2; B_alt = B1; } } } // 记录轨迹 trajectoryB.push_back(B); trajectoryBAlt.push_back(B_alt); sliderTrajectory.push_back(S); // 限制轨迹点数量 const size_t MAX_TRAJECTORY_POINTS = 200; if (trajectoryB.size() > MAX_TRAJECTORY_POINTS) { trajectoryB.erase(trajectoryB.begin()); trajectoryBAlt.erase(trajectoryBAlt.begin()); sliderTrajectory.erase(sliderTrajectory.begin()); } // 计算角度 double crankAngle = std::atan2(B.Y, B.X) * 180.0 / M_PI; double crankAngleAlt = std::atan2(B_alt.Y, B_alt.X) * 180.0 / M_PI; // 检查机构是否可以装配 auto range = calculateSliderRange(); if (std::abs(range.first - range.second) < 1e-10) { state.WarningMessage = "警告:机构无法装配!(曲柄+连杆长度小于滑块偏移量)"; } // 设置状态 state.Points["A"] = A; state.Points["B"] = B; state.Points["B_alt"] = B_alt; state.Points["S"] = S; state.Poses["AB"] = PoseCalculator::CalculatePoseAndQuaternion(A, B); state.Poses["BS"] = PoseCalculator::CalculatePoseAndQuaternion(B, S); // TCP姿态(滑块处) Pose7 tcpPose; tcpPose.tx = S.X; tcpPose.ty = S.Y; tcpPose.tz = 0.0; tcpPose.qw = 1.0; state.Poses["TCP"] = tcpPose; // 角度信息 state.Angles["当前解角度"] = crankAngle; state.Angles["备选解角度"] = crankAngleAlt; state.Angles["滑块位置"] = sliderX; return state; } catch (const std::exception &ex) { state.ErrorMessage = std::string("计算失败: ") + ex.what(); return state; } } // 参数验证 ValidationResult SliderCrankMechanism::validateParameters() { ValidationResult result; if (parameters.CrankLength <= 0.0) { result.Errors.push_back("曲柄长度必须大于0"); } if (parameters.ConnectingRodLength <= 0.0) { result.Errors.push_back("连杆长度必须大于0"); } if (parameters.CrankLength + parameters.ConnectingRodLength <= std::abs(parameters.SliderOffset)) { result.Errors.push_back("不满足Grashof条件: 曲柄+连杆长度必须大于滑块偏移量的绝对值"); } return result; } // 获取输入范围 std::pair SliderCrankMechanism::getInputRange() { return calculateSliderRange(); } // 获取轨迹点 std::vector SliderCrankMechanism::getTrajectoryPoints() { return trajectoryB; } std::vector SliderCrankMechanism::getSliderTrajectory() const { return sliderTrajectory; } std::vector SliderCrankMechanism::getAlternativeTrajectory() const { return trajectoryBAlt; } // 清除轨迹 void SliderCrankMechanism::clearTrajectory() { trajectoryB.clear(); trajectoryBAlt.clear(); sliderTrajectory.clear(); } // 获取状态文本 std::string SliderCrankMechanism::getStatusText() { auto range = calculateSliderRange(); std::string status = name + "\n"; if (std::abs(range.first - range.second) < 1e-10) { status += "⚠️ 警告:机构无法装配!(曲柄+连杆长度小于滑块偏移量)\n"; } else { status += "曲柄=" + formatDouble(parameters.CrankLength) + "m, "; status += "连杆=" + formatDouble(parameters.ConnectingRodLength) + "m\n"; status += "偏移=" + formatDouble(parameters.SliderOffset) + "m\n"; status += "滑块范围: [" + formatDouble(range.first) + ", " + formatDouble(range.second) + "]m\n"; status += "行程: " + formatDouble(range.second - range.first) + "m\n"; status += "解1角度范围: [" + formatDouble(parameters.CrankAngleRange1.first * 180.0 / M_PI, 1) + "°, "; status += formatDouble(parameters.CrankAngleRange1.second * 180.0 / M_PI, 1) + "°]\n"; status += "解2角度范围: [" + formatDouble(parameters.CrankAngleRange2.first * 180.0 / M_PI, 1) + "°, "; status += formatDouble(parameters.CrankAngleRange2.second * 180.0 / M_PI, 1) + "°]"; } return status; } // ==================== 工厂函数实现 ==================== SliderCrankMechanism *createSliderCrankMechanism() { return new SliderCrankMechanism(); } void deleteSliderCrankMechanism(SliderCrankMechanism *mechanism) { delete mechanism; } SliderCrankMechanismPtr createSliderCrankMechanismSmart() { return std::make_shared(); }