Gleichgewicht, Schwerpunkt und Hebelarm an einer Balkenwaage (Software)

Martin Vogel ⌂ @, Dortmund / Bochum, Sonntag, 08.01.2017, 22:21 (vor 676 Tagen)

Dieses Python-3-Programm mit Tkinter-Grafik und Mausbedienung über Schieberegler war in ähnlicher Form im vergangenen Jahr die Beispiellösung für die Programmieraufgabe im ersten Semester. Eine Balkenwaage hat vier mit der Maus beeinflussbare Parameter: die Längen der beiden Balkenarme und die Massen am jeweiligen Armende. Die Schieber sind so angeordnet, dass die Bedienung möglichst intuitiv ist. Die Regler für die Längen sind horizontal angeordnet und entgegengesetzt skaliert, die Regler für die Massen sind vertikal angeordnet.

Die Beschriftung der einzelnen Komponenten wird dynamisch an die sich ändernde Geometrie der Anordnung angepasst und auch eine gedrehte Beschriftung kommt vor. Ein (minimaler) 3D-Effekt wird durch einen Stapel immer heller und kleiner werdender Kreisscheiben erzielt, die eine Art Glanzpunkt auf den Massekugeln darstellen.

[image]

Download: [image]ZIP-Archiv_F8RAASYL1.zip

  1. # Simulation einer Balkenwaage
  2. #
  3. # Die Massen an den Balkenenden sowie die Längen der Waagbalkenhälften
  4. # sind variabel und können mit Schiebereglern beeinflusst werden.
  5. #
  6. # Durch Rechtsklick auf einen Schieberegler lässt sich die Waage wieder
  7. # ins Gleichgewicht bringen.
  8.  
  9. from tkinter import Tk, Canvas, Label, Entry, Scale, mainloop, messagebox
  10. from math import sin, cos, atan2, degrees, hypot
  11.  
  12. # Programmfenster einrichten
  13. T = Tk()
  14. T.title("Gleichgewicht und Schwerpunkt")
  15.  
  16. # Zeichenfläche definieren
  17. C = Canvas(T, width=800, height=600, bg="white")
  18. C.grid(row=0, column=1, columnspan=2, rowspan=2)
  19.  
  20.  
  21. def kreis(p, r, fill="black", outline=None, width=1):
  22. """Zeichnet Kreis um Punkt p mit Radius r"""
  23. # Falls Randfarbe nicht angegeben wurde, entspricht sie der Füllfarbe.
  24. if not outline:
  25. outline = fill
  26. # Der Kreis wird über das ihn umschließende Quadrat definiert.
  27. C.create_oval(p[0]-r, p[1]-r, p[0]+r, p[1]+r,
  28. fill=fill, outline=outline, width=width)
  29.  
  30.  
  31. def kugel(p, m):
  32. """Zeichnet Kugel der Masse m an Punkt p"""
  33. # Der Radius ist proportional zur dritten Wurzel der Masse.
  34. r = m**(1/3)*10
  35. # Die Kreisscheibe ist rot.
  36. kreis(p, r, "#E00000")
  37. # Oben links befindet sich ein kleiner Glanzpunkt. Er besteht aus
  38. # vielen Kreisen, die immer heller und immer kleiner werden.
  39. for ri in range(int(r/2), 0, -1):
  40. pi = (p[0]-r/3, p[1]-r/3)
  41. fi = "#E0%02X%02X" % (int(180*(1-2*ri/r)), int(180*(1-2*ri/r)))
  42. kreis(pi, ri, fi)
  43. # Beschriftung
  44. C.create_text(p, text=m, fill="white")
  45.  
  46.  
  47. def zeichnung(event=None):
  48. """Baut die Zeichnung komplett neu auf"""
  49. C.delete("all")
  50.  
  51. # Maßstab: 1 Meter entspricht 30 Pixeln
  52. m = 30
  53.  
  54. # Höhe des senkrechten Aufhängestabes
  55. h = 0.1 * m
  56.  
  57. # Fadenlänge der aufgehängten Massen
  58. fl = 3*m
  59.  
  60. # Massen links/rechts von Schiebereglern ablesen
  61. lm = S_LMasse.get()
  62. rm = S_RMasse.get()
  63.  
  64. # Längen links/rechts von Schiebereglern ablesen
  65. ll = S_LLänge.get()
  66. rl = S_RLänge.get()
  67.  
  68. # Schwerpunktordinate auf dem Waagbalken
  69. try:
  70. s = rm/(lm+rm)*(ll+rl)
  71. except ZeroDivisionError:
  72. C.create_text(400, 100, text="Eine der beiden Massen muss größer als"
  73. " null sein.")
  74. return
  75.  
  76. # Startpunkt (Gelenkige Aufhängung)
  77. p0 = x0, y0 = 400, 100
  78.  
  79. # Winkel der Waage
  80. alpha = atan2(s-ll, h)
  81.  
  82. # Hypotenuse des rechtwinkligen Dreiecks
  83. # Aufhängepunkt-Schwerpunkt-Balkenschnittpunkt
  84. hyp = h*m/cos(alpha)+fl
  85.  
  86. # Schwerpunkt
  87. ps = x0, y0+hyp
  88.  
  89. # Schnittpunkt von Aufhängestab und Waagbalken
  90. p1 = x0-h*m*sin(alpha), y0+h*m*cos(alpha)
  91.  
  92. # Punkt des rechten Winkels im blauen Schwerpunktdreieck
  93. pw = x0-hyp*sin(alpha)*cos(alpha), y0+hyp*cos(alpha)*cos(alpha)
  94.  
  95. # Linker Endpunkt des Waagbalkens
  96. pl = p1[0]-ll*m*cos(alpha), p1[1]-ll*m*sin(alpha)
  97.  
  98. # Rechter Endpunkt des Waagbalkens
  99. pr = p1[0]+rl*m*cos(alpha), p1[1]+rl*m*sin(alpha)
  100.  
  101. # Aufhängestab
  102. C.create_line(p0, p1, width=10, fill="brown")
  103.  
  104. # Gelenkige Aufhängung
  105. kreis(p0, 0.3*m, fill="white", outline="black", width=4)
  106.  
  107. # Waagbalken
  108. C.create_line(pl, pr, width=10, capstyle="round", fill="brown")
  109.  
  110. # Linke Masse
  111. pl1 = pl[0], pl[1]+fl
  112. C.create_line(pl, pl1, width=2)
  113. kugel(pl1, lm)
  114.  
  115. # Rechte Masse
  116. pr1 = pr[0], pr[1]+fl
  117. C.create_line(pr, pr1, width=2)
  118. kugel(pr1, rm)
  119.  
  120. # Schwerpunkt zeichnen und beschriften
  121. kreis(ps, 3, fill="blue")
  122. C.create_text(x0, y0+hyp+5, fill="blue",
  123. text="Schwerpunkt", anchor="n")
  124.  
  125. # Winkel einzeichnen:
  126. # Das blaue Dreieck
  127. C.create_polygon(p0, ps, pw, outline="blue", fill="")
  128. # Der Maßbogen des Winkels
  129. C.create_arc(x0-2.5*m, y0-2.5*m, x0+2.5*m, y0+2.5*m,
  130. style="arc", outline="blue",
  131. start=270, extent=-degrees(alpha))
  132. # Die Pfeilspitze des Maßbogens nur bei ausreichend großem Winkel zeichnen
  133. if abs(degrees(alpha)) > 5:
  134. x2 = x0+10 if alpha < 0 else x0-10
  135. y2 = y0+2.5*m
  136. C.create_polygon(x2, y2-5, x0, y2, x2, y2+3, fill="blue")
  137. # Winkelbemaßung je nach Vorzeichen links- oder rechtsbündig
  138. C.create_text(x0, y0+2.5*m, fill="blue",
  139. text=" α = %.2f° " % abs(degrees(alpha)),
  140. anchor="e" if alpha < 0 else "w")
  141. # Schwerpunktabstand (falls kein Gleichgewicht) beschriften
  142. if alpha:
  143. sa = hypot(ps[0]-pw[0], ps[1]-pw[1])/m
  144. C.create_text((ps[0]+pw[0])/2, (ps[1]+pw[1])/2,
  145. anchor="s", fill="blue",
  146. angle=degrees(-alpha), text="%.2fm" % sa)
  147.  
  148.  
  149. # Eingabebereich: Jeder Schieberegler lässt sich mit Rechtsklick
  150. # in die Gleichgewichtslage zurücksetzen (falls möglich).
  151.  
  152. # Vertikaler linker Regler
  153. Label(text="linke Massen[kg]").grid(row=0, column=0, sticky="ew")
  154. S_LMasse = Scale(from_=0, to=99, width=20, orient="vertical", length=500,
  155. tickinterval=10, resolution=0.1, command=zeichnung)
  156. S_LMasse.set(10)
  157. S_LMasse.grid(row=1, column=0, sticky="ns")
  158.  
  159.  
  160. def reset_LMasse(event):
  161. S_LMasse.set(S_RMasse.get()*S_RLänge.get()/S_LLänge.get())
  162. zeichnung()
  163. S_LMasse.bind("<Button-3>", reset_LMasse)
  164.  
  165. # Vertikaler rechter Regler
  166. Label(text="rechte Massen[kg]").grid(row=0, column=3, sticky="ew")
  167. S_RMasse = Scale(from_=0, to=99, width=20, orient="vertical", length=500,
  168. tickinterval=10, resolution=0.1, command=zeichnung)
  169. S_RMasse.set(10)
  170. S_RMasse.grid(row=1, column=3, sticky="ns")
  171.  
  172.  
  173. def reset_RMasse(event):
  174. S_RMasse.set(S_LMasse.get()*S_LLänge.get()/S_RLänge.get())
  175. zeichnung()
  176. S_RMasse.bind("<Button-3>", reset_RMasse)
  177.  
  178. # Horizontaler linker Regler
  179. Label(text="Länge des linken Waagbalkenarmesn[m]",
  180. ).grid(row=3, column=0, columnspan=2, sticky="ew")
  181. S_LLänge = Scale(from_=10, to=1, width=20, orient="horizontal",
  182. tickinterval=1, resolution=0.1, command=zeichnung)
  183. S_LLänge.set(5)
  184. S_LLänge.grid(row=4, column=0, columnspan=2, sticky="ew")
  185.  
  186.  
  187. def reset_LLänge(event):
  188. if S_LMasse.get():
  189. S_LLänge.set(S_RLänge.get()*S_RMasse.get()/S_LMasse.get())
  190. zeichnung()
  191. S_LLänge.bind("<Button-3>", reset_LLänge)
  192.  
  193. # Horizontaler rechter Regler
  194. Label(text="Länge des rechten Waagbalkenarmesn[m]"
  195. ).grid(row=3, column=2, columnspan=2, sticky="ew")
  196. S_RLänge = Scale(from_=1, to=10, width=20, orient="horizontal",
  197. tickinterval=1, resolution=0.1, command=zeichnung)
  198. S_RLänge.set(5)
  199. S_RLänge.grid(row=4, column=2, columnspan=2, sticky="ew")
  200.  
  201.  
  202. def reset_RLänge(event):
  203. if S_RMasse.get():
  204. S_RLänge.set(S_LLänge.get()*S_LMasse.get()/S_RMasse.get())
  205. zeichnung()
  206. S_RLänge.bind("<Button-3>", reset_RLänge)
  207.  
  208. # Anfangsdarstellung
  209. zeichnung()
  210. mainloop()

--
Dipl.-Ing. Martin Vogel
Leiter des Bauforums

Heute schon programmiert? Einführung in Python 3 (PDF)

Tags:
Python, Physik

RSS-Feed dieser Diskussion
powered by my little forum