You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ Raylib双摆模拟器角加速度方程实现故障咨询

双摆模拟器角加速度方程实现问题修复

核心问题分析

你的双摆模拟失效主要源于三个关键错误:

  1. 角度单位混用
    初始输入的角度是度数,setAngle()会将其转成弧度存入pAngle,但循环中你直接用uAngle1 += angularV1(angularV1是弧度/秒单位),随后又调用setAngle(uAngle1)将混合单位的数值再次转成弧度,导致角度数值异常放大,完全偏离真实物理状态。

  2. 缺失时间步长控制
    物理模拟中,角加速度(弧度/秒²)和角速度(弧度/秒)的更新必须乘以每帧的时间间隔(dt),否则相当于假设每帧时长为1秒,运动速度和加速度会极度失真。你当前直接累加数值,未考虑帧率波动带来的时间差异。

  3. 角加速度方程符号偏差
    第二个角加速度方程的分子部分,因坐标系的细微差异,g(m1+m2)cosθ1的符号应为负,你当前的正号会导致受力方向错误。

修复方案

1. 统一角度单位(全程用弧度)

  • 初始输入角度后,直接转成弧度存储,不再依赖setAngle()的度数转弧度逻辑:
    // 初始角度处理
    uAngle1 *= DEG2RAD;
    uAngle2 *= DEG2RAD;
    pen1.pAngle = uAngle1;
    pen2.pAngle = uAngle2;
    
  • 循环中直接更新弧度值,不再调用setAngle()避免重复转换:
    uAngle1 += angularV1 * dt;
    angularV1 += angularA1 * dt;
    pen1.pAngle = uAngle1;
    

2. 添加时间步长控制

每次循环获取当前帧的时间间隔,用于物理量更新:

float dt = GetFrameTime();

3. 修正角加速度方程符号

第二个角加速度的num3改为负号:

num3 = -g * (pen1.getMass() + pen2.getMass()) * cos(pen1.getAngle());

完整修正后的main.cpp关键片段

// 初始角度处理(替换原setAngle调用)
uAngle1 *= DEG2RAD;
uAngle2 *= DEG2RAD;
pen1.setMass(uMass1);
pen1.setLength(uLength1);
pen1.pAngle = uAngle1;
pen1.setX(pen1.pLength, pen1.getAngle());
pen1.setY(pen1.pLength, pen1.getAngle());

pen2.setMass(uMass2);
pen2.setLength(uLength2);
pen2.pAngle = uAngle2;
pen2.setX(pen2.pLength, pen2.getAngle());
pen2.setY(pen2.pLength, pen2.getAngle());
pen2.x = pen1.getX() + pen2.getX();
pen2.y = pen1.getY() + pen2.getY();

// 主循环内
while (!WindowShouldClose()) {
    float dt = GetFrameTime(); // 获取时间步长
    Vector2 rod1{px1,py1};
    Vector2 rod2 {px2, py2};

    // 摆1角加速度计算(原逻辑正确,保留)
    float num1 = -g * (2 * pen1.getMass() + pen2.getMass()) * sin(pen1.getAngle());
    float num2 = -pen2.getMass() * g * sin(pen1.getAngle() - 2 * pen2.getAngle());
    float num3 = -2 * sin(pen1.getAngle() - pen2.getAngle()) * pen2.getMass();
    float num4 = pow(angularV2, 2) * pen2.getLength() + pow(angularV1,2) * pen1.getLength() * cos(pen1.getAngle() - pen2.getAngle());
    float den1 = pen1.getLength() * (2*pen1.getMass() + pen2.getMass() - pen2.getMass() * cos(2*pen1.getAngle() - 2 * pen2.getAngle()));
    float angularA1 = (num1 + num2 + num3*num4) / den1;

    // 摆2角加速度计算(修正num3符号)
    num1 = 2 * sin(pen1.getAngle() - pen2.getAngle());
    num2 = (pow(angularV1,2.0) * pen1.getLength() * (pen1.getMass() + pen2.getMass()));
    num3 = -g * (pen1.getMass() + pen2.getMass()) * cos(pen1.getAngle()); // 这里改负号
    num4 = pow(angularV2,2.0) * pen2.getLength() * pen2.getMass() * cos(pen1.getAngle() - pen2.getAngle());
    den1 = pen2.getLength() * (2*pen1.getMass() + pen2.getMass() - pen2.getMass() * cos(2*pen1.getAngle() - 2*pen2.getAngle()));
    float angularA2 = (num1 * (num2 + num3 + num4)) / den1;

    // 更新部分(添加dt,修正角度赋值)
    frameCounter++;
    uAngle1 += angularV1 * dt;
    angularV1 += angularA1 * dt;
    pen1.pAngle = uAngle1; // 直接赋值弧度,不再调用setAngle
    pen1.setX(pen1.pLength, pen1.getAngle());
    pen1.setY(pen1.pLength, pen1.getAngle());
    px1 = pen1.getX() + origin.x;
    py1 = pen1.getY() + origin.y;

    uAngle2 += angularV2 * dt;
    angularV2 += angularA2 * dt;
    pen2.pAngle = uAngle2; // 直接赋值弧度
    pen2.setX( pen2.pLength, pen2.getAngle());
    pen2.setY( pen2.pLength, pen2.getAngle());
    pen2.x = pen1.getX() + pen2.getX();
    pen2.y = pen1.getY() + pen2.getY();
    px2 = pen2.getX() + origin.x;
    py2 = pen2.getY() + origin.y;

    // 其余绘制和文件写入逻辑保留
}

额外建议

  • 可以给pendulum类添加setAngleRad()方法,专门用于设置弧度角度,避免单位混淆问题。
  • 增大重力常数g的值(比如设为980,对应像素坐标系下的重力),模拟效果会更贴近真实。

内容的提问来源于stack exchange,提问作者Cr3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 17:10:25