# 自由落下
> 作者:王一哲
> 日期:2018/3/19
<br />
這次讓物體加上重力的作用,目標是畫出小球從某個高度往下加速落到地板上,並畫出小球的 y-t 圖、 v-t 圖,分為3個不同的狀況:
1. 小球觸地時停止 ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/4-1freefall))
2. 小球觸地時反彈 ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/4-2bounce))
3. 小球觸地時反彈, 恢復係數為e ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/4-3bouncee))
成果如下:
<img style="display: block; margin-left: auto; margin-right: auto" height="100%" width="100%" src="https://i.imgur.com/WdFx6Ki.png">
<div style="text-align:center">自由落下畫面截圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/ybJkErA.png">
<div style="text-align:center">小球觸地時停止: y-t 圖及 v-t 圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/qjsuQGx.png">
<div style="text-align:center">小球觸地時反彈: y-t 圖及 v-t 圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/vSpahU0.png">
<div style="text-align:center">小球觸地時反彈,e = 0.9: y-t 圖及 v-t 圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/ReNEqTo.png">
<div style="text-align:center">小球觸地時反彈,e = 0.8: y-t 圖及 v-t 圖</div>
<br />
## 程式 4-1:自由落下 ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/04.%E8%87%AA%E7%94%B1%E8%90%BD%E4%B8%8B/4-1_freefall.py))
```python=
"""
VPython教學: 4-1.自由落下
Ver. 1: 2018/2/18
Ver. 2: 2019/9/6
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size = 1 # 小球半徑
h = 15 # 小球離地高度
g = 9.8 # 重力加速度 9.8 m/s^2
t = 0 # 時間
dt = 0.001 # 時間間隔
"""
2. 畫面設定
"""
scene = canvas(title="Free Fall", width=600, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, 0, 0), size=vec(40, 0.01, 10), color=color.blue)
ball = sphere(pos=vec(0, h, 0), radius=size, color=color.red, v=vec(0, 0, 0), a=vec(0, -g, 0))
gd = graph(title="plot", width=600, height=450, x=0, y=600, xtitle="t(s)", ytitle="blue: y(m), red: v(m/s)")
yt = gcurve(graph=gd, color=color.blue)
vt = gcurve(graph=gd, color=color.red)
"""
3. 物體運動部分, 小球觸地時停止
"""
while ball.pos.y - floor.pos.y > size + 0.5*floor.height:
rate(1000)
ball.v += ball.a*dt
ball.pos += ball.v*dt
yt.plot(pos=(t, ball.pos.y))
vt.plot(pos=(t, ball.v.y))
t += dt
print("t = ", t)
```
<br />
### 參數設定
在此定義的變數有 size、h、g、t、dt,用途都已經寫在該行的註解中。
<br />
### 畫面設定
#### sphere
與前一個例子相比,這次新增的函式為 <span style="color:red; font-weight:bold">sphere</span>,功能是用來畫出球體。sphere 是英文的球、球體,在 VPython 中用來產生球體,在這個程式中用來產生小球 ball。\[[3](http://www.glowscript.org/docs/VPythonDocs/sphere.html )\] 在產生物件時通常會調整的選項為:
- **pos**: 球心位置,數值為向量,vector(x, y, z),vector 也可以簡化為 vec。
- **radius**: 半徑,數值為純量。
- **color**: 顏色。
也可以在產生物件後,用
```python
[物件名稱].[選項] =
```
來調整物件的屬性,例如質量 m、位置 pos、速度 v、加速度 a、動量 p……等等。因此以下兩行程式碼的功能,是將名稱為 ball 的 sphere 物件速度設為 (0, 0, 0)、加速度設為 (0, -g, 0)。
```python
ball.v = vec(0, 0, 0)
ball.a = vec(0, -g, 0)
```
#### graph
graph是英文的圖,在 VPython 中用來產生繪圖視窗。\[[4](http://www.glowscript.org/docs/VPythonDocs/graph.html)\] ,在這個程式中我將繪圖視窗命名為 gd,並將小球的 y-t 圖和 v-t 圖畫在同一個視窗當中。
<br />
### 物體運動
利用一個 while 迴圈每隔一小段時間 dt 更新一次物體的狀態,由於我希望當小球接觸到地板時程式停止運作,因此在 while 裡設定的條件為
```python
ball.pos.y - floor.pos.y > size + 0.5*floor.height
```
當條件成立時繼續執行。接下來逐行說明程式碼的用途。
1. **rate(1000)** 是指每秒更新動畫1000次。
2. **ball.v += ball.a*dt** 用來更新小球的速度,用 ball.v 讀取小球的速度,將讀取到的值加上加速度乘以一小段時間,再重新指定給小球的速度。由於所取的時間長度 dt 很短,可以當成是一小段等加速度運動,因此本式就是 $$v = v_0 + at$$
3. **ball.pos += ball.v*dt** 用來更新小球的位置,用 ball.pos 讀取小球的位置,將讀取到的值加上速度乘以一小段時間,再重新指定給小球的位置。由於所取的時間長度 dt 很短,可以當成是一小段等速度運動,因此本式就是 $$s = v \times dt$$
4. **yt.plot(pos = (t, ball.pos.y))** 用來畫小球的 y-t 圖。
5. **vt.plot(pos = (t, ball.v.y))** 用來畫小球的 v-t 圖。
6. **t += dt** 用來更新時間。
7. **print("t = ", t)** 印出整個運動經過的時間。
<br />
## 程式 4-2:自由落下,小球觸地時反彈 ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/04.%E8%87%AA%E7%94%B1%E8%90%BD%E4%B8%8B/4-2_bounce.py))
```python=
"""
VPython教學: 4-2.自由落下, 小球觸地時反彈
Ver. 1: 2018/2/18
Ver. 2: 2019/9/6
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size = 1 # 小球半徑
h = 15 # 小球離地高度
g = 9.8 # 重力加速度 9.8 m/s^2
t = 0 # 時間
dt = 0.001 # 時間間隔
"""
2. 畫面設定
"""
scene = canvas(title="Free Fall", width=600, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, 0, 0), size=vec(40, 0.01, 10), color=color.blue)
ball = sphere(pos=vec(0, h, 0), radius=size, color=color.red, v=vec(0, 0, 0), a=vec(0, -g, 0))
gd = graph(title="plot", width=600, height=450, x=0, y=600, xtitle="t(s)", ytitle="blue: y(m), red: v(m/s)")
yt = gcurve(graph=gd, color=color.blue)
vt = gcurve(graph=gd, color=color.red)
"""
3. 物體運動部分, 小球觸地時反彈
"""
while t < 20:
rate(1000)
ball.v += ball.a*dt
ball.pos += ball.v*dt
yt.plot(pos=(t, ball.pos.y))
vt.plot(pos=(t, ball.v.y))
if ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0:
ball.v.y = -ball.v.y
t += dt
print("t = ", t)
```
<br />
程式 4-2 與 4-1 幾乎一模一樣,只是為了使小球在接觸地板時反彈,在物體運動部分增加了
```python
if ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0:
ball.v.y = -ball.v.y
```
若 ball.pos.y - floor.pos.y <= size + 0.5*floor.height 代表小球碰到地板,若 ball.v.y < 0 代表小球速度向下,當兩個條件同時成立時,代表小球正在向下運動並撞到地板,小球反彈後速度由負變為正,因此將 ball.v.y 的乘上負號後再指定回 ball.v.y。
<br />
## 程式 4-3:自由落下,小球觸地時反彈,恢復係數為e ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/04.%E8%87%AA%E7%94%B1%E8%90%BD%E4%B8%8B/4-3_bounce_e.py))
```python=
"""
VPython教學: 4-3.自由落下, 小球觸地時反彈, 恢復係數為e
Ver. 1: 2018/2/19
Ver. 2: 2019/9/6
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
"""
size = 1 # 小球半徑
e = 0.9 # 恢復係數
i = 0 # 小球撞地板次數
N = 20 # 小球撞地板次數上限, 到達上限後停止運作
h = 15 # 小球離地高度
g = 9.8 # 重力加速度 9.8 m/s^2
t = 0 # 時間
dt = 0.001 # 時間間隔
"""
2. 畫面設定
"""
scene = canvas(title="Free Fall", width=600, height=600, x=0, y=0, center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6))
floor = box(pos=vec(0, 0, 0), size=vec(40, 0.01, 10), color=color.blue)
ball = sphere(pos=vec(0, h, 0), radius=size, color=color.red, v=vec(0, 0, 0), a=vec(0, -g, 0))
gd = graph(title="plot", width=600, height=450, x=0, y=600, xtitle="t(s)", ytitle="blue: y(m), red: v(m/s)")
yt = gcurve(graph=gd, color=color.blue)
vt = gcurve(graph=gd, color=color.red)
"""
3. 物體運動部分, 小球觸地時反彈
"""
while i < N:
rate(1000)
ball.v += ball.a*dt
ball.pos += ball.v*dt
yt.plot(pos=(t, ball.pos.y))
vt.plot(pos=(t, ball.v.y))
if ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0:
ball.v.y = -ball.v.y*e
i += 1
t += dt
print("i = ", i)
print("t = ", t)
```
<br />
程式 4-3 與 4-2 幾乎一模一樣,以下只說明不同之處。
1. 由於小球與地板間不是彈性碰撞,因此定義恢復係數
$$
e = \frac{v'}{v}
$$
其中$v$為撞前速度量值、$v'$為撞後速度量值。發生碰撞時執行的程式碼改為
```python
ball.v.y = -ball.v.y*e
```
2. 為了計算小球、地板撞擊次數,並在撞擊20次時停止程式,新增變數 i = 0 (小球撞地板次數,預設值為0)、N = 20(小球撞地板次數上限, 到達上限後停止運作),while 迴圈的條件改為 i < N,每次發生碰撞時將 i 的數值 +1。
3. 為了使小球撞擊地板時的條件更精準需要考慮地板的厚度,因此 if 的條件改為
```python
ball.pos.y - floor.pos.y <= size + 0.5*floor.height and ball.v.y < 0
```
上式中 floor.height 是用來讀取物件 floor 的高度值。
<br />
## 結語
其實程式 4-1、4-2 是為了寫出 4-3 的前置作業,先寫出最簡單程式再慢慢把條件加上去,不需要一口氣就寫出很複雜的程式,那樣難度太高了。在程式 4-3 中,可以試著將 e 改成不同的值,觀察反彈高度及運動時間的變化。也可以拿一顆球實際測試看看,如果想要增加實驗的精準度,可以將小球的運動過程錄影,再用影像分析軟體 Tracker 找出小球的 y-t、v-t 圖,同時也把測得的 e 值代入程式 4-3 中,看看理論與實驗值有何差異。
<br />
## VPython官方說明書
1. **canvas**: http://www.glowscript.org/docs/VPythonDocs/canvas.html
2. **box**: http://www.glowscript.org/docs/VPythonDocs/box.html
3. **sphere**: http://www.glowscript.org/docs/VPythonDocs/sphere.html
4. **graph**: http://www.glowscript.org/docs/VPythonDocs/graph.html
---
###### tags: `VPython`