multiple_pendulum.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import numpy as np
  2. from vedo import Plotter, mag, versor, vector
  3. from vedo import Cylinder, Line, Box, Sphere
  4. ############## Constants
  5. N = 5 # number of bobs
  6. R = 0.3 # radius of bob (separation between bobs=1)
  7. Ks = 50 # k of springs (masses=1)
  8. g = 9.81 # gravity acceleration
  9. gamma = 0.1 # some friction
  10. Dt = 0.03 # time step
  11. # Create the initial positions and velocitites (0,0) of the bobs
  12. bob_x = [0]
  13. bob_y = [0]
  14. x_dot = np.zeros(N+1) # velocities
  15. y_dot = np.zeros(N+1)
  16. # Create the bobs
  17. for k in range(1, N + 1):
  18. alpha = np.pi / 5 * k / 10
  19. bob_x.append(bob_x[k - 1] + np.cos(alpha) + np.random.normal(0, 0.1))
  20. bob_y.append(bob_y[k - 1] + np.sin(alpha) + np.random.normal(0, 0.1))
  21. plt = Plotter(title="Multiple Pendulum", bg2='ly')
  22. plt += Box(pos=(0, -5, 0), size=(12, 12, 0.7)).color("k").wireframe(1)
  23. sph = Sphere(pos=(bob_x[0], bob_y[0], 0), r=R / 2).color("gray")
  24. plt += sph
  25. bob = [sph]
  26. for k in range(1, N + 1):
  27. c = Cylinder(pos=(bob_x[k], bob_y[k], 0), r=R, height=0.3).color(k)
  28. plt += c
  29. bob.append(c)
  30. # Create some auxiliary variables
  31. x_dot_m = np.zeros(N+1)
  32. y_dot_m = np.zeros(N+1)
  33. dij = np.zeros(N+1) # array with distances to previous bob
  34. dij_m = np.zeros(N+1)
  35. for k in range(1, N + 1):
  36. dij[k] = mag([bob_x[k] - bob_x[k - 1], bob_y[k] - bob_y[k - 1]])
  37. fctr = lambda x: (x - 1) / x
  38. Dt *= np.sqrt(1 / g)
  39. Dt2 = Dt / 2 # Midpoint time step
  40. DiaSq = (2 * R) ** 2 # Diameter of bob squared
  41. def loop_func(evt):
  42. global bob_x, bob_y
  43. bob_x_m = list(map((lambda x, dx: x + Dt2 * dx), bob_x, x_dot)) # midpoint variables
  44. bob_y_m = list(map((lambda y, dy: y + Dt2 * dy), bob_y, y_dot))
  45. for k in range(1, N + 1):
  46. factor = fctr(dij[k])
  47. x_dot_m[k] = x_dot[k] - Dt2 * (Ks * (bob_x[k] - bob_x[k - 1]) * factor + gamma * x_dot[k])
  48. y_dot_m[k] = y_dot[k] - Dt2 * (Ks * (bob_y[k] - bob_y[k - 1]) * factor + gamma * y_dot[k] + g)
  49. for k in range(1, N):
  50. factor = fctr(dij[k + 1])
  51. x_dot_m[k] -= Dt2 * Ks * (bob_x[k] - bob_x[k + 1]) * factor
  52. y_dot_m[k] -= Dt2 * Ks * (bob_y[k] - bob_y[k + 1]) * factor
  53. # Compute the full step variables
  54. bob_x = list(map((lambda x, dx: x + Dt * dx), bob_x, x_dot_m))
  55. bob_y = list(map((lambda y, dy: y + Dt * dy), bob_y, y_dot_m))
  56. for k in range(1, N + 1):
  57. dij[k] = mag([bob_x[k] - bob_x[k - 1], bob_y[k] - bob_y[k - 1]])
  58. dij_m[k] = mag([bob_x_m[k] - bob_x_m[k - 1], bob_y_m[k] - bob_y_m[k - 1]])
  59. factor = fctr(dij_m[k])
  60. x_dot[k] -= Dt * (Ks * (bob_x_m[k] - bob_x_m[k - 1]) * factor + gamma * x_dot_m[k])
  61. y_dot[k] -= Dt * (Ks * (bob_y_m[k] - bob_y_m[k - 1]) * factor + gamma * y_dot_m[k] + g)
  62. for k in range(1, N):
  63. factor = fctr(dij_m[k + 1])
  64. x_dot[k] -= Dt * Ks * (bob_x_m[k] - bob_x_m[k + 1]) * factor
  65. y_dot[k] -= Dt * Ks * (bob_y_m[k] - bob_y_m[k + 1]) * factor
  66. # Check to see if they are colliding
  67. for i in range(1, N):
  68. for j in range(i + 1, N + 1):
  69. dist2 = (bob_x[i] - bob_x[j]) ** 2 + (bob_y[i] - bob_y[j]) ** 2
  70. if dist2 < DiaSq: # are colliding
  71. Ddist = np.sqrt(dist2) - 2 * R
  72. tau = versor([bob_x[j] - bob_x[i], bob_y[j] - bob_y[i], 0])
  73. DR = Ddist / 2 * tau
  74. bob_x[i] += DR[0] # DR.x
  75. bob_y[i] += DR[1] # DR.y
  76. bob_x[j] -= DR[0] # DR.x
  77. bob_y[j] -= DR[1] # DR.y
  78. Vji = vector(x_dot[j] - x_dot[i], y_dot[j] - y_dot[i])
  79. DV = np.dot(Vji, tau) * tau
  80. x_dot[i] += DV[0] # DV.x
  81. y_dot[i] += DV[1] # DV.y
  82. x_dot[j] -= DV[0] # DV.x
  83. y_dot[j] -= DV[1] # DV.y
  84. # Update the loations of the bobs and the stretching of the springs
  85. plt.remove("Line")
  86. for k in range(1, N + 1):
  87. bob[k].pos([bob_x[k], bob_y[k], 0])
  88. sp = Line(bob[k - 1].pos(), bob[k].pos()).color("gray").lw(8)
  89. plt.add(sp)
  90. plt.render()
  91. plt.add_callback("timer", loop_func)
  92. plt.timer_callback("start")
  93. plt.show().close()