Drone show¶
The goal is to make a nice night show.
We have a set of 100 drones that form the image of a boat in 3D. For us it is a set of 3D points (center of gravity of each drone) that we store in a Numpy 3 by 100 table. The boat fits in a 20x20x20 cube.
Initially
all the drones are centered at (0,0,0) so if you want to position the boat at (10, 20, 200) you have to translate the same amount over all the drones. the main axis of the boat is the axis of x i.e. the front of the boat is at x=10 and the back at x=-10.
import numpy as np
#boat = np.random.randint(-100, 100, size=(3,10)) / 10 # with a little luck...
# A formation that allows for easier debugging
boat = np.array([[-20., 0., 0.],
[ 20., 0., 0.],
[ 0., 0., -5.],
[ 0., 0., 5.],
[ 0., 0., 0.],
[ 0., -10., 0.],
[ 0., 10., 0.],
])
boat = boat.T
boat
array([[-20., 20., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., -10., 10.], [ 0., 0., -5., 5., 0., 0., 0.]])
We want to move the boat in the sky by making it do figures (the units used are the meter and the second). All movements are broken down second by second i.e. we give the position of all the drones every second (another program manages to move the drones to their next position).
Figure 1¶
Rotate the boat (therefore all the drones) horizontally around the point (0,0,80) at a distance of 100 m. It makes a full turn in 5 minutes.
Care should be taken that the orientation of the boat follows the movement, i.e. that the front of the boat is always well oriented.
def circle(boat, t):
# Code to display
# Do not touch this unless you know what you are doing
import matplotlib.animation
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from matplotlib.transforms import Affine2D
import mpl_toolkits.mplot3d.art3d as art3d
matplotlib.rcParams['animation.embed_limit'] = 256 # 256mb max animation size
plt.rcParams["animation.html"] = "jshtml"
plt.rcParams['figure.dpi'] = 100
plt.ioff()
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
# 5min -> 300 sec;
FRAMEPERSEC = 1.
def animate(t):
boat_prime = circle(boat_start, t/FRAMEPERSEC)
plt.cla()
p = Circle((0, 0), 100, fill=False)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=80, zdir="z")
plt.plot(boat_prime[0,:], boat_prime[1,:], boat_prime[2,:], '.b')
ax.set_xlim([-120, 120])
ax.set_ylim([-120, 120])
ax.set_zlim([0, 120]) # alternative
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_title(f"t: {t} sec")
matplotlib.animation.FuncAnimation(fig, animate, frames=int(300*FRAMEPERSEC))
Figure 2¶
We want to rotate the boat on its main axis (the x axis) until it returns to the original position. In aviation, this is called a barrel roll (rotation of 360 on the roll axis). Write the barrel_roll(boat, T, t)
function that returns the position of each drone at time t
given that a complete roll take T
seconds.
def barrel_rool(boat, T, t):
# Code to display
# You can change this
Tcomplete = 20
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
# Do not touch this unless you know what you are doing
def animate2(t):
boat_prime = barrel_roll(boat, Tcomplete, t)
plt.cla()
plt.plot(boat_prime[0,:], boat_prime[1,:], boat_prime[2,:], '.b')
ax.set_xlim([-60, 60])
ax.set_ylim([-60, 60])
ax.set_zlim([-60, 60])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_title(f"t: {t} sec")
# One frame per second for 2 complete rolls
matplotlib.animation.FuncAnimation(fig, animate2, frames=2*Tcomplete)
Figure 3¶
Combine figures 1 and 2 so that the boat rolls in 10 seconds every 30 seconds.
def combined_move(boat, t):
# Code to display
# Do not touch this unless you know what you are doing
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
def animate3(t):
boat_prime = combined_move(boat, t/FRAMEPERSEC)
plt.cla()
p = Circle((0, 0), 100, fill=False)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=80, zdir="z")
plt.plot(boat_prime[0,:], boat_prime[1,:], boat_prime[2,:], '.b')
ax.set_xlim([-120, 120])
ax.set_ylim([-120, 120])
ax.set_zlim([0, 120])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_title(f"t: {t} sec")
# 5min -> 300 sec
matplotlib.animation.FuncAnimation(fig, animate3, frames=int(300*FRAMEPERSEC))