Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Raspberry Pi 寵物小車

157,269 views

Published on

更新的投影片請參考 ==> http://bit.ly/2ztfSDV

更新的範例程式(在Pi做)
$ cd ~
$ wget http://goo.gl/V9HJW6 -O pi-follower-car.tar.gz
$ tar zxvf pi-follower-car.tar.gz

---

MakerConf 206 工作坊
http://www.makerconf.tw/?p=238

寵物小車特色:
1. 8 小時工作坊課程。
2. 可根據自訂顏色讓小車移動跟蹤。
3. 內容包含:
- GPIO 介紹。
- 馬達控制。
- 小車組裝與控制。
- Raspberry Pi Camera 介紹。
- 基礎 Camera 使用。
- 數位影像處理與 OpenCV。

展示影片
https://www.youtube.com/watch?v=wIBaFXD_2SM

範例程式:
https://github.com/raspberrypi-tw/pi-follower-car

購買學習套件:
https://www.raspberrypi.com.tw/13504/pi-follower-car-starter-kit/

Published in: Technology

Raspberry Pi 寵物小車

  1. 1. Raspberry Pi 工作坊 - 寵物小車 台灣樹莓派 <sosorry@raspberrypi.com.tw> Sep 03, 2016@MakerConf
  2. 2. 姓名標示 — 非商業性 — 相同方式分享 CC (Creative Commons) 姓名標示 — 你必須給予 適當表彰、提供指向本授權 條款的連結,以及 指出(本作品的原始版本)是否已 被變更。你可以任何合理方式為前述表彰,但不得以 任何方式暗示授權人為你或你的使用方式背書。 非商業性 — 你不得將本素材進行商業目的之使 用。 相同方式分享 — 若你重混、轉換本素材,或依本 素材建立新素材,你必須依本素材的授權條款來 散布你的貢獻物。
  3. 3. 3 ● element14 指定台灣地區 Raspberry Pi 個人用戶經銷商 about 台灣樹莓派 http://farnell.com/raspberrypi-consumer/approved-retailers.php?region=apac&MER=MER-LM-OB-RPICC-76315
  4. 4. ● 專注於 Raspberry Pi 應用與推廣 ● 舉辦社群聚會 / 工作坊 / 讀書會 / 黑客松 ● Website : ● https://www.raspberrypi.com.tw/ ● Facebook : ● 搜尋 RaspberryPi.Taiwan ● https://www.facebook.com/RaspberryPi.Taiwan about 台灣樹莓派
  5. 5. 5 ● COSCUP, MakerConf, PyCon 講者 ● 投影片 ● http://www.slideshare.net/raspberrypi-tw/presentations ● 程式碼 ● https://github.com/raspberrypi-tw 分享 x 社群
  6. 6. 6 ● 馬達與小車介紹 ● GPIO 介紹 ● 馬達控制 ● 小車組裝與控制 ● Raspberry Pi Camera 介紹 ● 基礎 Camera 使用 ● 數位影像處理與 OpenCV 今日主題
  7. 7. ● 信用卡大小般的電腦 Raspberry Pi 是什麼 ? http://www.flickr.com/photos/fotero/7697063016/
  8. 8. 硬體規格 http://goo.gl/v0ydxG
  9. 9. 9 連接週邊 http://vimeo.com/90103691
  10. 10. 10 選一套喜歡的 OS http://en.wikipedia.org/wiki/Raspberry_Pi
  11. 11. 11 立馬取代桌上型電腦 http://functy.sourceforge.net/?p=328
  12. 12. 12 還可以做更多
  13. 13. 13 http://makezine.com/2013/04/14/47-raspberry-pi-projects-to-inspire-your-next-build/
  14. 14. Raspberry Pi Family http://raspi.tv/2016/raspberry-pi-family-photo-updated-to-include-pi3b-29-feb-2016
  15. 15. 15 ● 硬體 : Raspberry Pi 3 ● 作業系統 : 2016-05-29-raspbian-jessie.img ● 為了可以使用 USB 轉 TTL 傳輸線 ● 修改 /boot/config.txt, 來停用 SoC 的藍牙功能 – dtoverlay=pi3-disable-bt 今日環境 https://www.raspberrypi.com.tw/10842/raspberry-pi-3-uart-overlay-workaround/
  16. 16. 沒有螢幕與鍵盤如何使用樹莓派?
  17. 17. 17 環境設定: Serial + WiFi 1. 樹莓派 Serial 連線 2. 樹莓派 WiFi 連線 用 Serial 來設定 WiFi 3. 筆電、手機、樹莓派 在同一個 LAN
  18. 18. 18 ● 以 USB 轉 TTL 傳輸線和 Pi 相連 ● 接線方式 ● 黑色 / 白色 / 綠色照圖接 ● 紅色不接 Serial 連線方式
  19. 19. 放大圖 黑色線接 6 號 白色線接 8 號 綠色線接 10 號 http://www.raspberrypi-spy.co.uk/2014/07/raspberry-pi-b-gpio-header-details-and-pinout/
  20. 20. ● 安裝驅動程式 , http://goo.gl/QC5Q3O ● 從裝置管理員找到 COM 的埠號 ( 本例為 COM9) Serial Port in Windows
  21. 21. ● 下載 putty, http://goo.gl/zdD9G9 ● 執行 putty ● 1. 選擇 Session ● 2. 選擇 Serial ● 3. Serial line 填 COM9 ● 4. Speed 填入 115200 ● 5. Open ! ● 沒畫面 , 先按 ENTER ● 再不行 , 重插拔電源 Serial Port in Windows - 2
  22. 22. 22 ● $ ls /dev/ttyUSB* ● 開啟 putty ● 選擇 Session ● 在 Serial line 填入 /dev/ttyUSB0 ( 本例為 ttyUSB0) ● Speed 填入 115200 ● Open ! ● 無法連線時 , 使用 sudo 執行 putty Serial Port in Linux
  23. 23. 23 ● 安裝驅動程式 , http://goo.gl/htlt3F ● 重開機生效 ● $ ls /dev/cu* ● 如果有 /dev/cu.usbserial ● $ screen /dev/cu.usbserial 115200 ● 如果沒畫面 , 重新插拔電源 (PL2303 不要拔 ) Serial Port in Mac
  24. 24. 24 ● 預設帳號 / 密碼: pi / raspberry ● 如果沒有畫面 , 先按 Enter, 再不行 , 重新插拔電源 ● 如果出現亂碼 , 確定 baud rate 為 115200 連線成功
  25. 25. 25 ● 登入畫面 ● pi 是登入的使用者 ● @ 表示”在” ● raspberrypi 是主機名稱 ● ~ 表示在家目錄 (home directory) ● $ 表示該使用者所使用的 shell( 一種文字工具介面 ) 符號說明
  26. 26. 26 使用: nano <NAME_OF_FILE> 離開: Ctrl + x > 令存新檔: y > 不存離開: n > 離開: Ctrl + c nano 編輯器使用
  27. 27. 27 $ ifconfig wlan0 IP = 192.168.43.102 查詢 IP
  28. 28. 28 就可以使用 SSH 連線
  29. 29. 29 ● Serial 以實體線路相連 , 純文字 , 是獨占式的連線 ● SSH 是 TCP/IP 通訊協定 , 透過 Ethernet 或 WiFi 連線 Serial 連線和 SSH 連線有什麼不同?
  30. 30. ● $ sudo apt-get update ● $ sudo apt-get install -y python-opencv ● $ sudo apt-get install -y python-dev ● $ sudo apt-get install -y python-pip ● $ sudo pip install readchar ● $ sudo pip install bottle 安裝今日所需軟體
  31. 31. 31 Raspberry Pi GPIO 介紹
  32. 32. 32 ● General Purpose Input Output ● GPIO 是一種可用軟體控制的數位訊號 什麼是 GPIO ? http://www.tek.com/datasheet/tps2000b-series-digital-storage-oscilloscopes-datasheet
  33. 33. 33 ● 決定是輸入還是輸出 ● 輸出:寫值到某根腳位 ● 輸入:從某根腳位讀值 ● 等待中斷 (interrupt) 的發生 ● 決定是正緣觸發還是負緣觸發 用軟體控制什麼 ?
  34. 34. 34 GPIO 腳位在哪裡? http://www.raspberrypi-spy.co.uk/ Pin1 Pin2 Pin25 Pin26 Pin3 Pin4Z Z 字型的腳位編號
  35. 35. 35 ● C ● C + wiringPi ● C# ● Ruby ● Perl ● Python ● Scratch ● Java Pi4J Library ● Shell script 如何控制 Raspberry Pi 的 GPIO ?
  36. 36. 36 數位輸出
  37. 37. 37 實驗 1-1 :硬體的 Hello World 目的:從硬體到軟體的思維
  38. 38. 38 ● 發光二極體 ● 單向導通 ● 省電 LED http://upload.wikimedia.org/wikipedia/commons/c/c8/5mm_Red_LED.jpg 長腳接正極 Vcc 短腳接負極 GND
  39. 39. 39 要接哪一個腳位?
  40. 40. 40 要接哪一個腳位? 目標:一隻腳接地 , 一隻腳給電
  41. 41. 41 線路圖 LED RPi 長腳 (RED) Pin12 (GPIO18) 短腳 (BLACK) Pin6 (Ground)
  42. 42. 42 麵包板的種類 https://goo.gl/JipVgH
  43. 43. 43 麵包板的使用 http://bugworkshop.blogspot.tw/2012/12/diy-breadboard.html 1. 藍色和綠色兩塊不通 2. 藍色垂直相通 3. 紅色水平相通 麵包板的內部結構
  44. 44. 44 使用麵包板 LED RPi 長腳 (RED) Pin12 (GPIO18) 短腳 (BLACK) Pin6 (Ground)
  45. 45. 45 開始用 Python 控制 GPIO 吧
  46. 46. 46 ● 載入模組 (Import module) ● 選擇編號系統 (Define pin numbering) ● 定義腳位 (Setup up a channel) ● 讀取輸入 / 寫入輸出 (Input/Output) ● 清理 (Cleanup) Python Code 基本流程 http://code.google.com/p/raspberry-gpio-python/wiki/BasicUsage
  47. 47. 47 #!/usr/bin/python ● ● import RPi.GPIO as GPIO # 載入模組 ● import time ● ● GPIO.setmode(GPIO.BOARD) # 選擇系統( 以實體腳位系統為例) ● GPIO.setup(12, GPIO.OUT) # 定義腳位 ● ● print("LED is on") ● GPIO.output(12, GPIO.HIGH) # 設定腳位狀態 ● time.sleep(3) ● ● GPIO.cleanup() # 清理 ● 一分鐘學會用 Python 控制 GPIO
  48. 48. 48 ● Wiki ● http://sourceforge.net/p/raspberry-gpio-python/wiki/Home/ ● 用 Raspberry Pi 學 GPIO - 自己做遊戲機 ● http://www.slideshare.net/raspberrypi-tw/gpio-gameconsolestarterkit 更多 RPi.GPIO 的使用方法
  49. 49. 49 DEMO led_on.py
  50. 50. 50 ● cd < 目錄 > # 跳到 < 目錄 > ● cd .. # 回上一層 ● cd ~ # 回 < 家目錄 > ● pwd # 查看目前工作目錄 ● ls # 列出檔案與目錄 ● sudo reboot # 重開機 你必須知道的 Linux 指令
  51. 51. 51 $ cd ~ $ https://github.com/raspberrypi-tw/pi-follower-car $ cd pi-follower-car $ cd 01-gpio $ cd 01_1-led_on $ sudo python led_on.py 讀寫 GPIO 會存取 /dev/mem, 需 root 權限 (2015-09-24 以後的 image 可以用一般使用者身份執行 ) 執行方式
  52. 52. 52 實驗 1-2 :控制 LED 閃爍 目的:熟悉 Python 語法
  53. 53. 53 一樣的線路圖 LED RPi 長腳 (RED) Pin12 (GPIO18) 短腳 (BLACK) Pin6 (Ground)
  54. 54. 54 GPIO.setmode(GPIO.BOARD) ● LED_PIN = 12 ● GPIO.setup(LED_PIN, GPIO.OUT) ● ● whileTrue: ● print("LED is on") ● GPIO.output(LED_PIN, GPIO.HIGH) ● time.sleep(1) ● print("LED is off") ● GPIO.output(LED_PIN, GPIO.LOW) ● time.sleep(1) ● ● GPIO.cleanup() 永不停止的 while 迴圈 - 按 Ctrl+c 跳出迴圈
  55. 55. 55 DEMO led_blink_warning.py $ cd .. $ cd 02_1-led_blink_warning $ sudo python led_blink_warning.py
  56. 56. 56 RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
  57. 57. 57 為什麼出現 Warning ?
  58. 58. 58 try: ● whileTrue: ● print("LED is on") ● GPIO.output(LED_PIN, GPIO.HIGH) ● time.sleep(1) ● print("LED is off") ● GPIO.output(LED_PIN, GPIO.LOW) ● time.sleep(1) ● except KeyboardInterrupt: ● print "Exception: KeyboardInterrupt" ● finally: ● GPIO.cleanup() 接住例外
  59. 59. 59 DEMO led_blink.py $ cd .. $ cd 01_3-led_blink $ sudo python led_blink.py
  60. 60. 60 實驗 1-4 :改變 LED 亮度 目的:調變脈衝寬度輸出脈波
  61. 61. 61 ● 數位: 0 與 1 的訊號 ● 類比:連續的訊號 數位與類比 http://www.bitscope.com/software/blog/DJ/?p=DJ19A
  62. 62. 62 ● 數位:亮和不亮 ● 類比:亮 , 有點亮 , 有點不亮 ..., 不亮 ● 可是 GPIO 腳位輸出都是固定值 , 怎麼辦? 從 LED 的角度來看
  63. 63. 63 ● 旋轉式 , 滑動式 ● 線性關係 (B 型 ), 對數關係 (A 型 ) ● 常見規格: 0 -10k Ohm( 線性 ) 可變電阻 Potentiometer(VR) https://en.wikipedia.org/wiki/Potentiometer 接高電位 接低電位 滑動接點 ( 可變輸出 )
  64. 64. 64 利用可變電阻讓 LED 亮度改變
  65. 65. 65 有不使用額外硬體的方法嗎?
  66. 66. 66 ● 是將類比信號轉為脈波的一種技術 ● 改變工作比 (duty cycle) = 改變電壓 ● Duty cycle = pulse width x100 / period ( 單位 :%) 脈寬調變 (Pulse-Width Modulation) http://www.protostack.com/blog/2011/06/atmega168a-pulse-width-modulation-pwm/
  67. 67. 67 ● 類比輸出電壓 = 脈衝寬度 (duty cycle)x 高電位值 公式計算 http://www.societyofrobots.com/schematics_h-bridgedes.shtml
  68. 68. 68 ● To create a PWM instance: ● p = GPIO.PWM(channel, frequency) ● To start PWM: ● p.start(dc) # where dc is the duty cycle (0.0 <= dc <= 100.0) ● To change the duty cycle: ● p.ChangeDutyCycle(dc) # where 0.0 <= dc <= 100.0 ● To stop PWM: ● p.stop() GPIO.PWM() http://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/
  69. 69. 69 線路圖 LED RPi 長腳 (RED) Pin12 (GPIO18) 短腳 (BLACK) Pin6 (Ground)
  70. 70. 70 PWM_PIN = 12 ● GPIO.setup(PWM_PIN, GPIO.OUT) pwm = GPIO.PWM(PWM_PIN, 500) ● pwm.start(0) ● ● try: ● whileTrue: ● duty_s = raw_input("Enter Brightness (0 to 100):") ● duty = int(duty_s) ● ● if duty >= 0 and duty <=100 : ● pwm.ChangeDutyCycle(duty) ● ● except KeyboardInterrupt: ● pwm.stop() ● GPIO.cleanup() 互動式的調光
  71. 71. 71 DEMO pwm_led.py $ cd .. $ cd 01_4-pwm_led $ sudo python pwm_led.py
  72. 72. 72 實驗 2-1 :馬達驅動 目的:用電晶體電路驅動馬達
  73. 73. 73 ● 直流馬達 (DC motors) ● 伺服馬達 (Servo motors) ● 步進馬達 (Stepper motors) 馬達種類 https://learn.adafruit.com/adafruit-motor-selection-guide
  74. 74. 74 https://learn.adafruit.com/adafruit-motor-selection-guide
  75. 75. 75 直流 ( 碳刷 ) 馬達 https://learn.adafruit.com/adafruit-motor-selection-guide 永久磁鐵定子 轉子和線圈 整流子 電源 Fleming's Left Hand Rule
  76. 76. 76 ● 速度和負重的需求 ( 負載 ) ● 轉速 ● 扭力 ( 轉矩 ) ● 電源和控制器的配置 ● 工作電壓 ● 消耗電流 ● 堵轉電流 FA-130RA 直流馬達規格 工作電壓 空載 堵轉負載
  77. 77. 77 1. 馬達和直流電源直接相接 http://www.simplecircuitsandprojects.com/circuits/dc-motor.html 順時鐘旋轉 逆時鐘旋轉
  78. 78. 78 控制電路 Motor RPi 馬達 A(Green) Pin16(GPIO4) 馬達 A(Yellow) Pin20(Ground) 馬達 A
  79. 79. 79 GPIO.setmode(GPIO.BOARD) GPIO.setup(MOTOR_PIN, GPIO.OUT) try: while True: print("Motor start ...") GPIO.output(MOTOR_PIN, GPIO.HIGH) time.sleep(2) print("Motor stop !!!") GPIO.output(MOTOR_PIN, GPIO.LOW) time.sleep(2) finally: GPIO.cleanup() ● 轉 - 停 - 轉 - 停 -
  80. 80. 80 DEMO dc_motor.py $ cd ../../02-motor $ cd 02_1-dc_motor $ sudo python dc_motor.py
  81. 81. 81 為什麼不會動 ?
  82. 82. 82 ● 電源和控制器的配置 ● 工作電壓 ● 消耗電流 ● 堵轉電流 ● Raspberry Pi GPIO 的電流輸出為 2 mA 到 16 mA 重新檢視直流馬達規格 工作電壓 空載 堵轉負載
  83. 83. 83 ● 一種可放大、開關、穩壓、信號調節的元件 ● 由於微處理器的輸出微弱,無法驅動大型負載 ● 但可透過電晶體放大訊號,控制外部裝置 3. 透過電晶體驅動馬達 https://learn.adafruit.com/adafruit-motor-selection-guidehttp://de.wikipedia.org/wiki/Transistor 常用符號
  84. 84. 84 水管閥門功能 https://learn.adafruit.com/adafruit-motor-selection-guidehttp://commons.wikimedia.org/wiki/File:Transistor_animation.gif E( 射極 ) 射出電流 C( 集極 ) 收集電流 B( 基極 ) 控制閥門 微小電流就可控制 允許大電流通過 推動大型負載 腳位意義 ( 依功能分 ) 實際運作情形
  85. 85. 85 控制電路 Motor RPi 馬達 A(Green) Pin16(GPIO4) 馬達 A(Yellow) Pin20(Ground)
  86. 86. 86 GPIO.setmode(GPIO.BOARD) GPIO.setup(MOTOR_PIN, GPIO.OUT) try: while True: print("Motor start ...") GPIO.output(MOTOR_PIN, GPIO.HIGH) time.sleep(2) print("Motor stop !!!") GPIO.output(MOTOR_PIN, GPIO.LOW) time.sleep(2) finally: GPIO.cleanup() ● 控制的是電晶體
  87. 87. 87 實驗 2-2 :控制馬達轉向 目的:瞭解車子移動的原理
  88. 88. 88 ● C 極外部電源提供馬達轉動 ● B 極發送控制訊號讓電晶體導通 ● 一個電晶體電路可控制馬達轉動 回顧剛剛的電路圖 https://learn.adafruit.com/adafruit-motor-selection-guidehttp://www.robotoid.com/my-first-robot/rbb-bot-phase2-part1.html E( 射極 ) 射出電流 C( 集極 ) 收集電流 B( 基極 ) 控制閥門
  89. 89. 89 ● 每一個節點都是電晶體控制電路 控制馬達轉向 - H 橋式電路 https://learn.adafruit.com/adafruit-motor-selection-guidehttp://www.robotoid.com/my-first-robot/rbb-bot-phase2-part1.html
  90. 90. 90 如何用程式控制? https://learn.adafruit.com/adafruit-motor-selection-guide 連接 作用 Q1 和 Q4 順時鐘轉動 Q3 和 Q2 逆時鐘轉動 Q1 和 Q3 煞車 無 慣性自由轉動 Q1 和 Q2 短路 ! Q3 和 Q4 短路 ! http://www.robotoid.com/my-first-robot/rbb-bot-phase2-part1.html
  91. 91. 91 如何用程式控制? https://learn.adafruit.com/adafruit-motor-selection-guide 連接 作用 Q1 和 Q4 順時鐘轉動 Q3 和 Q2 逆時鐘轉動 Q1 和 Q3 煞車 無 慣性自由轉動 Q1 和 Q2 短路 ! Q3 和 Q4 短路 ! http://www.robotoid.com/my-first-robot/rbb-bot-phase2-part1.html 可是 ... 1. 不小心給錯電就會把電晶體燒掉 2. 一個馬達要搭配四個電晶體電路 3. 我想要一次控制兩個馬達的轉動
  92. 92. 92 ● 馬達驅動晶片 : L298N ● 雙 H 橋式直流 ( 步進 ) 馬達驅動 ● 最大馬達驅動電壓 : DC 50V ● 降壓晶片 : 78M05 ● 將外部輸入電源降壓為 DC 5V 給電路板 ● 外部輸入電源電壓限制範圍 : DC 7V - DC 35V L298N 馬達控制板 https://learn.adafruit.com/adafruit-motor-selection-guide
  93. 93. 93 OUT1 OUT2 OUT3 OUT4 ENA: OUT1, OUT2 生效 IN1 IN2 IN3 IN4 馬達控制接腳: IN1-2 : OUT1-2 IN3-4 : OUT3-4 ENB: OUT3, OUT4 生效 輸出電源 ( 正極 ) 電源 ( 負極 ) 輸入電源 ( 正極 )
  94. 94. 94 單輪電路圖 (L298N 要和 Pi 共接地 ) L298N RPi IN1(Green) Pin16(GPIO4) IN2(Yellow) Pin18(GPIO5) 馬達 A L298N Motor OUT1(Yellow) 馬達 A(Yellow) OUT2(Green) 馬達 A(Green)
  95. 95. 95 Motor_R1_Pin = 16 ● Motor_R2_Pin = 18 GPIO.setmode(GPIO.BOARD) GPIO.setup(Motor_R1_Pin, GPIO.OUT) GPIO.setup(Motor_R2_Pin, GPIO.OUT) try: GPIO.output(Motor_R1_Pin,True) # clockwise time.sleep(3) GPIO.output(Motor_R1_Pin, False) ● time.sleep(1) # protect motor GPIO.output(Motor_R2_Pin,True) # counterclockwise time.sleep(3) GPIO.output(Motor_R2_Pin, False) finally: GPIO.cleanup() 控制單輪正反轉
  96. 96. 96 DEMO l298n_motor.py $ cd .. $ cd 02_2-l298n_motor $ sudo python l298n_motor.py
  97. 97. 97 如何控制馬達轉速?
  98. 98. 98 ● 改變電壓的方式 ● 增加 ( 減少 ) 電池 ● 增加負載 ( 利用可變電阻 ) ● 脈寬調變 (PWM) 技術 直流馬達轉速由輸入電壓決定
  99. 99. 99 一樣的線路圖 L298N RPi IN1(Green) Pin16(GPIO4) IN2(Yellow) Pin18(GPIO5) 馬達 A L298N Motor OUT1(Yellow) 馬達 A(Yellow) OUT2(Green) 馬達 A(Green)
  100. 100. 100 PWM_PIN = 12 ● GPIO.setup(PWM_PIN, GPIO.OUT) pwm = GPIO.PWM(PWM_PIN, 500) ● pwm.start(0) ● ● try: ● whileTrue: ● duty_s = raw_input("Enter Duty Cycle (0 to 100):") ● duty = int(duty_s) ● ● if duty >= 0 and duty <=100 : ● pwm.ChangeDutyCycle(duty) ● ● except KeyboardInterrupt: ● pwm.stop() ● GPIO.cleanup() 使用 PWM 調整輸出電壓
  101. 101. 101 DEMO pwm_l298n.py $ cd .. $ cd 02_3-pwm_l298n $ sudo python pwm_l298n.py
  102. 102. 102 實驗 2-4 :遙控車 目的:瞭解小車的各項機構
  103. 103. 103 ● 車體 ( 機構 ) ● 馬達 / 車輪 ( 動力 ) ● 控制板 / 微處理器 ( 邏輯 ) ● 無線網路 / 紅外線 / 藍牙 ( 傳輸控制 ) 遙控車的組成
  104. 104. 104 先動手組裝車體吧 !
  105. 105. 105 所有零件 ( 含 Pi 和 L298N)
  106. 106. 106 馬達與固定螺絲
  107. 107. 107 固定在車體上 接線朝內
  108. 108. 108 第二個馬達依樣畫葫蘆 + 裝輪胎
  109. 109. 109 萬向輪和固定螺絲
  110. 110. 110 組裝萬向輪 有帽子的螺絲
  111. 111. 111 固定在車體上
  112. 112. 112 L298N 和固定螺絲
  113. 113. 113 安裝兩個螺絲即可
  114. 114. 114 固定在車體上 + 馬達接線
  115. 115. 115 電池盒和固定螺絲
  116. 116. 116 安裝在車體上並接線
  117. 117. 117 Pi 和固定螺絲
  118. 118. 118 固定在車體上 ( 可能會需要鑽孔 )
  119. 119. 119 和 L298N 相接 共接地 L298N RPi IN1(Brown) Pin16 IN2(RED) Pin18 IN3(Orange) Pin11 IN4(Yellow) Pin13
  120. 120. 120 安裝相機模組 相機模組
  121. 121. 121 從正面看的角度
  122. 122. 122 ● 向前走 ( 雙輪逆時鐘旋轉 ) ● 向後走 ( 雙輪順時鐘旋轉 ) ● 向右轉 ( 左輪逆時鐘轉 , 右輪靜止 ) ● 向左轉 ( 右輪逆時鐘轉 , 左輪靜止 ) 車子如何移動? 前 左
  123. 123. 123 雙輪電路圖 L298N RPi IN1(Green) Pin16(GPIO4) IN2(Yellow) Pin18(GPIO5) IN3(Purple) Pin11(GPIO0) IN4(Orange) Pin13(GPIO1) 馬達 A 馬達 B L298N Motor OUT1(Yellow) 馬達 A(Yellow) OUT2(Green) 馬達 A(Green) OUT3(Purple) 馬達 B(Green) OUT4(Orange) 馬達 B(Yellow)
  124. 124. 124 ● def stop(): # stop all wheels def forward(): GPIO.output(16,True) GPIO.output(18, False) GPIO.output(11,True) GPIO.output(13, False) time.sleep(1) stop() try: while True: ● ch = readchar.readkey() ● ● if ch == 'w': ● forward() 控制小車移動
  125. 125. 125 DEMO move_car.py $ cd .. $ cd 02_4-move_car $ sudo python move_car.py
  126. 126. 126 實驗 3-1 : Raspberry Pi Camera 目的: Camera 與 OpenCV 使用
  127. 127. Raspberry Pi Camera 介紹
  128. 128. 從手機相機模組講起 http://www.phonearena.com/news/13MP-camera-tipped-for-Samsung-Galaxy-S-IV_id35168 1. Lens( 透鏡 ) 2.VCM( 音圈馬達 ) 3. IR-Cut( 紅外光濾片 ) 4. Sensor( 感光元件 ) 5. PCB( 印刷電路板 ) 6. ISP( 影像訊號處理器 )
  129. 129. ● 問:樹葉為什麼看起來是綠色的? ● 答:因為樹葉吸收了大部分可見光,只反射綠色光 基礎光學原理 https://www.raspberrypi.org/learning/infrared-bird-box/worksheet/
  130. 130. Type of Raspberry Pi Camera http://elinux.org/Rpi_Camera_Module Raspberry Pi Camera Module NoIR Camera Module
  131. 131. ● Sensor: OmniVision OV5647 Color CMOS QSXGA (5MP) ● 靜態拍照最高解析度: 2592 x 1944 pixel ● Pixel Size: 1.4 x 1.4 µm ● Lens: f=3.6 mm, f/2.9 ● Angle ofView: 54 x 41 degrees ● Field ofView: 2.0 x 1.33 m at 2 m ● Fixed Focus: 1m ● 動態攝影最高解析度: 1080p@30 FPS with H.264/AVC 技術規格
  132. 132. Raspberry Pi Camera Module(v1) https://www.modmypi.com 15-Pins, CSI 介面 綠色 PCB 板
  133. 133. ● No IR = No 'IR cut filter' installed ● 因此 CMOS 可吸收到不可見光 (Infrared) ● No IR 相機 ≠ 夜視相機 ● 除非有額外的紅外線發光源 No IR Camera (v1) 黑色 PCB 板
  134. 134. 兩種相機效果比較 http://www.themagpi.com/issue/issue-18/ 1. 非 NoIR 相機 2. NoIR 相機 3. NoIR 相機 4. NoIR 相機 + 藍色濾光片
  135. 135. Camera 安裝
  136. 136. 安裝 Raspberry Pi Camera http://goo.gl/7LqyMY
  137. 137. $ sudo raspi-config
  138. 138. 啟用 Raspberry Pi Camera
  139. 139. 進階選項
  140. 140. 設定記憶體分配 >128M
  141. 141. Camera 使用
  142. 142. ● 只預覽 2 秒 (-t), 不存檔 ● $ raspistill -t 2000 ● 5 秒後拍照 ( 預設 ), 檔案 test.jpg(-o) ● $ raspistill -o test.jpg ● 3 秒後拍照 , 並編碼成 png 格式 (-e), 長 640x 寬 480 ● $ raspistill -t 3000 -o test.png -e png -w 640 -h 480 RaspiStill https://www.raspberrypi.org/documentation/usage/camera/raspicam/raspistill.md
  143. 143. 如何看拍照結果?
  144. 144. 方法一:使用 X11 Forwarding
  145. 145. 145 ● 是一種圖形應用標準 ● Client/Server 架構 ● X Client : 應用程式 ● X Server : 管理硬體輸入 / 輸出 ● 可透過網路傳輸 ● TCP/IP 或是 Unix Domain Socket ● X11 是通訊協定名稱 X Window System http://keyj.emphy.de/files/linuxgraphics_en.pdf
  146. 146. 146 ● Windows( 使用 Xming + putty) ● Xming 安裝 (http://sourceforge.net/projects/xming/)+ 下一步到底 ● putty > SSH > X11 > Enable X11 forwarding ● Linux/Mac : ssh -X pi@ip.of.pi X11 Forwarding using SSH
  147. 147. ● 看照片 ● $ gpicview image.jpg ● 如果不行 , 先確認 1. 是不是使用 SSH 連線? 不能使用 COM 連線 ! 2. SSH 是以 X11 Forwarding 方式連線嗎? 3. 如果是 Windows, 上面的 Xming 有跑起來嗎? X11 Forwarding 連線成功後
  148. 148. ● 在 Mac 上 ● 第一步:編輯 /etc/sshd_config 修改這行 # X11Forwarding no 把它改成 yes 並且把註解拿掉 ● 第二步:下載安裝 XQuartz 並重開機 http://xquartz.macosforge.org/landing/ ● 感謝 Dami 和 YUN-TAO CHEN 的貢獻 “Can not open display” on Mac https://hackpad.com/X11-Forwarding-FcyKHioKxmW
  149. 149. 方法二:將 Pi 的檔案傳回本機端
  150. 150. 150 ● 使用 scp ● 一個實做 SCP(Secure Copy Protocol) 的應用程式 ● 透過 SSH(Secure Shell) 傳輸資料 ● Windows 請安裝 WinSCP ● http://winscp.net/eng/download.php ● 從 Pi 複製檔案到 PC 上 ● scp pi@x.x.x.x:/home/pi/file.txt . ● scp file.txt pi@x.x.x.x:/home/pi 如何讓 Pi 和 PC 互傳檔案? http://winscp.net/
  151. 151. 除了 gpicview 以外 , 還能怎麼開圖?
  152. 152. ● 跨平台的計算機函式庫 , 主要由 C/C++ 撰寫 OpenCV - Open Source ComputerVision Library http://www.embedded-vision.com/technology/computer-vision-algorithms
  153. 153. OpenCV 的架構 http://www.cse.iitk.ac.in/users/vision/dipakmj/papers/OReilly%20Learning%20OpenCV.pdf
  154. 154. import cv2 ● import sys ● imagePath = sys.argv[1] image = cv2.imread(imagePath) ● ● cv2.imshow("preview", image) cv2.waitKey(0) cv2.destroyAllWindows() ● ● ● 載入圖檔並顯示
  155. 155. 155 DEMO image_load.py $ cd ../../03-camera $ cd 03_1-image_load $ python image_load.py lena512rgb.png
  156. 156. 156 除了拍照存檔後開圖以外 , 可以即時預覽 Camera 的結果嗎?
  157. 157. 你有用過 webcam 嗎?
  158. 158. 158 Webcam http://www.slideshare.net/gxben/abs-2014-android-kit-kat-internals
  159. 159. ● 預定義好的 Userspace API ● Video and radio streaming devices ● video cameras ● analog and digital TV receiver cards ● AM/FM receiver cards Video4Linux 2nd(V4L2) http://free-electrons.com/doc/embedded_linux_multimedia.pdf /dev/video0 Driver Hardware App1 (fd1) App2 (fd2) ioctl() ioctl() read() write() Identifying App1 and App2 by different file descriptors, the driver can send them different data.
  160. 160. Camera ≠ Webcam
  161. 161. 161 Modern Device Internal http://www.slideshare.net/gxben/abs-2014-android-kit-kat-internals
  162. 162. 162 Image Processing Pipeline http://www.slideshare.net/gxben/abs-2014-android-kit-kat-internals ISP 在做的事 (HW) color space/format 轉換 (SW)
  163. 163. 163 http://elinux.org/Raspberry_Pi_VideoCore_APIs
  164. 164. 164 ● 開放多媒體加速層 (Open Media Acceleration) ● 由 Khronos Group 提出的標準 ● 統一的介面,加速大量多媒體資料的處理 OpenMAX https://www.khronos.org/openmax/
  165. 165. 165 Multimedia Stack Example http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/Architecture/Multimedia_Domain
  166. 166. 166 ● Kernel driver ● 使用 camera 像是 webcam 一樣 ● $ sudo modprobe bcm2835-v4l2 ● 可直接存取 /dev/videoX ● $ v4l2-ctl --list-devices ● $ v4l2-ctl --list-formats ● $ v4l2-ctl -L ×OfficialV4L2 Driver https://github.com/raspberrypi/linux/blob/rpi-3.10.y/Documentation/video4linux/bcm2835-v4l2.txt
  167. 167. import cv2 cap = cv2.VideoCapture(0) cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 320) cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 240) while True: ret, frame = cap.read() cv2.imshow(“preview”, frame) if cv2.waitKey(1) & 0xFF == ord(“q”): break cap.release() cv2.destroyAllWindows() 讀取 Camera 並顯示
  168. 168. 168 DEMO camera_preview.py 使用前記得要先載入模組 $ sudo modprobe bcm2835-v4l2 $ cd .. $ cd 03_2-camera_preview $ python camera_preview.py
  169. 169. 169 實驗 4-1 :色彩空間轉換 目的:數位影像處理入門
  170. 170. ● 顏色 ● 形狀 ● 特徵 ... 電腦如何分辨東西? http://www.pyimagesearch.com/
  171. 171. ● 分離與萃取資訊 ● 增強或平滑訊號 ● 作為分群、特徵識別等應用的前處理 影像處理的意義 http://mkweb.bcgsc.ca/color-summarizer/
  172. 172. ● RGB ● CMY(K) ● HSV ● YUV 色彩空間 (Color Space)
  173. 173. ● R( 紅 ), G( 綠 ), B( 藍 ) ● 光的三原色 ● 疊加型混色的色彩模型 ● 常用在電腦上表現色彩 ● 8-bit: (255, 0, 0), #FF0000 RGB - R(Red), G(Green), B(Blue) https://en.wikipedia.org/wiki/RGB_color_model
  174. 174. 色彩深度 (Depth of Color) https://sewelldirect.com/learning-center/what-is-deep-color 黑白 灰階 ( 或 256 色 ) 全彩
  175. 175. ● C( 青 ), M( 紫 ),Y( 黃 ), K( 黑 ) ● 彩色墨水三原色 ● 削減型混色的色彩模型 ● 常用在印表機 / 影印機表現色彩 ● 黑色 , R=G=B=1 CMY(K) - C(Cyan), M(Magenta),Y(Yellow), K(Black) https://en.wikipedia.org/wiki/CMYK_color_model
  176. 176. ● H( 彩度 , 0-179), S( 飽和度 , 0-255),V( 明度 , 0-255) ● 符合人對顏色的感知 ● 常用在數位影像處理 HSV - H(Hue), S(Saturation),V(Value) https://en.wikipedia.org/wiki/HSL_and_HSV
  177. 177. ● 以 RGB 為中心 ● RGB to CMY 色彩空間的轉換 ● CMY to RGB http://isis-data.science.uva.nl/koelma/horus/dox/horus2.0/refcpp/html/HxColConvert_8h.html
  178. 178. ● 以 RGB 為中心 ● HSV to RGB 色彩空間的轉換 http://www.rapidtables.com/convert/color/hsv-to-rgb.htm
  179. 179. 179 線上轉換工具 http://goo.gl/EV4l0z
  180. 180. ● cv2.cvtColor(img, flag) ● 灰階 , flag = cv2.COLOR_BGR2GRAY ● HSV, flag = cv2.COLOR_BGR2HSV 色彩空間的轉換 http://docs.opencv.org/3.0-beta/modules/imgproc/doc/miscellaneous_transformations.html
  181. 181. ● cv2.threshold(img, thresh, maxval, type) ● 轉成黑白 ● cv2.threshold(image, 127, 255, cv2.THRESH_BINARY) 二值化 - 將影像以強度 (threshold) 區分 http://docs.opencv.org/3.0-beta/modules/imgproc/doc/miscellaneous_transformations.html
  182. 182. ● cv2.inRange(img, lowerval, upperval) ● 只取出紫色部份 ● lower = np.array( [141, 0, 0] ) ● upper = np.array( [164, 145, 197] ) 另一種二值化 - 在 HSV 空間裡 , 根據區間 (lower/upper) 分割
  183. 183. image = cv2.imread("lena512rgb.png") ● gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ● ● (_, binary) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) ● ● lower = np.array( [141, 0, 0] ) ● upper = np.array( [164, 145, 197] ) ● mask = cv2.inRange(hsv, lower, upper) ● ● bitwise = cv2.bitwise_and(image, image, mask=mask) 色彩空間轉換與二值化處理
  184. 184. 184 DEMO color_space.py $ cd ../../04-opencv $ cd 04_1-color_space $ python color_space.py ../lena512rgb.png
  185. 185. ● 即時調整 HSV 的值?
  186. 186. 186 DEMO $ python hsv_value ../lena512rgb.png
  187. 187. 187 實驗 4-2 :輪廓與中心點 目的:數位影像處理入門
  188. 188. ● 輪廓就是一堆連續的點 , 可以將兩個不同顏色或 是不同密度的點分離 ● 是物體辨識或是形狀分析應用的前處理 ● 使用二值化 ( 黑白 ) 的圖形可更精準的找出輪廓 輪廓 (Contours) http://urbanhonking.com/ideasfordozens/2013/07/10/announcing-opencv-for-processing/
  189. 189. ● cv2.findContours(image, mode, method) ● mode( 輪廓取得模式 ) ● method( 輪廓儲存法 ) 尋找輪廓 (findContours) http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.html
  190. 190. ● mode( 輪廓取得模式 ) ● CV_RETR_EXTERNAL: 只取最外層的輪廓 ● CV_RETR_LIST: 取得所有輪廓,不建立階層 (hierarchy) ● CV_RETR_CCOMP: 取得所有輪廓,但只儲存成兩層的階層 ● CV_RETR_TREE: 取得所有輪廓,以全階層的方式儲存 ● method( 輪廓儲存法 ) ● CV_CHAIN_APPROX_NONE: 儲存所有輪廓點 ● CV_CHAIN_APPROX_SIMPLE: 只留下頭尾點或對角頂點 參數說明 http://monkeycoding.com/?p=615 http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_contours/py_contours_hierarchy/py_contours_hierarchy.html
  191. 191. ● cv2.drawContours(image, contours, contourIdx, color) ● contourIdx = -1 表示畫出所有輪廓點 畫輪廓 (drawContours) http://docs.opencv.org/3.0-beta/modules/imgproc/doc/drawing_functions.html
  192. 192. image = cv2.imread("lena512rgb.png") ● ● gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ● (_, binary) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) ● ● (contours, _) = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) ● cv2.drawContours(image, contours, -1, (0,255,0), 3) ● cv2.imshow("Contours", image) ● 找出輪廓並且全部畫出
  193. 193. 193 DEMO draw_contour.py $ cd .. $ cd 04_2-contours $ python draw_contour.py ../lena512rgb.png
  194. 194. ● 從矩 (moment) 的觀點來看 ● 物理學:表示作用力促使物體繞支點旋轉的趨向 ● 數學:用來描述資料分佈特徵 ● 以二值化 ( 黑白 ) 的圖形找中心點 找中心點 http://docs.opencv.org/3.1.0/d8/d23/classcv_1_1Moments.html
  195. 195. ● 空間矩 (spatial moments) ● 中心矩 (central moments) ● 正規中心矩 (central normalized moments) 常見矩 http://docs.opencv.org/3.1.0/d8/d23/classcv_1_1Moments.html
  196. 196. image = cv2.imread("rectangle1rgb.png") ● ● gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ● (_, binary) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) ● (contours, _) = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) ● ● cnt = contours[0] ● M = cv2.moments(cnt) ● ● ((x, y), radius) = cv2.minEnclosingCircle(cnt) ● M = cv2.moments(cnt) ● center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])) ● cv2.circle(image, (int(x), int(y)), int(radius), (0, 255, 255), 2) ● cv2.circle(image, center, 5, (0, 0, 255), -1) 找中心點與外框
  197. 197. 197 DEMO $ python draw_moment.py rectangle.png
  198. 198. 198 實驗 4-3 :影像的再處理 目的:數位影像處理入門
  199. 199. ● 侵蝕 (Erode) ● 膨脹 (Dilate) ● 濾波器 ( 平滑化 ) 影像的再處理
  200. 200. ● 侵蝕 (Erode) ● 消融物體的邊界 從形態學的觀點 https://www.cs.auckland.ac.nz/courses/compsci773s1c/lectures/ImageProcessing-html/topic4.htm ● 膨脹 (Dilate) ● 擴大物體的邊界 通常以奇數矩形為結構元素 (3x3, 5x5, 7x7...), 預設為 3x3
  201. 201. ● cv2.erode(src, kernel[, iterations]) ● iterations – number of times dilation is applied. 侵蝕 (Erode) http://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html 黑白 iteration=1 iteration=2
  202. 202. ● cv2.dilate(src, kerne[, iterations]) ● iterations – number of times dilation is applied. 膨脹 (Dilate) http://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html 黑白 iteration=1 iteration=2
  203. 203. image = cv2.imread("lena512rgb.png") ● gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ● (_, binary) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) ● ● erode = cv2.erode(binary, None, iterations=2) ● cv2.imshow("erode", erode) ● ● #dilate = cv2.dilate(binary, None, iterations=2) ● #cv2.imshow("dilate", dilate) ● 侵蝕效果
  204. 204. 204 DEMO erode_dilate.py $ python erode_dilate.py ../lena512rgb.png $ cd .. $ cd 04_3-image_processing $ python erode_dilate.py ../lena512rgb.png
  205. 205. image = cv2.imread("lena512rgb.png") ● gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ● (_, binary) = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) ● ● #erode = cv2.erode(binary, None, iterations=2) ● #cv2.imshow("erode", erode) ● ● dilate = cv2.dilate(binary, None, iterations=2) ● cv2.imshow("dilate", dilate) ● 膨脹效果 ( 將註解換掉 )
  206. 206. 206 DEMO erode_dilate.py $ python erode_dilate.py ../lena512rgb.png
  207. 207. ● 目的是為了去除雜訊 , 但對比度可能下降 ● 線性濾波 ● 平均平滑 (blur) ● 高斯平滑 (GaussianBlur) ● 非線性濾波 ● 中值濾波 (medianBlur) ● 雙邊濾波 (bilateralFilter) 影像平滑
  208. 208. ● cv2.GaussianBlur(src, ksize, cv2.BORDER_CONSTANT) 高斯平滑 (GaussianBlur) http://www.gamasutra.com/view/feature/131511/four_tricks_for_fast_blurring_in_.php
  209. 209. image = cv2.imread(“lena512rgb.png”) ● cv2.imshow("Normal", image) ● ● blur = cv2.GaussianBlur(image, (9,9), 0) ● cv2.imshow("GaussianBlur", blur) ● ● ● 高斯平滑效果
  210. 210. 210 DEMO $ python gaussian_blur.py ../lena512rgb.png
  211. 211. 211 實驗 4-4 :色彩追蹤 目的:找出 HSV 與即時色彩追蹤
  212. 212. ● 定義要追蹤的顏色 ( 例如綠色 ) ● 將影像轉到 HSV 空間後二值化 ● 綠色參考數值 – Color_Lower = (36, 130,46) – Color_Upper = (113, 255, 255) ● 找出該顏色的輪廓 ● 找出質心與半徑 ● 畫出質心與半徑 追蹤流程
  213. 213. 213 DEMO color_tracking.py $ cd .. $ cd 04_4-color_tracking $ python color_tracking.py
  214. 214. 214 實驗 4-5 :寵物小車 目的:根據顏色控制小車移動
  215. 215. ● 找出顏色質心 , 定義規則 ( 超過中心線 10 就動作 ) if radius < 90: motor.forward() elif radius > 100: motor.backward() if center[0] > width/2 + 10: motor.turnRight() elif center[0] < width/2 - 10: motor.turnLeft() 根據移動規則控制小車移動
  216. 216. 216 DEMO follower_car.py $ cd .. $ cd 04_5-follower_car $ python follower_car.py
  217. 217. ● 是否要做高斯模糊化? frame = cv2.GaussianBlur(frame, (11, 11), 0) ● 是否要作侵蝕? mask = cv2.erode(mask, None, iterations=2) ● 是否要作膨脹? ● mask = cv2.dilate(mask, None, iterations=2) ● 修改找輪廓的參數是否會更快? ● (contours, _) = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 優化
  218. 218. ● 關掉顯示視窗 # cv2.imshow("Frame", frame) ● 使用 PWM 控制轉速 pwm_r1 = GPIO.PWM(Motor_R1_Pin, 500) ● pwm_r2 = GPIO.PWM(Motor_R2_Pin, 500) ● pwm_l1 = GPIO.PWM(Motor_L1_Pin, 500) ● pwm_l2 = GPIO.PWM(Motor_L2_Pin, 500) 優化
  219. 219. Raspberry Pi Rocks the World Thanks
  220. 220. 220 補充資訊
  221. 221. 221 實驗 2-5 :無線 (WiFi) 遙控 目的:學習如何從網頁控制硬體
  222. 222. ● 一個軟體 ● 回應從 80/8080 port 進來的 HTTP 要求 ● 可透過 CGI 或 module 方式擴充 ● 如 Apache, Nginx, Boa 網頁伺服器 (Web Server) http://www.resultantsys.com/index.php/general/what-is-a-web-application-server/
  223. 223. 223 - A fast, simple and lightweight WSGI micro web-framework $ sudo pip install bottle
  224. 224. 用 AJAX 送指令 ● 非同步 JavaScript & XML ● XMLHttpRequest 物件 ● 無須更新整個頁面
  225. 225. 225 DEMO bottle_control.py

×