日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【毕业设计】树莓派智能捡垃圾机器人 - 机器视觉 单片机 物联网

發(fā)布時間:2024/3/24 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【毕业设计】树莓派智能捡垃圾机器人 - 机器视觉 单片机 物联网 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 0 前言
  • 1 簡介
  • 2 主要器件
  • 3 實現(xiàn)效果
  • 4 設計原理
    • 1 在 Edge Impulse 中構建平衡良好的數(shù)據(jù)集
    • 2 在 Edge Impulse 中設計脈沖(神經(jīng)網(wǎng)絡模型)
    • 3 使用遷移學習訓練神經(jīng)網(wǎng)絡模型(脈沖)
    • 4 將 Raspberry Pi 4 連接到 Edge Impulse
    • 5 在 Raspberry Pi 4 上部署和運行模型
    • 6 在 Raspberry Pi 4 上設置 RPLIDAR A1M8 360 度激光雷達
    • 7 使用RPLIDAR A1M8檢測障礙物并控制機器人底盤
    • 8 使用 Arduino 為機器人構建跌倒檢測系統(tǒng)
  • 5 部分核心代碼
  • 8 最后


0 前言

🔥 這兩年開始畢業(yè)設計和畢業(yè)答辯的要求和難度不斷提升,傳統(tǒng)的畢設題目缺少創(chuàng)新和亮點,往往達不到畢業(yè)答辯的要求,這兩年不斷有學弟學妹告訴學長自己做的項目系統(tǒng)達不到老師的要求。

為了大家能夠順利以及最少的精力通過畢設,學長分享優(yōu)質(zhì)畢業(yè)設計項目,今天要分享的是

🚩 基于樹莓派的智能撿垃圾機器人

🥇學長這里給一個題目綜合評分(每項滿分5分)

  • 難度系數(shù):5分
  • 工作量:3分
  • 創(chuàng)新點:5分

🧿 選題指導, 項目分享:

https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%E6%AF%95%E8%AE%BE%E6%8C%87%E5%AF%BC/README.md


1 簡介

通過這款自動駕駛機器人,可進行物體檢測識別和監(jiān)控垃圾。它還部署了視頻流和跌倒檢測系統(tǒng)。
使用 Edge Impulse 構建了一個神經(jīng)網(wǎng)絡模型,用于在這三類下通過物體檢測來檢測垃圾:

  • 瓶子(玻璃和塑料)
  • 罐(金屬)
  • 包裝(塑料、紙、紙板等)

Edge Impulse 還可以在連接到 Raspberry Pi 后提供實時視頻流。因此,無需創(chuàng)建網(wǎng)絡攝像頭服務器 (Motion) 即可使用 Raspberry Pi 為該項目進行直播。

2 主要器件

  • 樹莓派4
  • RPLIDAR A1M8 360 度激光雷達
  • Arduino Nano
  • DFRobot Black Gladiator
  • SSD1306 OLED 屏幕(128x32)

3 實現(xiàn)效果



4 設計原理

1 在 Edge Impulse 中構建平衡良好的數(shù)據(jù)集

Edge Impulse是一個免費的嵌入式機器學習開發(fā)平臺,供開發(fā)人員(新手或?qū)<?#xff09;從學習到部署。它具有許多功能和內(nèi)置神經(jīng)網(wǎng)絡模型,可滿足各種要求,例如用于多目標檢測的遷移學習。此外,該平臺還提供來自連接設備攝像頭的實時視頻流。因此,本項目使用 Edge Impulse 來識別和監(jiān)控垃圾。

在構建用于物體檢測的神經(jīng)網(wǎng)絡模型之前,需要創(chuàng)建一個平衡良好的數(shù)據(jù)集來檢測多個垃圾類別:

瓶子(玻璃和塑料)
罐(金屬)
包裝(塑料、紙、紙板等)

通過精心挑選與上述垃圾類別相關的最合適的圖像,結合了廢物和垃圾的兩個不同數(shù)據(jù)集:

垃圾分類數(shù)據(jù)集
TACO 垃圾數(shù)據(jù)集

選擇后,每個類別大約有100張圖像,總共292張。通常,像這樣的小數(shù)據(jù)集無法在垃圾檢測中得到準確的結果。然而,Edge Impulse 在訓練模型時采用了遷移學習,所以得到了相當不錯的結果,而且準確率很高。

首先,注冊Edge Impulse并創(chuàng)建一個新項目(垃圾檢測機器人)。

為了能夠使用對象檢測模型,請轉到儀表板 ? 項目信息 ? 標簽方法并選擇Bounding box (object detection) 。

然后,轉到數(shù)據(jù)獲取并選擇上傳數(shù)據(jù)(上傳現(xiàn)有數(shù)據(jù))。

成功上傳垃圾數(shù)據(jù)集后,用提到的三個垃圾類別標記每個圖像 -瓶子、罐頭、包裝。在 Edge Impulse 中,標記一個對象,類似在它周圍拖動一個框并輸入一個標簽一樣簡單。此外,Edge Impulse 在標記對象時在后臺運行跟蹤算法,因此它會自動為不同圖像中的相同對象移動框。

?轉至數(shù)據(jù)獲取?標簽隊列(Object detection labeling)。它顯示了數(shù)據(jù)集中剩余的所有未標記圖像。

?然后,選擇一個未標記的圖像,拖動框,單擊Save labels ,然后重復此操作,直到整個數(shù)據(jù)集都被標記。


完成標記后,可以看到在數(shù)據(jù)采集下列出了一個平衡良好的數(shù)據(jù)集,用于垃圾檢測。

2 在 Edge Impulse 中設計脈沖(神經(jīng)網(wǎng)絡模型)

脈沖是邊緣脈沖中的自定義神經(jīng)網(wǎng)絡模型。在這個項目中,設計了一個脈沖,它獲取原始圖像數(shù)據(jù),調(diào)整圖像大小,使用預處理塊來處理圖像,然后利用學習塊對新數(shù)據(jù)進行分類:

圖像預處理塊 ? 取彩色圖像中的數(shù)據(jù),可選地使圖像灰度化,然后將數(shù)據(jù)轉化為特征數(shù)組。
遷移學習學習塊 -對象檢測(圖像)? 接收所有圖像并學習區(qū)分三種(瓶子、罐子、包裝)垃圾類別。
預處理塊總是為相同的輸入返回相同的值(例如,將彩色圖像轉換為灰度圖像),而學習塊則從過去的經(jīng)驗中學習。除了內(nèi)置的預處理塊,Edge Impulse 還允許用戶創(chuàng)建自定義預處理塊(步驟)。

?進入創(chuàng)建脈沖,設置圖像寬度和圖像高度為320,調(diào)整大小模式為適合最短軸。然后,添加圖像和對象檢測(圖像)塊。最后,單擊Save Impulse 。

配置處理塊和功能
? 要配置處理塊,請轉到Impulse design下的Image ,選擇顏色深度為RGB ,然后單擊Save parameters 。處理塊為模型適當?shù)馗袷交紙D像數(shù)據(jù)。

然后,在特征生成屏幕上,單擊生成特征以:

  • 調(diào)整圖像數(shù)據(jù)大小,
  • 將處理塊應用于圖像數(shù)據(jù),
  • 并創(chuàng)建完整的垃圾數(shù)據(jù)集的 3D 可視化。

3 使用遷移學習訓練神經(jīng)網(wǎng)絡模型(脈沖)

它正在努力從頭開始構建準確的計算機視覺模型,因為該模型需要各種各樣的輸入數(shù)據(jù)才能很好地泛化,并且在 GPU 上訓練此類模型可能需要數(shù)天時間。然而,Edge Impulse 在訓練用于對象檢測的神經(jīng)網(wǎng)絡模型時采用了遷移學習。轉移學習方法重新訓練訓練有素的神經(jīng)網(wǎng)絡模型的上層以進行對象檢測,從而產(chǎn)生更可靠的模型,這些模型可以在很短的時間內(nèi)進行訓練并使用更小的數(shù)據(jù)集。

盡管遷移學習使訓練對象檢測模型變得輕松,但使用機器學習識別和監(jiān)控垃圾仍然具有挑戰(zhàn)性。由于垃圾種類的顏色、形狀和材料各不相同,因此我從兩個不同的數(shù)據(jù)集中精心挑選了 292 張最合適的圖像,如前面的步驟所述。處理完我的數(shù)據(jù)集后,我用整個數(shù)據(jù)集訓練模型以區(qū)分三種不同的垃圾類別(瓶子、罐頭、包裝)。

使用數(shù)據(jù)集訓練模型后,Edge Impulse 將精度分數(shù)(準確度)評估為60.2% 。

? 進入Impulse design下的Object detection ,選擇默認的基礎模型,并設置:

訓練周期數(shù)? 40
學習率? 0.01

驗證神經(jīng)網(wǎng)絡模型

由于使用整個數(shù)據(jù)集來訓練模型,因此上傳了新圖像作為測試數(shù)據(jù)集來驗證模型。

在驗證模型后,推斷它區(qū)分瓶子(塑料和玻璃)和罐子(金屬)的準確率超過 88%。然而,它很難檢測包裝(塑料、紙、紙板等),因為包裝在很多方面都不同——形狀、顏色、材料等。由于收集的種類繁多,包裝的準確度在 45% 到 55% 之間。因此,我仍在收集數(shù)據(jù)以改進我的數(shù)據(jù)集和包裝的準確性。

使用測試數(shù)據(jù)集(大約 50 張圖像),Edge Impulse 評估模型精度為84.11% 。

? 要驗證模型,請轉到模型測試并選擇Classify all 。

4 將 Raspberry Pi 4 連接到 Edge Impulse

經(jīng)過設計、訓練、驗證和驗證后,剩下的就是將模型部署到了樹莓派 4。由于 Edge Impulse 官方支持樹莓派 4,因此使用此開發(fā)板部署和運行模型非常簡單。

?首先,打開終端,運行以下命令安裝依賴和模塊:

安裝依賴項后,將USB網(wǎng)絡攝像頭連接到Raspberry Pi 4并運行以下命令:邊緣脈沖Linux

然后,登錄并使用終端向?qū)нx擇一個Edge Impulse項目(垃圾檢測機器人)。

要驗證樹莓派 4 是否成功連接到所選 Edge Impulse 項目,請轉到項目頁面并單擊Devices 。

5 在 Raspberry Pi 4 上部署和運行模型

? 要在 Raspberry Pi 4 本地部署和運行模型,請打開終端并在下面輸入以下命令:

edge-impulse-linux-runner

? 然后,Edge Impulse 會自動編譯具有完整硬件加速的模型并將其下載到 Raspberry Pi 4。在這方面,該模型以最小的延遲和功耗運行。

在 Raspberry Pi 4 上部署模型后,將它和 USB 網(wǎng)絡攝像頭連接到機器人底盤。就可運行模型,就可以在三個垃圾類別之間進行分類。

瓶子(玻璃和塑料)
罐(金屬)
包裝(塑料、紙、紙板等)

由于 Edge Impulse 在模型運行時提供帶有來自連接的網(wǎng)絡攝像頭的分類結果的實時視頻流,因此當垃圾檢測機器人運行時,不需要創(chuàng)建帶有 Motion 或其他模塊的網(wǎng)絡攝像頭服務器來顯示分類結果。

? 要顯示實時視頻流和分類結果,直接在運行模型后轉到終端中給定的 URL:

6 在 Raspberry Pi 4 上設置 RPLIDAR A1M8 360 度激光雷達

為了讓垃圾檢測機器人自主移動,使用了 RPLIDAR A1M8-R6 - 360 度激光掃描儀(激光雷達)。該激光雷達可以在 12 米范圍內(nèi)執(zhí)行 360 度掃描,每秒生成多達 8000 個樣本。

沒有繪制環(huán)境來導航機器人(SLAM),而是使用激光雷達來檢測三個不同方向(右、左和前)的障礙物,因為我想讓機器人在不受環(huán)境(室內(nèi)或室外)任何限制的情況下運行)。

為了獲得 RPLIDAR A1M8 和 Raspberry Pi 生成的 360 度掃描數(shù)據(jù),我使用了Adafruit CircuitPython RPLIDAR庫。

在使用庫收集數(shù)據(jù)之前,將 RPLIDAR A1M8 連接到計算機 (Windows) 并運行Frame Grabber應用程序以在掃描周圍環(huán)境的同時檢查角度方向和距離測量值。

7 使用RPLIDAR A1M8檢測障礙物并控制機器人底盤

RPLIDAR A1M8 不是采用步進讀取方法,而是通過直流電機驅(qū)動旋轉掃描儀,并根據(jù)掃描儀獲得的角度生成距離讀數(shù)。這樣,單次旋轉不能保證為每個可能的角度(從 0 到 360)產(chǎn)生距離值。只需旋轉幾次,即可使用此激光雷達進行完整的 360 度掃描。因此,在不調(diào)試生成的掃描數(shù)據(jù)點的情況下,使用 RPLIDAR A1M8 進行避障可能會非常棘手和困難。

在設置好RPLIDAR A1M8并包括所需的模塊后,對掃描儀每轉產(chǎn)生的不完整的360度掃描數(shù)據(jù)進行調(diào)試和處理,以檢測三個不同方向的障礙物。對于每個方向,定義了一個起始角和一個終止角(順時針):

右 ? 開始:60 ,結束:120
左 ? 開始:240 ,結束:300
前 ? 開始:340結束:20
在每個方向范圍內(nèi),代碼搜索準確的距離測量作為起點和終點:

起點 ? 從起始角到起始角 + 15 ,
終點 ? 從終點角度到終點角度 - 15 .
這樣,代碼覆蓋每個方向的 30 度范圍,以得出準確的距離測量值(起點和終點),不會出現(xiàn)錯誤或遺漏。然后,如果引出的方向起點和終點小于給定閾值(40 cm),則代碼激活機器人底盤(L298N)以避開該方向檢測到的障礙物。

在完成代碼并將激光雷達(RPLIDAR A1M8)安裝到機器人底盤上后,在外殼上測試了垃圾檢測機器人的避障系統(tǒng)。

8 使用 Arduino 為機器人構建跌倒檢測系統(tǒng)

完成上述步驟后,為垃圾檢測機器人添加一個 6 軸加速度計作為跌倒檢測系統(tǒng),以防止碰撞。跌倒檢測系統(tǒng)還顯示 X、Y 和 Z 軸的加速度測量值。

下載所需的庫以從 DFRobot 串行 6 軸加速度計獲取數(shù)據(jù)。
下載控制 SSD1306 OLED 屏幕所需的庫。

為了構建機器人的跌倒檢測系統(tǒng),我將 DFRobot 串行 6 軸加速度計、SSD1306 OLED 屏幕(128x32)和蜂鳴器連接到 Arduino Nano。為了提供 Arduino Nano,將它連接到 Raspberry Pi 4:

5 部分核心代碼

/*!@file getLightIntensity.ino@Set the frequency of data output by the sensor, read the acceleration, angular velocity, and angle of X, Y, and Z axes.@n Experimental phenomenon: when the sensor starts, it outputs data at the set frequency and the data will be displayed on serial monitor@copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)@licence The MIT License (MIT)@author [huyujie](yujie.hu@dfrobot.com)@version V1.0@date 2020-12-03@https://github.com/DFRobot */ #include <DFRobot_WT61PC.h> #include <SoftwareSerial.h>//Use software serial port RX:10,TX:11 SoftwareSerial mySerial(10, 11);DFRobot_WT61PC sensor(&mySerial);void setup() {//Use Serial as debugging serial port Serial.begin(115200);//Use software serial port mySerial as communication seiral port mySerial.begin(9600);//Revise the data output frequncy of sensor FREQUENCY_0_1HZ for 0.1Hz, FREQUENCY_0_5HZ for 0.5Hz, FREQUENCY_1HZ for 1Hz, FREQUENCY_2HZ for 2Hz, // FREQUENCY_5HZ for 5Hz, FREQUENCY_10HZ for 10Hz, FREQUENCY_20HZ for 20Hz, FREQUENCY_50HZ for 50Hz, // FREQUENCY_100HZ for 100Hz, FREQUENCY_125HZ for 125Hz, FREQUENCY_200HZ for 200Hz.sensor.modifyFrequency(FREQUENCY_10HZ); }void loop() {if (sensor.available()) {Serial.print("Acc\t"); Serial.print(sensor.Acc.X); Serial.print("\t"); Serial.print(sensor.Acc.Y); Serial.print("\t"); Serial.println(sensor.Acc.Z); //acceleration information of X,Y,ZSerial.print("Gyro\t"); Serial.print(sensor.Gyro.X); Serial.print("\t"); Serial.print(sensor.Gyro.Y); Serial.print("\t"); Serial.println(sensor.Gyro.Z); //angular velocity information of X,Y,ZSerial.print("Angle\t"); Serial.print(sensor.Angle.X); Serial.print("\t"); Serial.print(sensor.Angle.Y); Serial.print("\t"); Serial.println(sensor.Angle.Z); //angle information of X, Y, Z Serial.println(" ");} } void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {// Pixel is in-bounds. Rotate coordinates if needed.switch (getRotation()) {case 1:ssd1306_swap(x, y);x = WIDTH - x - 1;break;case 2:x = WIDTH - x - 1;y = HEIGHT - y - 1;break;case 3:ssd1306_swap(x, y);y = HEIGHT - y - 1;break;}switch (color) {case SSD1306_WHITE:buffer[x + (y / 8) * WIDTH] |= (1 << (y & 7));break;case SSD1306_BLACK:buffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7));break;case SSD1306_INVERSE:buffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7));break;}} }/*!@brief Clear contents of display buffer (set all pixels to off).@return None (void).@note Changes buffer contents only, no immediate effect on display.Follow up with a call to display(), or with other graphicscommands as needed by one's own application. */ void Adafruit_SSD1306::clearDisplay(void) {memset(buffer, 0, WIDTH * ((HEIGHT + 7) / 8)); }/*!@brief Draw a horizontal line. This is also invoked by the Adafruit_GFXlibrary in generating many higher-level graphics primitives.@param xLeftmost column -- 0 at left to (screen width - 1) at right.@param yRow of display -- 0 at top to (screen height -1) at bottom.@param wWidth of line, in pixels.@param colorLine color, one of: SSD1306_BLACK, SSD1306_WHITE or SSD1306_INVERSE.@return None (void).@note Changes buffer contents only, no immediate effect on display.Follow up with a call to display(), or with other graphicscommands as needed by one's own application. */ void Adafruit_SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w,uint16_t color) {bool bSwap = false;switch (rotation) {case 1:// 90 degree rotation, swap x & y for rotation, then invert xbSwap = true;ssd1306_swap(x, y);x = WIDTH - x - 1;break;case 2:// 180 degree rotation, invert x and y, then shift y around for height.x = WIDTH - x - 1;y = HEIGHT - y - 1;x -= (w - 1);break;case 3:// 270 degree rotation, swap x & y for rotation,// then invert y and adjust y for w (not to become h)bSwap = true;ssd1306_swap(x, y);y = HEIGHT - y - 1;y -= (w - 1);break;}if (bSwap)drawFastVLineInternal(x, y, w, color);elsedrawFastHLineInternal(x, y, w, color); }/*!@brief Draw a horizontal line with a width and color. Used by publicmethods drawFastHLine,drawFastVLine@param xLeftmost column -- 0 at left to (screen width - 1) at right.@param yRow of display -- 0 at top to (screen height -1) at bottom.@param wWidth of line, in pixels.@param colorLine color, one of: SSD1306_BLACK, SSD1306_WHITE orSSD1306_INVERSE.@return None (void).@note Changes buffer contents only, no immediate effect on display.Follow up with a call to display(), or with other graphicscommands as needed by one's own application. */ void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w,uint16_t color) {if ((y >= 0) && (y < HEIGHT)) { // Y coord in bounds?if (x < 0) { // Clip leftw += x;x = 0;}if ((x + w) > WIDTH) { // Clip rightw = (WIDTH - x);}if (w > 0) { // Proceed only if width is positiveuint8_t *pBuf = &buffer[(y / 8) * WIDTH + x], mask = 1 << (y & 7);switch (color) {case SSD1306_WHITE:while (w--) {*pBuf++ |= mask;};break;case SSD1306_BLACK:mask = ~mask;while (w--) {*pBuf++ &= mask;};break;case SSD1306_INVERSE:while (w--) {*pBuf++ ^= mask;};break;}}} }/*!@brief Draw a vertical line. This is also invoked by the Adafruit_GFXlibrary in generating many higher-level graphics primitives.@param xColumn of display -- 0 at left to (screen width -1) at right.@param yTopmost row -- 0 at top to (screen height - 1) at bottom.@param hHeight of line, in pixels.@param colorLine color, one of: SSD1306_BLACK, SSD1306_WHITE or SSD1306_INVERSE.@return None (void).@note Changes buffer contents only, no immediate effect on display.Follow up with a call to display(), or with other graphicscommands as needed by one's own application. */ void Adafruit_SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h,uint16_t color) {bool bSwap = false;switch (rotation) {case 1:// 90 degree rotation, swap x & y for rotation,// then invert x and adjust x for h (now to become w)bSwap = true;ssd1306_swap(x, y);x = WIDTH - x - 1;x -= (h - 1);break;case 2:// 180 degree rotation, invert x and y, then shift y around for height.x = WIDTH - x - 1;y = HEIGHT - y - 1;y -= (h - 1);break;case 3:// 270 degree rotation, swap x & y for rotation, then invert ybSwap = true;ssd1306_swap(x, y);y = HEIGHT - y - 1;break;}if (bSwap)drawFastHLineInternal(x, y, h, color);elsedrawFastVLineInternal(x, y, h, color); }/*!@brief Draw a vertical line with a width and color. Used by public methoddrawFastHLine,drawFastVLine@param xLeftmost column -- 0 at left to (screen width - 1) at right.@param __yRow of display -- 0 at top to (screen height -1) at bottom.@param __h height of the line in pixels@param colorLine color, one of: SSD1306_BLACK, SSD1306_WHITE orSSD1306_INVERSE.@return None (void).@note Changes buffer contents only, no immediate effect on display.Follow up with a call to display(), or with other graphicscommands as needed by one's own application. */ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y,int16_t __h, uint16_t color) {if ((x >= 0) && (x < WIDTH)) { // X coord in bounds?if (__y < 0) { // Clip top__h += __y;__y = 0;}if ((__y + __h) > HEIGHT) { // Clip bottom__h = (HEIGHT - __y);}if (__h > 0) { // Proceed only if height is now positive// this display doesn't need ints for coordinates,// use local byte registers for faster jugglinguint8_t y = __y, h = __h;uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x];// do the first partial byte, if necessary - this requires some maskinguint8_t mod = (y & 7);if (mod) {// mask off the high n bits we want to setmod = 8 - mod;// note - lookup table results in a nearly 10% performance// improvement in fill* functions// uint8_t mask = ~(0xFF >> mod);static const uint8_t PROGMEM premask[8] = {0x00, 0x80, 0xC0, 0xE0,0xF0, 0xF8, 0xFC, 0xFE};uint8_t mask = pgm_read_byte(&premask[mod]);// adjust the mask if we're not going to reach the end of this byteif (h < mod)mask &= (0XFF >> (mod - h));switch (color) {case SSD1306_WHITE:*pBuf |= mask;break;case SSD1306_BLACK:*pBuf &= ~mask;break;case SSD1306_INVERSE:*pBuf ^= mask;break;}pBuf += WIDTH;}if (h >= mod) { // More to go?h -= mod;// Write solid bytes while we can - effectively 8 rows at a timeif (h >= 8) {if (color == SSD1306_INVERSE) {// separate copy of the code so we don't impact performance of// black/white write version with an extra comparison per loopdo {*pBuf ^= 0xFF; // Invert bytepBuf += WIDTH; // Advance pointer 8 rowsh -= 8; // Subtract 8 rows from height} while (h >= 8);} else {// store a local value to work withuint8_t val = (color != SSD1306_BLACK) ? 255 : 0;do {*pBuf = val; // Set bytepBuf += WIDTH; // Advance pointer 8 rowsh -= 8; // Subtract 8 rows from height} while (h >= 8);}}if (h) { // Do the final partial byte, if necessarymod = h & 7;// this time we want to mask the low bits of the byte,// vs the high bits we did above// uint8_t mask = (1 << mod) - 1;// note - lookup table results in a nearly 10% performance// improvement in fill* functionsstatic const uint8_t PROGMEM postmask[8] = {0x00, 0x01, 0x03, 0x07,0x0F, 0x1F, 0x3F, 0x7F};uint8_t mask = pgm_read_byte(&postmask[mod]);switch (color) {case SSD1306_WHITE:*pBuf |= mask;break;case SSD1306_BLACK:*pBuf &= ~mask;break;case SSD1306_INVERSE:*pBuf ^= mask;break;}}}} // endif positive height} // endif x in bounds }/*!@brief Return color of a single pixel in display buffer.@param xColumn of display -- 0 at left to (screen width - 1) at right.@param yRow of display -- 0 at top to (screen height -1) at bottom.@return true if pixel is set (usually SSD1306_WHITE, unless display invertmode is enabled), false if clear (SSD1306_BLACK).@note Reads from buffer contents; may not reflect current contents ofscreen if display() has not been called. */ bool Adafruit_SSD1306::getPixel(int16_t x, int16_t y) {if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {// Pixel is in-bounds. Rotate coordinates if needed.switch (getRotation()) {case 1:ssd1306_swap(x, y);x = WIDTH - x - 1;break;case 2:x = WIDTH - x - 1;y = HEIGHT - y - 1;break;case 3:ssd1306_swap(x, y);y = HEIGHT - y - 1;break;}return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7)));}return false; // Pixel out of bounds }

8 最后

總結

以上是生活随笔為你收集整理的【毕业设计】树莓派智能捡垃圾机器人 - 机器视觉 单片机 物联网的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。