Raspberry Pi 寵物小車

64,597 views

Published on

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
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
64,597
On SlideShare
0
From Embeds
0
Number of Embeds
63,110
Actions
Shares
0
Downloads
106
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

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

×