使用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()
关键修正点说明
- 状态变量索引修正:明确
y1对应小车位置x,y3对应摆角theta,修复原代码中索引混淆导致的位置错误。 - 图形初始化优化:仅在初始化阶段将图形元素添加到轴一次,后续仅更新位置,避免重复创建和清空轴导致的渲染异常。
- 添加摆锤连线:初始化连线对象,在
update函数中同步更新小车顶部中心到摆锤端点的连线坐标。 - 坐标轴调整:扩大范围并设置等比例显示,确保运动过程中图形不会超出视野。
- 小车位置校准:调整矩形坐标计算逻辑,使小车中心与状态变量
x_cart对齐,符合视觉预期。
内容的提问来源于stack exchange,提问作者Ibrahim zawra
相关产品推荐
相关产品推荐

