# 自由落下 > 作者:王一哲 > 日期: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`