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

使用Matplotlib Animation模拟小车摆系统的可视化问题排查

小车摆系统Matplotlib动画修复方案

问题根源分析

  • 矩形小车不显示:代码中状态变量索引搞反(混淆了小车位置与摆角),且重复创建图形对象、每帧清空轴再重新添加元素,导致blit优化失效,图形无法正常渲染。
  • 缺少摆锤连线:未初始化连线对象,也未在动画更新时同步更新连线端点坐标。

修正后的完整代码

import numpy
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
import matplotlib.animation as animation


def cart_pend(t, x, pend_mass, cart_Mass, L, g, d, u):
    Sx = numpy.sin(x[2])
    Cx = numpy.cos(x[2])
    D = pend_mass * L * L * (cart_Mass + pend_mass * (1 - Cx**2))

    dx1_dt = x[1]
    dx2_dt = (1 / D) * (
        -(pend_mass**2) * L**2 * g * Cx * Sx
        + pend_mass * L**2 * (pend_mass * L * x[3] ** 2 * Sx - d * x[1])
    ) + pend_mass * L * L * (1 / D) * u
    dx3_dt = x[3]
    dx4_dt = (1 / D) * (
        (pend_mass + cart_Mass) * pend_mass * g * L * Sx
        - pend_mass * L * Cx * (pend_mass * L * x[3] ** 2 * Sx - d * x[1])
    ) - pend_mass * L * Cx * (1 / D) * u

    return [dx1_dt, dx2_dt, dx3_dt, dx4_dt]


m = 1
M = 5
L = 2
g = -10
d = 1
tspan = (1.0, 10.0)
x0 = [0, 0, numpy.pi, 0.5]
sol = solve_ivp(lambda t, x: cart_pend(t, x, m, M, L, g, d, -1), tspan, x0)
t = sol.t
y1, y2, y3, y4 = sol.y  # y1:小车位置x, y3:摆角theta

# 状态曲线可视化(保留原功能)
plt.plot(t, y1, label="小车位置")
plt.plot(t, y3, label="摆角")
plt.xlabel("时间")
plt.ylabel("状态变量")
plt.legend()
plt.grid(True)
plt.show()

# 动画可视化部分
fig, ax = plt.subplots()
# 调整坐标轴范围,适配摆长L=2的运动范围
ax.set_xlim(-5, 5)
ax.set_ylim(-3, 3)
ax.set_aspect('equal')  # 保持坐标轴比例一致,避免图形变形

# 初始化图形元素:小车矩形、摆锤圆形、连接连线
cart = plt.Rectangle((0, -0.1), 0.4, 0.2, color='blue')  # 小车尺寸:宽0.4,高0.2,底部在y=-0.1
pendulum = plt.Circle((0, 0), 0.1, color='red')
line, = ax.plot([], [], 'k-', lw=2)  # 摆锤连线

# 将图形元素添加到轴上
ax.add_patch(cart)
ax.add_patch(pendulum)

def init():
    # 初始化位置
    cart.set_xy([y1[0] - 0.2, -0.1])  # 小车中心在y1[0],左边界为x-0.2(宽0.4)
    pendulum.center = (y1[0] + L * numpy.sin(y3[0]), L * numpy.cos(y3[0]))
    line.set_data([y1[0], y1[0] + L * numpy.sin(y3[0])], [0, L * numpy.cos(y3[0])])
    return cart, pendulum, line

def update(frame):
    # 获取当前帧的状态
    x_cart = y1[frame]
    theta = y3[frame]
    # 计算摆锤端点坐标
    x_pend = x_cart + L * numpy.sin(theta)
    y_pend = L * numpy.cos(theta)
    
    # 更新小车位置
    cart.set_xy([x_cart - 0.2, -0.1])
    # 更新摆锤位置
    pendulum.center = (x_pend, y_pend)
    # 更新连线:小车顶部中心到摆锤端点
    line.set_data([x_cart, x_pend], [0, y_pend])
    
    return cart, pendulum, line

# 创建动画
anim = animation.FuncAnimation(fig, update, frames=len(t), init_func=init, interval=50, blit=True)

# 显示动画
plt.show()

# 保存为HTML文件
html_anim = anim.to_jshtml()
with open("animation.html", "w") as f:
    f.write(html_anim)

plt.close()

关键修正点说明

  1. 状态变量索引修正:明确y1对应小车位置x,y3对应摆角theta,修复原代码中索引混淆导致的位置错误。
  2. 图形初始化优化:仅在初始化阶段将图形元素添加到轴一次,后续仅更新位置,避免重复创建和清空轴导致的渲染异常。
  3. 添加摆锤连线:初始化连线对象,在update函数中同步更新小车顶部中心到摆锤端点的连线坐标。
  4. 坐标轴调整:扩大范围并设置等比例显示,确保运动过程中图形不会超出视野。
  5. 小车位置校准:调整矩形坐标计算逻辑,使小车中心与状态变量x_cart对齐,符合视觉预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 18:20:20