樹莓派Raspberry Pi 系統搭建和智慧機器人小車的組裝除錯
本文的出發點:無意接觸到樹莓派這款優秀的晶片,比較適合青少年程式設計,激發孩子的程式設計思維的培養,最好的學習就是實戰,藉助於淘寶上現成零件式的智慧小車硬體和樹莓派實現智慧機器人小車的實現,給孩子帶來低成本高效能的玩具,重要的是通過個人的行動帶動孩子的興趣達到啟蒙作用。
主要分樹莓派系統搭建和智慧小車組裝除錯兩大部分,內容偏實戰,理論知識網路上遍地都是會附帶而過,儘量做到步驟簡潔易懂,細節力求完整,為您零基礎學習樹莓派提供捷徑,如有不足請指正。
1. 樹莓派系統搭建
1.1 什麼是樹莓派
Raspberry Pi(中文名為“樹莓派”,簡寫為RPi,(或者RasPi / RPI) [1] 是為學習計算機程式設計教育而設計,只有信用卡大小的微型電腦,其系統基於Linux,由註冊於英國的慈善組織“Raspberry Pi 基金會”開發,推廣給全世界的青少年電腦愛好者,用於培養計算機程式設計的興趣和能力。
您可以將樹莓派連線電視、顯示器、鍵盤滑鼠等裝置使用。你可以通過樹莓派來DIY以下一些場景應用:
- 打造一款屬於自己的手持式遊戲機,雖然沒手機方便,但也會很酷....
- 藉助於一些感測器和執行機構實現智慧家居的遠端監控,上班也能瞧瞧美麗的小家和可愛的娃 : )
- 扔掉帶有各種廣告和限制的機頂盒,實現自己的家庭多媒體中心,重溫下硬盤裡的經典影片,建立專屬的家庭相簿和視訊集,打打兒時的經典遊戲,,,
- 打造一款智慧小車,可以根據你的指令跑到廚房裡問媽媽:今天有紅燒肉吃嗎?再跑回來告訴你結果
- 設計平面自動作畫系統或者簡易3D印表機,在家也能體驗藝術魅力
樹莓派裁剪了桌面計算機的強大應用,簡化複雜的硬體構建和程式設計,更注重於作品的創意和設計,培養青少年的程式設計思維。
樹莓派引數資訊不作具體詳細介紹,直接上Raspberry Pi 3B有個直觀印象。
1.2 樹莓派系統映象下載、燒寫和備份
樹莓派支援多種系統型別,如 Raspbian、Arch Linux ARM、Debian Squeeze、Firefox OS、Gentoo Linux、Google Chrome OS、Raspberry Pi Fedora Remix、Slackware ARM、QtonPi、Slackware ARM、WebOS、RISC OS、FreeBSD、NetBSD、Android 4.0(Ice Cream Sandwich)等。
樹莓派實際使用micro SD 卡裝載系統,系統燒寫及時寫SD卡的過程
- 電腦插入SD卡(推薦4G以上的Class4以上卡),使用Win32DiskImager(Win32DiskImager-0.9.5-install.exe)燒寫Raspbian作業系統映象檔案2017-03-02-raspbian-jessie.img,一頓猛操作:最好關閉系統防火牆;選擇載入img映象系統;點選write;確認yes;喝完茶之後看到write successful介面說明系統安裝成功了!細心點你會發現磁碟空間有點奇怪,最大也就幾十MB,莫慌!這是正常現象,linux下的磁碟分割槽在Windows下是看不到的。
1.3 樹莓派硬體連線
電源:樹莓派正常採用5V, 2A 的Micro USB供電,就是常見的安卓手機介面,但考慮到眾多外設、顯示屏等諸多負載產生的壓降,特地購置了原裝樹莓派專用官方電源(5.1V, 2.5A)。網上獲知因電源不穩定造成的諸多後果太多了:鍵盤動不了;顯示器不顯示或者花屏閃屏;系統重啟等等。總之而言,電源是無論放在什麼場合都是重中之重,必須足夠重視,否則很容易陷入各種不可預期的麻煩,讓你懷疑人生。
1.4 樹莓派連線顯示屏
樹莓派可以通過各種工具如SSH, TightVnc,Putty,Winscp等等實現檔案互動甚至系統畫面訪問,不過初學者還是強烈建議買塊顯示屏進行初始的一些配置,所謂眼見為實,這樣便於入門。這裡我配置了一塊微雪的7寸高清電容屏和微型無線鍵盤滑鼠。
7寸顯示器HDMI接樹莓派的HDMI; 顯示器Mico USB供電口接入樹莓派的USB供電;無線鍵盤的的接收器同樣插到樹莓派USB口上;最後上電啟動樹莓派系統。
初次啟動即發現螢幕顯示花屏,無法全屏顯示
諮詢了微雪顯示屏客戶得到了解決方案:用於樹莓派的Raspbian/ Ubuntn mate系統時,需要手動修改系統根目錄下config.txt配置檔案,檔案末尾新增以下配置行並確保等號左右沒有空格即可,親自有效!
max_usb_current=1
hdmi_group=2
hdmi_mode=87
hdmi_cvt 1024 600 60 6 0 0 0
hdmi_drive=1
成功啟動畫面如圖所示:
- pi賬戶和root賬戶
pi賬戶是樹莓派自動分配的使用者賬戶,預設密碼為raspberry,建議使用者用以下命令自行修改密碼。
[email protected]:password pi
不過一般的檔案系統操作,pi賬戶沒有足夠的許可權,這時候就需要獲取系統的root許可權。在pi賬戶登入情況下,可以臨時通過sudo臨時獲取root許可權如下命令:
[email protected]:sudo raspi-config
對於官方的初始系統root密碼預設是沒有密碼的,但賬戶確是鎖定的,可在pi賬戶下開啟root密碼,如下命令:[email protected]:sudo passwd root
執行此命令後系統會提示輸入兩遍的root密碼,輸入你想設的密碼即可,然後再執行:
sudo passwd --unlock root
這樣root使用者解鎖成功,如果不想每次輸入命令都使用sudo獲取臨時root許可權的話,可以在pi賬戶下輸入su命令並輸入root密碼即可獲取長期root許可權。
1.4 登入方式配置
通過顯示屏進入系統,發現畫面右上角已經顯示出當前可連線的wifi路由器,直接點選輸入WiFi密碼連線。使用預設瀏覽器看是否能上網。接著開啟系統左上角的命令列終端,輸入ifconfig命令檢視當前系統ip地址為(172.20.1.5),這樣電腦端連線同樣的Wifi路由,只要能訪問到該IP地址就可以使用多種遠端工具進行訪問樹莓派系統,進行檔案傳送,遠端桌面訪問等操作了。
[email protected]:ifconfigifconfig
- SSH和SSH檔案傳輸
使用SSH,必須先手動開啟樹莓派的SHH遠端服務,操作如下:
a.命令開啟raspi配置視窗
pi#sudo raspi-config
然後選擇"Interfacing options" 進入二級選單,選擇"P2 SSH" 回車確認Enable即可。
b. 這樣我們就可以通過SSH工具軟體遠端訪問樹莓派系統了。
預設使用pi賬戶及預設密碼raspberry登入,成功登入後顯示如下資訊。
c. 點選SSH工具欄上的“New file transfer window”圖示可以開啟檔案系統操作視窗如下,左側為本地電腦目錄系統,右側即為樹莓派可訪問的linux目錄系統,藉助於root許可權可以相互移動和修改檔案。
注意1:如果出現server responded “algorithm negotiation failed”的操作錯誤,這時我們需要登入pi之後修改ssh的配置檔案/etc/ssh/sshd_config
sudo vi /etc/ssh/sshd_config
並在開啟的檔案中新增如下程式碼
Ciphers aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,3des-cbc,arcfour128,arcfour256,arcfour,blowfish-cbc,cast128-cbc
MACs hmac-md5,hmac-sha1,[email protected],hmac-ripemd160,hmac-sha1-96,hmac-md5-96
KexAlgorithms diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group-exchange-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group1-sha1,[email protected]
重啟sshd服務後,即可正常登入
sudo service ssh restart
或者
sudo /etc/init.d/ssh restart
- 遠端桌面登入(xdrp)
如果你覺得SSH訪問工具不夠直觀的話,還可以通過遠端桌面訪問的方式,顧名思義就是可以訪問到樹莓派系統的主畫面,相當於直接操作樹莓派的linux系統,這樣無論從檔案操作,程式執行以及命令執行上都顯得比較明瞭,方便初學者使用。
首先需要獲取root許可權並安裝xdrp
[email protected]:sudo apt-get install xrdp
或者
[email protected]:su
[email protected]:apt-get install xrdp
安裝過程如下圖:
安裝完成後,可以通過Windows命令框輸入mstsc或者remote開啟遠端桌面訪問客戶端,並輸入樹莓派的IP地址訪問連線。
pi和root賬戶皆可登入到樹莓派系統中,如下就可以看到正在的樹莓派Raspbian作業系統了。
不過如果遠端桌面的登入過程中出現如下錯誤(IP地址,使用者名稱,密碼正確的情況下)
解決的辦法就需要再樹莓派系統中安裝tightvnc server服務
- Tight Vnc
[email protected]: apt-get install tightvncserver
安裝完成後,reboot重啟後再次遠端桌面連線即可成功!
1.5 Vim編輯器配置
Linux自帶的編輯器有nano和vi,但vi編輯器使用起來很不方便,通常我們可以使用Vim編輯器。vim 是vi的升級版本,它不僅相容vi的所有指令,而且還有一些新的特性在裡面。vim的這些優勢主要體現在以下幾個方面:1、多級撤消我們知道在vi裡,按 u只能撤消上次命令,而在vim裡可以無限制的撤消。2、易用性vi只能運行於unix中,而vim不僅可以運行於unix,windows ,mac等多操作平臺。3、語法加亮vim可以用不同的顏色來加亮你的程式碼。4、視覺化操作就是說vim不僅可以在終端執行,也可以運行於x window、 mac os、 windows。5、對vi的完全相容某些情況下,你可以把vim當成vi來使用。
安裝之前,首先需要更新索引源:
sudo apt-get update
安裝vim編輯器:
sudo apt-get install vim
注意:有的系統預設自帶安裝了Vim文字編輯器,但是樹莓派的源是國外版的,預設編輯器並不好用,還無法顯示中文,所以最好先解除安裝一次,再重新安裝:
sudo apt-get remove vim-common
sudo apt-get install vim
也可以使用SSH Secure File Transfer工具將windows下的檔案與樹莓派的檔案實現檔案跨系統傳輸,將下載好的vimconfig.tar.gz檔案安裝包傳輸到樹莓派系統的目錄中,如/home/pi/workdir。然後在命令列中輸入解壓縮命令:
進入vimconfig目錄中執行config.sh指令碼
會出現如下錯誤,不用急
我們只需要在/root/目錄下新建.vim和.vimrc檔案,還需要apt-get install ctags即可 ,確保在root(加sudo),否則沒有許可權。
配置好的vim編輯器:
具體Vim編輯器的使用方法和相關命令,請自行百度查詢。
1.7 樹莓派配置成路由器
Raspberry Pi 3板載了無線網路介面卡和陶瓷天線,不需要額外增加無線網絡卡就可以把它打造成一個無線路由器。
以下描述如何開啟樹莓派無線網路介面卡的AP功能,並且共享其有線網路,實現無線路由功能。
- 先下載相關軟體hostapd和dnsmasp,前者可以開啟無線介面卡的AP功能,後者是DHCP和DNS伺服器。
sudo apt-get install hostapd dnsmasq
安裝完成之後就可以直接安裝DHCP服務了
sudo apt-get install isc-dhcp-server
- 下面設定靜態IP
需要將無線介面wlan0的IP配置成靜態地址,首先讓dhcpcd不再管理wlan0,避免設定衝突。修改etc資料夾中的dhcpcd.conf檔案,開頭增加一行:denyinterfaces wlan0
vi /etc/dhcpcd.conf
然後設定wlan0的靜態ip,修改檔案:
vi /etc/network/interfaces
將wlan0相關的內容修改成如下內容:
192.168.0.1是給樹莓派做路由器分配的閘道器IP,不能與區域網其他路由器閘道器IP重複,若重複此處可以修改IP地址為其他閘道器。
重啟服務和wlan0
service dhcpcd restart
ifdown wlan0
ifup wlan0
通過ifconfig可以看到wlan0的ip已經設定好了。
- 安裝Hostapd
新建配置檔案,並輸入如下配置行:
vi /etc/hostapd/hostapd.conf
上面文件中,ssid=RaspberryPi是無線網路的名字,wpa_passphrase=raspberry是密碼。
測試配置是否正確:
sudo /usr/sbin/hostapd /etc/hostapd/hostapd.conf
通過手機等裝置應該可以搜到名為RaspberryPi的WiFi,還不需要連線。如果沒有問題,按Ctrl+C停止測試。使上述設定生效:
vi /etc/default/hostapd
將#DAEMON_CONF=""修改為DAEMON_CONF="/etc/hostapd/hostapd.conf"。
- 配置DHCP伺服器
備份配置檔案:
cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.bak
編輯新的配置檔案,修改成如下內容:
vi /etc/dhcp/dhcpd.conf
重啟DHCP服務
service isc-dhcp-server restart
- 開啟IPV4轉發
修改相應的檔案,去掉net.ipv4.ip_forward=1前面的“#”號
vi /etc/sysctl.conf
通過iptables做NAT轉發
這些配置重啟之後就會失效了,需要儲存起來
sh -c “iptables-save > /etc/iptables.ipv4.nat”
並設定為開機自動載入:
vi /etc/rc.local
在exit 0上方增加:
iptables-restore < /etc/iptables.ipv4.nat
啟動服務
service hostapd start
接著reboot重啟。樹莓派重啟之後就可以用手機連線到wifi了。名字和密碼在上面的文件中體現了,連線之後系統會自動為我們連線的裝置分配未使用的ip。如果我們的樹莓派通過有線網路連上網際網路的話,我們連上的樹莓派路由器的話,也是可以上網的。
1.8 樹莓派攝像頭配置
樹莓派攝像頭配置需要如下步驟
- 拷貝和解壓攝像頭驅動
通過SSH拷貝驅動包檔案master.zip到home資料夾,並執行解壓縮命令
#unzip master.zip
- 安裝CMake工具
CMake是一個跨平臺的安裝(編譯)工具,可以用簡單的語句來描述所有平臺的安裝(編譯過程)。他能夠輸出各種各樣的makefile或者project檔案,能測試編譯器所支援的C++特性,類似UNIX下的automake。這裡編譯攝像頭驅動需要用到此工具。執行下列下載安裝命令:
#sudo apt-get install cmake
中間若有提示,輸入“Y”即可,完成後如下圖所示:
- 安裝所需要的編譯支援庫libjpeg8
執行指令,完成後如下圖所示:
#sudo apt-get install libjpeg8-dev
- 執行攝像頭編譯
首先需要知道你手上的攝像頭的資料格式(JPEG或者YUYV),驅動中預設為JPEG格式,如需修改請在如下目錄檔案中修改
# cd /home/pi/mjpg-streamer-master/mjpg-streamer-experimental/plugins/input_uvc/
# sudo vim input_uvc.c
修改135行處的format為V4L2_PIX_FMT_YUYV,然後然後返回到/mjpg-streamer-experimental/下執行如下命令完成編譯
#sudo make clean all
- 攝像頭畫面呼叫
進入樹莓派配置介面,Enable啟用Camera攝像頭
#sudo raspi-config
然後插上USB攝像頭,重啟系統
# sudo reboot
重啟完畢進入系統,進入mjpg-streamer-experimental目錄並使用下列指令啟動普通USB攝像頭
#./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so -w ./www"
啟動樹莓派專用攝像頭RaspiCamera的指令
#./mjpg_streamer -i "./input_raspicam.so" -o "./output_http.so -w ./www"
執行過程中可能會有報錯,可以忽略,只要最後沒有退回到命令列提示符,而且顯示“Starting ouput”,就應該成功了。
下面在PC端使用瀏覽器檢視攝像頭的靜止影象
http://<樹莓派IP>:8080/?action=snapshot
動態影象查詢:
http://<樹莓派IP>:8080/?action=stream
或者 http://<樹莓派IP>:8080/javascript_simple.html
1.9 樹莓派3串列埠(UART)使用問題和方法解決
串列埠(UART)的硬體bug如下文引用
““”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“””
根據官方的反饋和回覆,我們瞭解到樹莓派3上使用者目前無法正常是使用GPIO中的UART串列埠(GPIO14&GPIO15),也就是說使用者無論是想用串列埠來除錯樹莓派,還是想用GPIO中的串列埠來連線GPS,藍芽,XBEE等等串列埠外設目前都是有問題的。
原因是樹莓派CPU內部有兩個串列埠,一個是硬體串列埠(官方稱為PL011 UART),一個是迷你串列埠(官方成為mini-uart)。在樹莓派2B/B+這些老版樹莓派上,官方設計時都是將“硬體串列埠”分配給GPIO中的UART(GPIO14&GPIO15),因此可以獨立調整串列埠的速率和模式。而樹莓派3的設計上,官方在設計時將硬體串列埠分配給了新增的藍芽模組上,而將一個沒有時鐘源,必須由核心提供時鐘參考源的“迷你串列埠”分配給了GPIO的串列埠,這樣以來由於核心的頻率本身是變化的,就會導致“迷你串列埠”的速率不穩定,這樣就出現了無法正常使用的情況。
目前解決方法就是,關閉藍芽對硬體串列埠的使用,將硬體串列埠重新恢復給GPIO的串列埠使用,也就意味著樹莓派3的板載藍芽和串列埠,現在成了魚和熊掌,兩者無法兼得。
”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”
下面講述如何恢復硬體串列埠的方法
- 下載pi3-miniuart-bt-overlay檔案,解壓出pi3-miniuart-bt-overlay.dtb檔案,並將dtb檔案拷貝到/boot/overlays/目錄
- 修改/boot目錄下的config.txt檔案,在最後新增如下兩行並儲存.
#sudo vim /boot/config.txt
dtoverlay=pi3-miniuart-bt-overlayforce_turbo=1
- 修改/boot目錄下的cmdline.txt檔案
#sudo vim /boot/cmdline.txt
修改前的截圖:
修改為:
dwc_otg.lpm_enable=0 console=serial1,115200 console=tty1 root=/dev/mmcblk0p2 kgdboc=serial1,115200 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
最後儲存退出。
下面需要做的就是關閉自帶的板載藍芽功能。
- 輸入下面命令關閉hciuart使用uart0
#sudo systemctl disable hciuart
- 修改/lib/systemd/system/hciuart.server 將 “ttyAMA0”修改為“ttyS0”,並儲存退出。
sudo vim /lib/systemd/system/hciuart.service
- 最後更新並重啟即可
sudo apt-get update
sudo apt-get upgrade
sudo reboot
1.6 Wiring庫函式
2. 智慧小車組裝除錯
智慧小車簡介
這裡選用深圳亞博智慧科技出品的4WD可相容多種控制器(樹莓派、Arduino、51、STM32)的智慧小車。該車支援多個定製的精良感測器,能出色完成巡線、避障、跟隨、尋光、灰度識別等功能;支援多種遙控方式,藍芽4.0控制、微信小程式控制、紅外遙控、PC上位機遙控等;支援多種組裝方式,單、雙層平臺結構,平臺上多個安裝孔選擇。
2.1 智慧小車組裝
具體安裝步驟如下:底板安裝孔、電機安裝、輪胎安裝、電池盒安裝、循跡探頭安裝、紅外尋光模組安裝、風扇安裝、藍芽安裝、樹莓派3B+與擴充套件板安裝、擴充套件板安裝、舵機,超聲波模組、探照燈模組安裝、攝像頭雲臺搭建、攝像頭雲臺與二層平臺安裝、雙平臺安裝、擴充套件板接線端子、PS2遙控手柄安裝、檢查各模組插頭連線和跳線。詳細見下面官方圖,在此無需累贅。
2.1 智慧小車除錯
2.1.1 Wiring庫函式
簡介:wiringPi是應用於樹莓派平臺的GPIO控制庫函式,wiringPi中的函式類似於Arduino的wiringPi系統,wiringPi庫包含了豐富的庫函式,如GPIO庫,I2C庫,SPI庫,UART庫和軟體PWM庫。
wiringPi安裝
- 使用git工具
首先安裝git工具
sudo apt-get install git-core
如果安裝時發生錯誤,可以嘗試更新apt庫
sudo apt-get update
接著通過 git 線上獲得wiringPi的原始碼,輸入命令
git clone git://git.drogon.net/wiringPi
進入wiringPi目錄並安裝wiringPi庫
cd wiringPi
./build
build指令碼將會自動完成wiringPi庫的編譯和安裝,安裝完成如下....
若需要更新wiringPi庫,輸入以下命令:
cd wiringPi
git pull origin
- 離線下載安裝wiringPi函式庫
直接下載wiringPi原始碼和解壓,並進行本地安裝...從以下網址獲得wiringPi原始碼:
點選圖中的snapshot便可下載最新版本,將下載到的安裝包移動到你需要安裝的目錄下,然後使用以下命令解壓和安裝:
tar xfz wiringPi-96344ff.tar.gz
cd wiringPi-96344ff
./build
wiringPi的版本資訊檢視
安裝完成後,開啟命令終端,可以通過gpio命令來檢查wiringPi的版本資訊。
GPIO口的使用
命令列輸入gpio readall 可以獲得wiringPi和樹莓派的GPIO介面之間的對應關係,如下圖所示:
上圖中的physical列代表的是樹莓派物理上介面J8的管腳定義,wPi列即代表在wiringPi中所對應的數值,BCM列即代表在BCM2835的GPIO暫存器中的偏移地址,即在BCM2835 C library中對應的GPIO的數值。我們使用的是wiringPi庫函式,進行的樹莓派wifi智慧小車的開發。
2.1.1 程式碼功能除錯和說明
WiringPi庫的具體函式使用說明可以自己網上檢視手冊,在此不作累贅,具體以智慧小車的控制功能和原始碼進行典型性講解。
這裡以廠家提供的原始碼程式簡單介紹
庫檔案引用和變數定義
#include <wiringPi.h>
#include <softPwm.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiringSerial.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#define run_car '1'//按鍵前
#define back_car '2'//按鍵後
#define left_car '3'//按鍵左
#define right_car '4'//按鍵右
#define stop_car '0'//按鍵停
#define front_left_servo '1'
#define front_right_servo '2'
#define up_servo '3'
#define down_servo '4'
#define left_servo '6'
#define right_servo '7'
#define updowninit_servo '5'
#define stop_servo '8'
#define ON 1
#define OFF 0
#define HIGH 1
#define LOW 0
/*小車執行狀態列舉*/
enum {
enSTOP = 0,
enRUN,
enBACK,
enLEFT,
enRIGHT,
enTLEFT,
enTRIGHT
} enCarState;
/*小車舵機狀態列舉*/
enum {
enFRONTSERVOLEFT = 1,
enFRONTSERVORIGHT,
enSERVOUP,
enSERVODOWN,
enSERVOUPDOWNINIT,
enSERVOLEFT,
enSERVORIGHT,
enSERVOSTOP,
enSERVOFRONTINIT
} enServoState;
//定義引腳
int Left_motor_go = 28; //左電機前進AIN2連線Raspberry的wiringPi編碼28口
int Left_motor_back = 29; //左電機後退AIN1連線Raspberry的wiringPi編碼29口
int Right_motor_go = 24; //右電機前進BIN2連線Raspberry的wiringPi編碼24口
int Right_motor_back = 25; //右電機後退BIN1連線Raspberry的wiringPi編碼25口
int Left_motor_pwm = 27; //左電機控速PWMA連線Raspberry的wiringPi編碼27口
int Right_motor_pwm = 23; //右電機控速PWMB連線Raspberry的wiringPi編碼23口
/*循跡紅外感測器引腳及變數設定*/
//TrackSensorLeftPin1 TrackSensorLeftPin2 TrackSensorRightPin1 TrackSensorRightPin2
// 9 21 7 1
const int TrackSensorLeftPin1 = 9; //定義左邊第一個循跡紅外感測器引腳為wiringPi編碼9口
const int TrackSensorLeftPin2 = 21; //定義左邊第二個循跡紅外感測器引腳為wiringPi編碼21口
const int TrackSensorRightPin1 = 7; //定義右邊第一個循跡紅外感測器引腳為wiringPi編碼7口
const int TrackSensorRightPin2 = 1; //定義右邊第二個循跡紅外感測器引腳為wiringPi編碼1口
//定義各個循跡紅外引腳採集的資料的變數
int TrackSensorLeftValue1;
int TrackSensorLeftValue2;
int TrackSensorRightValue1;
int TrackSensorRightValue2;
char infrared_track_value[5] = {0};
/*避障紅外感測器引腳及變數設定*/
const int AvoidSensorLeft = 26; //定義左邊避障的紅外感測器引腳為wiringPi編碼26口
const int AvoidSensorRight = 0; //定義右邊避障的紅外感測器引腳為wiringPi編碼0口
int LeftSensorValue ; //定義變數來儲存紅外感測器採集的資料大小
int RightSensorValue ;
char infrared_avoid_value[3] = {0};
/*定義光敏電阻引腳及變數設定*/
const int LdrSensorLeft = 11; //定義左邊光敏電阻引腳為wiringPi編碼11口
const int LdrSensorRight = 22; //定義右邊光敏電阻引腳為wiringPi編碼22口
int LdrSersorLeftValue ; //定義變數來儲存光敏電阻採集的資料大小
int LdrSersorRightValue ;
char LDR_value[3] = {0};
/*蜂鳴器引腳設定*/
int buzzer = 10; //設定控制蜂鳴器引腳為wiringPi編碼10口
/*小車初始速度控制*/
unsigned int g_CarSpeedControl = 150;
/*設定舵機驅動引腳*/
int FrontServoPin = 4;
int ServoUpDownPin = 13;
int ServoLeftRightPin = 14;
/*超聲波引腳及變數設定*/
int EchoPin = 30; //定義回聲腳為連線Raspberry的wiringPi編碼30口
int TrigPin = 31; //定義觸發腳為連線Raspberry的wiringPi編碼31口
/*RGBLED引腳設定*/
int LED_R = 3; //LED_R接在Raspberry上的wiringPi編碼3口
int LED_G = 2; //LED_G接在Raspberry上的wiringPi編碼2口
int LED_B = 5; //LED_B接在Raspberry上的wiringPi編碼5口
/*滅火電機引腳設定*/
int OutfirePin = 8; //設定滅火電機引腳為wiringPi編碼8口
/*變數*/
/*攝像頭舵機上下和左右兩個自由度的變數*/
int ServoUpDownPos = 90;
int ServoLeftRightPos = 90;
/*前舵機左右搖動變數*/
int FrontServoLeftRightPos = 90;
unsigned char g_frontservopos = 90;
/*舵機控制標誌位*/
int ServoFlags;
int g_ServoState = enSERVOSTOP;
int g_lednum = 0; //led顏色切換變數
/*串列埠裝置開啟的檔案描述符*/
int fd;
/*串列埠長度變數*/
int g_num=0;
int g_packnum=0;
/*計時變數*/
int serialtime = 5000;
int count = 20;
/*串列埠資料設定*/
char InputString[512] = {0}; //用來儲存接收到的內容
int NewLineReceived = 0; //前一次資料結束標誌
int StartBit = 0; //協議開始標誌
int g_CarState = enSTOP; //1前2後3左4右0停止
char ReturnTemp[512] = {0}; //儲存返回值
/*小車模式切換*/
int g_modeSelect = 0; //0是預設狀態; //2:巡線模式 3:超聲波避障 //4: 七彩探照 5: 尋光模式 6: 紅外跟蹤
重要功能函式
- main函式:初始化以及模式控制
/**
* Function main
* @brief 對串列埠傳送過來的資料解析,並執行相應的指令
* @param[in] void
* @retval void
* @par History 無
*/
int main()
{
g_modeSelect = 1;
//wiringPi初始化
wiringPiSetup();
digitalWrite(OutfirePin, HIGH);
//初始化電機驅動IO為輸出方式
pinMode(Left_motor_go, OUTPUT);
pinMode(Left_motor_back, OUTPUT);
pinMode(Right_motor_go, OUTPUT);
pinMode(Right_motor_back, OUTPUT);
//建立兩個軟體控制的PWM腳
softPwmCreate(Left_motor_pwm,0,255);
softPwmCreate(Right_motor_pwm,0,255);
//定義左右感測器為輸入介面
pinMode(AvoidSensorLeft, INPUT);
pinMode(AvoidSensorRight, INPUT);
//定義尋跡紅外感測器為輸入模式
pinMode(TrackSensorLeftPin1, INPUT);
pinMode(TrackSensorLeftPin2, INPUT);
pinMode(TrackSensorRightPin1, INPUT);
pinMode(TrackSensorRightPin2, INPUT);
//定義光敏電阻引腳為輸入模式
pinMode(LdrSensorLeft, INPUT);
pinMode(LdrSensorRight, INPUT);
//初始化蜂鳴器IO為輸出方式
pinMode(buzzer, OUTPUT);
digitalWrite(buzzer, HIGH);
//初始化超聲波引腳模式
pinMode(EchoPin, INPUT); //定義超聲波輸入腳
pinMode(TrigPin, OUTPUT); //定義超聲波輸出腳
//定義滅火IO口為輸出模式並初始化
pinMode(OutfirePin, OUTPUT);
//初始化RGB三色LED的IO口為輸出方式,並初始化
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
softPwmCreate(LED_R,0,255);
softPwmCreate(LED_G,0,255);
softPwmCreate(LED_B,0,255);
//初始化舵機引腳為輸出模式
pinMode(FrontServoPin, OUTPUT);
//初始化舵機引腳為輸出模式
pinMode(FrontServoPin, OUTPUT);
pinMode(ServoUpDownPin, OUTPUT);
pinMode(ServoLeftRightPin, OUTPUT);
//舵機位置初始化
servo_init();
//開啟串列埠裝置,如若失敗則會列印錯誤資訊
if ((fd = serialOpen("/dev/ttyAMA0", 9600)) < 0)
{
fprintf(stderr, "Uable to open serial device: %s\n", strerror(errno));
return -1;
}
while(1)
{
//呼叫串列埠解包函式
serialEvent();
if (NewLineReceived)
{
printf("serialdata:%s\n",InputString);
serial_data_parse(); //呼叫串列埠解析函式
NewLineReceived = 0;
}
//切換不同功能模式
switch (g_modeSelect)
{
case 1: break; //暫時保留
case 2: Tracking_Mode(); break; //巡線模式
case 3: Ultrasonic_avoidMode(); break; //超聲波避障模式
case 4: LED_Color_Mode(); break; //七彩顏色模式
case 5: LightSeeking_Mode(); break; //尋光模式
case 6: Infrared_follow_Mode(); break; //紅外跟隨模式
}
//舵機雲臺的控制
Servo_Control_Thread();
//讓串列埠平均每秒傳送採集的資料給上位機
if(g_modeSelect == 1)
{
serialtime--;
if(serialtime ==0)
{
count--;
serialtime = 5000;
if(count == 0)
{
serial_data_postback(fd);
serialtime = 5000;
count = 20;
}
}
}
usleep(10);
}
serialClose(fd); //關閉串列埠
return 0;
}
- servo_appointed_detection(n);// 舵機旋轉一定的角度
/**
* Function servo_pulse
* @brief 定義一個脈衝函式,用來模擬方式產生PWM值
* 時基脈衝為20ms,該脈衝高電平部分在0.5-2.5ms
* 控制0-180度
* @param[in1] ServPin:舵機控制引腳
* @param[in2] myangle:舵機轉動指定的角度
* @param[out] void
* @retval void
* @par History 無
*/
void servo_pulse(int v_iServoPin, int myangle)
{
int PulseWidth; //定義脈寬變數
PulseWidth = (myangle * 11) + 500; //將角度轉化為500-2480 的脈寬值
digitalWrite(v_iServoPin, HIGH); //將舵機介面電平置高
delayMicroseconds(PulseWidth); //延時脈寬值的微秒數
digitalWrite(v_iServoPin, LOW); //將舵機介面電平置低
delay(20 - PulseWidth / 1000); //延時週期內剩餘時間
return;
}
/**
* Function servo_appointed_detection
* @brief 舵機旋轉到指定角度
* @param[in] pos:指定的角度
* @param[out] void
* @retval void
* @par History 無
*/
void servo_appointed_detection(int pos)
{
int i = 0;
for (i = 0; i <= 20; i++) //產生PWM個數,等效延時以保證能轉到響應角度
{
servo_pulse(FrontServoPin, pos); //模擬產生PWM
}
}
- 超聲波測距函式
/**
* Function Distance
* @brief 超聲波測一次前方的距離
* @param[in] void
* @param[out] void
* @retval float:distance返回距離值
* @par History 無
*/
float Distance()
{
float distance;
struct timeval tv1;
struct timeval tv2;
struct timeval tv3;
struct timeval tv4;
long start, stop;
digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH); //向Trig腳輸入至少10US的高電平
delayMicroseconds(15); //10
digitalWrite(TrigPin, LOW);
//防止程式未檢測到電平變化,陷入死迴圈,加入一個超時重測機制
gettimeofday(&tv3, NULL); //超時重測機制開始計時
start = tv3.tv_sec * 1000000 + tv3.tv_usec;
while(!digitalRead(EchoPin) == 1)
{
gettimeofday(&tv4, NULL); //超時重測機制結束計時
stop = tv4.tv_sec * 1000000 + tv4.tv_usec;
if ((stop - start) > 30000) //最大測5米時的時間值:10/340=0.03s
{
return -1; //超時返回-1
}
}
//防止程式未檢測到電平變化,陷入死迴圈,加入一個超時重測機制
gettimeofday(&tv1, NULL); //當echo腳電平變高時開始計時
start = tv1.tv_sec*1000000+tv1.tv_usec;
while(!digitalRead(EchoPin) == 0)
{
gettimeofday(&tv3,NULL); //超時重測機制開始計時
stop = tv3.tv_sec*1000000+tv3.tv_usec;
if ((stop - start) > 30000)
{
return -1;
}
} //超時重測機制結束計時
gettimeofday(&tv2, NULL); //當echo腳電平變低時結束計時
start = tv1.tv_sec * 1000000 + tv1.tv_usec;
stop = tv2.tv_sec * 1000000 + tv2.tv_usec;
distance = (float)(stop - start)/1000000 * 34000 / 2;
printf("distance: %f\n", distance);
return distance;
}
- 小車前進、後退、剎車、左拐、右拐等執行函式
/**
* Function