# 自由落下兩球碰撞
> 作者:王一哲
> 日期:2018/5/5
<br />
若將兩個彈性極佳的球上下疊放,且下方的球質量較大,將兩球從某個高度釋放,兩球受到重力的作用由靜止開始向下加速,當下方的球撞到地面反彈後會發生什麼事?在 YouTube 上有相當多實驗影片,例如 "[Stacked Ball Drop](https://youtu.be/2UHS883_P60)" 。我們可以利用之前寫好的〈[自由落下](https://hackmd.io/@yizhewang/S1e8LxzGQ)〉及〈[一維彈性碰撞](https://hackmd.io/@yizhewang/SkYXPWrfm)〉模擬程式來處理這個問題。
以下共有兩個程式,16-1 有兩個球,16-2 改為三個球。其實可以讓畫只執行到最上方的球飛出去之後就停止,因為在真實的情境下很難讓最上方的球被撞擊後往正上方飛出,掉落下後發生第二次碰撞的機率極低。
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/A6sahrl.png">
<div style="text-align:center">程式16-1畫面截圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://i.imgur.com/je6ObGJ.png">
<div style="text-align:center">程式16-2畫面截圖</div>
<br />
## 程式 16-1.自由落下兩球碰撞 ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/16.%E8%87%AA%E7%94%B1%E8%90%BD%E4%B8%8B%E5%85%A9%E7%90%83%E7%A2%B0%E6%92%9E/16-1_bounce.py)) ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/16-1bounce))
```python=
"""
VPython教學: 16-1.自由落下兩球碰撞
Ver. 1: 2018/2/28
Ver. 2: 2019/9/14
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
(1) r1 = 2, m1 = 2, r2 = 1, m2 = 1
(2) r1 = 1, m1 = 1, r2 = 2, m2 = 2
"""
r1, m1, c1 = 2, 2, color.red # 小球1半徑, 質量, 顏色
r2, m2, c2 = 1, 1, color.green # 小球2半徑, 質量, 顏色
h, L = 15, 40 # 小球離地高度, 地板邊長
g = 9.8 # 重力加速度 9.8 m/s^2
t, dt = 0, 0.001 # 時間, 時間間隔
"""
2. 畫面設定
"""
# 產生動畫視窗
scene = canvas(title="Free Fall and Collision", width=600, height=600, x=0, y=0,
center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6), range=L)
# 產生地板
floor = box(pos=vec(0, -r1, 0), size=vec(L, 0.01, L), texture=textures.wood)
# 產生小球並設定初速度、加速度
b1 = sphere(pos=vec(0, h, 0), radius=r1, color=c1, m=m1, v=vec(0, 0, 0), a=vec(0, -g, 0))
b2 = sphere(pos=vec(0, h+r1+r2, 0), radius=r2, color=c2, m=m2, v=vec(0, 0, 0), a=vec(0, -g, 0))
# y-t plot
gd = graph(title="<i>y</i>-<i>t</i> plot", width=600, height=450, x=0, y=600,
xtitle="<i>t</i> (s)", ytitle="red: <i>y</i><sub>1</sub>, green: <i>y</i><sub>2</sub> (m)")
yt1 = gcurve(graph=gd, color=c1)
yt2 = gcurve(graph=gd, color=c2)
# v-t plot
gd2 = graph(title="<i>v</i>-<i>t</i> plot", width=600, height=450, x=0, y=1050,
xtitle="<i>t</i> (s)", ytitle="red: <i>v</i><sub>2</sub>, green: <i>v</i><sub>2</sub> (m/s)")
vt1 = gcurve(graph=gd2, color=c1)
vt2 = gcurve(graph=gd2, color=c2)
# 一維彈性碰撞速度公式
def af_col_v(m1, m2, v1, v2):
v1_prime = (m1-m2)/(m1+m2)*v1 + (2*m2)/(m1+m2)*v2
v2_prime = (2*m1)/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2
return (v1_prime, v2_prime)
"""
3. 物體運動部分, 小球觸地時反彈
"""
while(t < 20):
rate(1000)
# 更新小球速度、位置
b1.v += b1.a*dt
b1.pos += b1.v*dt
b2.v += b2.a*dt
b2.pos += b2.v*dt
# 繪製小球 y-t、v-t 圖
yt1.plot(pos=(t, b1.pos.y))
yt2.plot(pos=(t, b2.pos.y))
vt1.plot(pos=(t, b1.v.y))
vt2.plot(pos=(t, b2.v.y))
# 若 b1 撞到地板則反彈
if(b1.pos.y <= 0 and b1.v.y < 0): b1.v.y = -b1.v.y
# 若 b1、b2 相撞則計算撞後速度並重新指定給 vy1, vy2
if(b2.pos.y - b1.pos.y <= r1 + r2):
b1.v.y, b2.v.y = af_col_v(b1.m, b2.m, b1.v.y, b2.v.y)
# 更新時間
t += dt
```
<br />
### 參數設定
在此設定變數為小球的半徑、質量、顏色,小球離地高度、地板邊長、重力加速度、時間、時間間隔,對應的變數名稱請參考程式碼。
<br />
### 畫面設定
產生動畫視窗、地板、小球、繪圖視窗的程式碼在之前動畫當中已經出現很多次,這裡就不再贅述。比較特別之處在於動畫視窗中多加了一個選項 **range=L**,這是為了限制動畫視窗顯示範圍,使畫面不會因為上方的小球反彈到太高的地方而自動縮小。
<br />
### 物體運動部分
1. 更新小球速度、位置。
2. 繪製小球 y-t、v-t 圖。
3. 若 **b1.pos.y <= 0 代表 b1 撞到地板**,將速度加上負號使 b1 反彈。
4. 若 **b2.pos.y - b1.pos.y <= r1 + r2 代表 b1、b2 相撞**,將 m1、b1.v.y、m2、b2.v.y 代入自訂函式 af_col_v 中計算撞後速度,再重新指定給 b1.v.y、b2.v.y。
<br />
### 模擬結果
我測試了 2 種不同的條件:
1. r1 = 2, m1 = 2, r2 = 1, m2 = 1
2. r1 = 1, m1 = 1, r2 = 2, m2 = 2
當下方的小球 b1 較重時,b2 反彈的高度會遠超過原本的離地高度。當下方的小球 b1 較輕時,b1 會不斷地在地板和 b2 之間來回反彈。
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/UJuYRwc.png">
<div style="text-align:center">條件1的模擬結果:高度 - 時間關係圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/XcNM95o.png">
<div style="text-align:center">條件1的模擬結果:速度 - 時間關係圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/EEZiKly.png">
<div style="text-align:center">條件2的模擬結果:高度 - 時間關係圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/EMjjHPc.png">
<div style="text-align:center">條件2的模擬結果:速度 - 時間關係圖</div>
<br />
## 程式 16-2.自由落下三球碰撞 ([取得程式碼](https://github.com/YiZheWangTw/VPythonTutorial/blob/master/16.%E8%87%AA%E7%94%B1%E8%90%BD%E4%B8%8B%E5%85%A9%E7%90%83%E7%A2%B0%E6%92%9E/16-2_bounce.py)) ([GlowScript 網站動畫連結](http://www.glowscript.org/#/user/yizhe/folder/Public/program/16-2bounce))
```python=
"""
VPython教學: 16-2.自由落下三球碰撞
Ver. 1: 2018/2/28
Ver. 2: 2019/9/14
作者: 王一哲
"""
from vpython import *
"""
1. 參數設定, 設定變數及初始值
(1) r1 = 3, m1 = 3, r2 = 2, m2 = 2, r3 = 1, m3 = 1
(2) r1 = 1, m1 = 1, r2 = 2, m2 = 2, r3 = 3, m3 = 3
"""
r1, m1, c1 = 3, 3, color.red # 小球1半徑, 質量, 顏色
r2, m2, c2 = 2, 2, color.green # 小球2半徑, 質量, 顏色
r3, m3, c3 = 1, 1, color.blue # 小球3半徑, 質量, 顏色
h, L = 15, 50 # 小球離地高度, 地板邊長
g = 9.8 # 重力加速度 9.8 m/s^2
t, dt = 0, 0.001 # 時間, 時間間隔
"""
2. 畫面設定
"""
# 產生動畫視窗
scene = canvas(title="Free Fall and Collision", width=600, height=600, x=0, y=0,
center=vec(0, h/2, 0), background=vec(0, 0.6, 0.6), range=L)
# 產生地板
floor = box(pos=vec(0, -r1, 0), size=vec(L, 0.01, L), texture=textures.wood)
# 產生小球並設定初速度、加速度
b1 = sphere(pos=vec(0, h, 0), radius=r1, color=c1, m=m1, v=vec(0, 0, 0), a=vec(0, -g, 0))
b2 = sphere(pos=vec(0, h+r1+r2, 0), radius=r2, color=c2, m=m2, v=vec(0, 0, 0), a=vec(0, -g, 0))
b3 = sphere(pos=vec(0, h+r1+2*r2+r3, 0), radius=r3, color=c3, m=m3, v=vec(0, 0, 0), a=vec(0, -g, 0))
# y-t plot
gd = graph(title="<i>y</i>-<i>t</i> plot", width=600, height=450, x=0, y=600,
xtitle="<i>t</i> (s)", ytitle="red: <i>y</i><sub>1</sub>, green: <i>y</i><sub>2</sub>, blue: <i>y</i><sub>3</sub> (m)")
yt1 = gcurve(graph=gd, color=c1)
yt2 = gcurve(graph=gd, color=c2)
yt3 = gcurve(graph=gd, color=c3)
# v-t plot
gd2 = graph(title="<i>v</i>-<i>t</i> plot", width=600, height=450, x=0, y=1050,
xtitle="<i>t</i> (s)", ytitle="red: <i>v</i><sub>2</sub>, green: <i>v</i><sub>2</sub>, blue: <i>v</i><sub>3</sub> (m/s)")
vt1 = gcurve(graph=gd2, color=c1)
vt2 = gcurve(graph=gd2, color=c2)
vt3 = gcurve(graph=gd2, color=c3)
# 一維彈性碰撞速度公式
def af_col_v(m1, m2, v1, v2):
v1_prime = (m1-m2)/(m1+m2)*v1 + (2*m2)/(m1+m2)*v2
v2_prime = (2*m1)/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2
return (v1_prime, v2_prime)
"""
3. 物體運動部分, 小球觸地時反彈
"""
while(t < 20):
rate(1000)
# 更新小球速度、位置
b1.v += b1.a*dt
b1.pos += b1.v*dt
b2.v += b2.a*dt
b2.pos += b2.v*dt
b3.v += b3.a*dt
b3.pos += b3.v*dt
# 繪製小球 y-t、v-t 圖
yt1.plot(pos=(t, b1.pos.y))
yt2.plot(pos=(t, b2.pos.y))
yt3.plot(pos=(t, b3.pos.y))
vt1.plot(pos=(t, b1.v.y))
vt2.plot(pos=(t, b2.v.y))
vt3.plot(pos=(t, b3.v.y))
# 若 b1 撞到地板則反彈
if(b1.pos.y <= 0 and b1.v.y < 0): b1.v.y = -b1.v.y
# 若 b1、b2 相撞則計算撞後速度並重新指定給 vy1, vy2
if(b2.pos.y - b1.pos.y <= r1 + r2):
b1.v.y, b2.v.y = af_col_v(b1.m, b2.m, b1.v.y, b2.v.y)
# 若 b2、b3 相撞則計算撞後速度並重新指定給 vy2, vy3
if(b3.pos.y - b2.pos.y <= r2 + r3):
b2.v.y, b3.v.y = af_col_v(b2.m, b3.m, b2.v.y, b3.v.y)
# 更新時間
t += dt
```
<br />
### 程式設計部分
程式 16-2 和 16-1 幾乎相同,只是多了一個小球 b3。
<br />
### 模擬結果
我測試了 2 種不同的條件:
1. r1 = 3, m1 = 3, r2 = 2, m2 = 2, r3 = 1, m3 = 1
2. r1 = 1, m1 = 1, r2 = 2, m2 = 2, r3 = 3, m3 = 3
當下方的小球 b1、b2 比 b3 重時,b3 反彈的高度會遠超過原本的離地高度。當下方的小球 b1 較輕時,b1 會不斷地在地板和 b2 之間來回反彈。
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/lYU0IhV.png">
<div style="text-align:center">條件1的模擬結果:高度 - 時間關係圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/xd4cZE3.png">
<div style="text-align:center">條件1的模擬結果:速度 - 時間關係圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/t0gwGKs.png">
<div style="text-align:center">條件2的模擬結果:高度 - 時間關係圖</div>
<br />
<img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/rLEABn2.png">
<div style="text-align:center">條件2的模擬結果:速度 - 時間關係圖</div>
<br />
## 結語
當我們寫過較多的程式之後,寫程式的速度會開始變快,熟練度較高是原因之一,同時也更懂得利用之前寫好的程式碼,例如這次就是利用了自由落下和一維彈性碰撞的程式。接下來可以試著發揮創意,將之前寫過的程式碼組合成有趣的東西。
<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`