我刚开始使用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()
答案 0 :(得分: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()