0

我刚刚开始使用 python 并尝试使用 tkinter 创建双摆动画。我知道由于我缺乏经验,我可能采取了一种复杂的方法。

我有一个我没想到的错误。钟摆似乎在某些地方奇怪地减慢了速度。随着时间的推移,系统的能量似乎下降了,这不应该发生,因为我没有考虑任何摩擦。

我不认为我在 theta1_dotdot 和 theta2_dotdot 的公式中犯了错误,因为即使我使用更简单的(非物理)公式也会发生减速。

这是我的程序:

from tkinter import*
from random import*
from math import*

gui = Tk()
gui.title("Double Pendulum")
canvas = Canvas(gui, width=300, height=300)
canvas.pack()

r1,r2,m1,m2 = 75,75,10,10
g = 9.81
t=0
delt=0.001
theta1 = random()*2*pi
theta2 = random()*2*pi
theta1_dot,theta2_dot = 0,0
dt = 0.1
t = 0

while t < 1000000:
    num1 = (-g*(2*m1+m2)*sin(theta1))
    num2 = -m2*g*sin(theta1-2*theta2)
    num3 = (-2*sin(theta1-theta2)*m2*            (theta2_dot**2*r2+theta1_dot**2*r1*cos(theta1-theta2)))
    denom1 = r1*(2*m1+m2-m2*cos(2*theta1-2*theta2))
    theta1_dotdot = (num1 + num2 + num3)/denom1

    num4 = 2*sin(theta1-theta2)
    num5 = (theta1_dot**2*r1*(m1+m2))
    num6 = g*(m1+m2)*cos(theta1)
    num7 = theta2_dot**2*r2*m2*cos(theta1-theta2)
    denom2 = r2*(2*m1+m2-m2*cos(2*theta1-2*theta2))
    theta2_dotdot = (num4*(num5+num6+num7))/denom2

    theta1_dot += theta1_dotdot * dt
    theta2_dot += theta2_dotdot * dt
    theta1 += theta1_dot * dt
    theta2 += theta2_dot * dt

    x1 = r1*sin(theta1)
    y1 = r1*cos(theta1)

    x2 = x1 + r2*sin(theta2)
    y2 = y1 + r2*cos(theta2)

    trace = canvas.create_oval(150 + x2, 60 + y2, 150 + x2, 60 + y2, fill='black', outline='black')
    lin1 = canvas.create_line(150,60,150+x1, 60+y1,width=3,fill='pink')
    lin2 = canvas.create_line(150+x1, 60+y1,150+x2, 60+y2,width=3,fill='pink')
    ov1 = canvas.create_oval(140+x1,50+y1,160+x1,70+y1,     fill='pink',outline='pink')
    ov2 = canvas.create_oval(140+x2,50+y2,160+x2,70+y2, fill='pink',outline='pink')
    t += .1
    canvas.after(1)
    canvas.update()
    canvas.delete(ov1)
    canvas.delete(ov2)
    canvas.delete(lin1)
    canvas.delete(lin2)

gui.mainloop()
4

1 回答 1

2

我已经重写了您的代码以删除一揽子导入(import *),使用类结构而不是全局变量和函数,并正确使用 tkinter mainloop 和 after 函数:

import tkinter as tk
import random
from math import pi, sin, cos

r1,r2,m1,m2 = 75,75,10,10
g = 9.81

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title("Double Pendulum")
        self.canvas = tk.Canvas(self, width=300, height=300)
        self.canvas.pack()
        self.delt=0.001
        self.theta1 = random.random()*2*pi
        self.theta2 = random.random()*2*pi
        self.theta1_dot,self.theta2_dot = 0,0
        self.dt = 0.1
        self.t = 0

        self.after(1, self.do_after)

    def do_after(self):
        self.canvas.delete('pendulum')

        num1 = (-g*(2*m1+m2)*sin(self.theta1))
        num2 = -m2*g*sin(self.theta1-2*self.theta2)
        num3 = (-2*sin(self.theta1-self.theta2)*m2*(self.theta2_dot**2*r2+self.theta1_dot**2*r1*cos(self.theta1-self.theta2)))
        denom1 = r1*(2*m1+m2-m2*cos(2*self.theta1-2*self.theta2))
        theta1_dotdot = (num1 + num2 + num3)/denom1

        num4 = 2*sin(self.theta1-self.theta2)
        num5 = (self.theta1_dot**2*r1*(m1+m2))
        num6 = g*(m1+m2)*cos(self.theta1)
        num7 = self.theta2_dot**2*r2*m2*cos(self.theta1-self.theta2)
        denom2 = r2*(2*m1+m2-m2*cos(2*self.theta1-2*self.theta2))
        theta2_dotdot = (num4*(num5+num6+num7))/denom2

        self.theta1_dot += theta1_dotdot * self.dt
        self.theta2_dot += theta2_dotdot * self.dt
        self.theta1 += self.theta1_dot * self.dt
        self.theta2 += self.theta2_dot * self.dt

        x1 = r1*sin(self.theta1)
        y1 = r1*cos(self.theta1)

        x2 = x1 + r2*sin(self.theta2)
        y2 = y1 + r2*cos(self.theta2)

        self.canvas.create_oval(150 + x2, 60 + y2, 150 + x2, 60 + y2, fill='black', outline='black', tag='trace')
        self.canvas.create_line(150,60,150+x1, 60+y1,width=3,fill='pink', tags='pendulum')
        self.canvas.create_line(150+x1, 60+y1,150+x2, 60+y2,width=3,fill='pink', tags='pendulum')
        self.canvas.create_oval(140+x1,50+y1,160+x1,70+y1,     fill='pink',outline='pink', tags='pendulum')
        self.canvas.create_oval(140+x2,50+y2,160+x2,70+y2, fill='pink',outline='pink', tags='pendulum')
        self.t += .1

        self.after(1, self.do_after)

if __name__ == '__main__':
    app = App()
    app.mainloop()

在您的代码中,您强制调用update循环的每次迭代,而不是让 tkinter 在需要更新时进行处理,您也在调用after时没有回调,而 AFAICT 实际上并没有做任何事情。
我还在钟摆部件上添加了标签,这样您就可以通过一次调用将它们全部删除,而不必每次都存储它们的 ID。

经过进一步测试,真正的问题是您在画布上创建了数千个 tkinter 难以渲染的对象。要保留跟踪,您可以保留坐标列表并将其绘制为一条线:

import tkinter as tk
import random
from math import pi, sin, cos

r1,r2,m1,m2 = 75,75,10,10
g = 9.81

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title("Double Pendulum")
        self.canvas = tk.Canvas(self, width=300, height=300)
        self.canvas.pack()
        self.delt=0.001
        self.theta1 = random.random()*2*pi
        self.theta2 = random.random()*2*pi
        self.theta1_dot,self.theta2_dot = 0,0
        self.dt = 0.1
        self.t = 0

        self.trace_coords = []

        self.after(1, self.do_after)

    def do_after(self):
        self.canvas.delete('trace')
        self.canvas.delete('pendulum')

        num1 = (-g*(2*m1+m2)*sin(self.theta1))
        num2 = -m2*g*sin(self.theta1-2*self.theta2)
        num3 = (-2*sin(self.theta1-self.theta2)*m2*(self.theta2_dot**2*r2+self.theta1_dot**2*r1*cos(self.theta1-self.theta2)))
        denom1 = r1*(2*m1+m2-m2*cos(2*self.theta1-2*self.theta2))
        theta1_dotdot = (num1 + num2 + num3)/denom1

        num4 = 2*sin(self.theta1-self.theta2)
        num5 = (self.theta1_dot**2*r1*(m1+m2))
        num6 = g*(m1+m2)*cos(self.theta1)
        num7 = self.theta2_dot**2*r2*m2*cos(self.theta1-self.theta2)
        denom2 = r2*(2*m1+m2-m2*cos(2*self.theta1-2*self.theta2))
        theta2_dotdot = (num4*(num5+num6+num7))/denom2

        self.theta1_dot += theta1_dotdot * self.dt
        self.theta2_dot += theta2_dotdot * self.dt
        self.theta1 += self.theta1_dot * self.dt
        self.theta2 += self.theta2_dot * self.dt

        x1 = r1*sin(self.theta1)
        y1 = r1*cos(self.theta1)

        x2 = x1 + r2*sin(self.theta2)
        y2 = y1 + r2*cos(self.theta2)

        self.trace_coords.append((150 + x2, 60 + y2, 150 + x2, 60 + y2))
        self.canvas.create_line(self.trace_coords, fill='black', tag='trace')
        self.canvas.create_line(150,60,150+x1, 60+y1,width=3,fill='pink', tags='pendulum')
        self.canvas.create_line(150+x1, 60+y1,150+x2, 60+y2,width=3,fill='pink', tags='pendulum')
        self.canvas.create_oval(140+x1,50+y1,160+x1,70+y1,     fill='pink',outline='pink', tags='pendulum')
        self.canvas.create_oval(140+x2,50+y2,160+x2,70+y2, fill='pink',outline='pink', tags='pendulum')
        self.t += .1

        self.after(1, self.do_after)

if __name__ == '__main__':
    app = App()
    app.mainloop()
于 2018-08-07T09:56:27.520 回答