這個有趣但復雜的項目將涵蓋從設計構建機器人到 linux (raspberry pi) 中的高級配置,再到構建 Android 應用程序和控制機器人。
之所以說它是個有趣的項目,是因為它比一般的項目更有野心,而且我認為通過在這里理解一些想法甚至復制整個項目也并不能完全復現整個項目,你會有很多東西需要學習。
首先,我們將使用有機玻璃、塑料板、帶變速箱的直流電機和各種電子元件來構建機器人。該設備將能夠獨立移動兩個前輪,并且能夠使用它的前照燈。然后我們將設置為機器人供電的樹莓派,并配置項目并安裝各種依賴項。然后我們將構建并安裝一個 android 應用程序,并使用它通過攝像頭和 wifi 連接遠程控制機器人。
所需技術和概念:
開發平臺:Arduino、Raspberry pi、Android
Linux:使用 docker、docker compose、使用 systemctl 配置服務、視頻流
編程:Android應用程序、python、arduino語言、串口通信、MQTT
第 1 步:需要的東西
材料:
1.有機玻璃板
2.塑料板(這里也可以用有機玻璃板)
3.膠水
4.輪胎+直流電機帶變速箱+支架。小螺母和螺栓,六角金屬墊片
6. 2 x 任意方向的車輪輪胎
7.小LED手電筒(會變成頭燈)
8. Arduino pro mini 328p
9. 2 x 紅外障礙物傳感器
10.印刷電路板
11.NPN晶體管(驅動手電筒)
12. L7805CV 5V穩壓器
13. L298 H橋
14. Rezistor 220 歐姆
16. 公微型 USB 連接器
17.各種電線
18. 3 v調節器(用于arduino和樹莓派之間的通信)
19. 公母PCB連接器
20.開/關開關
21. XT-60 母 LiPo 連接器
22. 2S 1300 mAh 鋰聚合物電池,帶 XT-60 連接器
23. 5v電池組
24.樹莓派 3
25.樹莓派卡
26.樹莓派案例
27.樹莓派相機
工具:
1. USB 到串行 FTDI 適配器 FT232RL 對 arduino pro mini 進行編程
2. Arduino IDE
3. 鉆孔
4.細鋸片
5. 螺絲刀
6.烙鐵
7. 剪線鉗
技能:
1.焊接
2.基本的arduino編程
3.Linux服務配置、包安裝
第 2 步:構建機器人平臺
我們要建造的機器人將具有以下規格:
- 兩個單獨的直流電機將在前輪上產生牽引力
- 后輪應該能夠向任何方向移動 360 度
- 方向將由前輪的變速控制,因此不需要單獨的方向機構,機器人也可以原地旋轉
- 頂部會有燈
- 它應該有足夠的空間放置電子設備、電池和帶攝像頭的樹莓派外殼
- 需要幾厘米的離地間隙來克服小障礙物
注意:不要忘記檢查圖像以獲取重要細節和構建提示。
我們要用有機玻璃或硬塑料制造機器人,我都用過,但你可以選擇任何你想要的。
底板上的底板為 18 x 13 厘米,直流發動機將用金屬支架螺母和螺栓連接。H 橋將安裝在面向地板的板中間。后輪將使用 2 cm 六角形金屬墊片(一側為公頭,一側為母頭)安裝
H 橋附近需要一個大孔來連接頂部的電子設備。
機器人的頂部由兩個“L”形的板組成,一個是 12 x 13 厘米,另一個是 6.5 x 13 厘米。塑料板將粘在一起。這些板將為電子設備提供蓋板、安裝前照燈的位置和樹莓派外殼的支撐。頂部將使用 6 cm 六角形金屬墊片從底部連接
第 3 步:構建電子設備
引腳分配(arduino):
LED手電筒:D3
左電機:PWM (D5), EN1, EN2(A4, A5)
右電機:PWM(D6)、EN1、EN2(A3、A2)
紅外傳感器:前(A0),后(A1)
樹莓派通信引腳:Tx:D11,Rx:D10
構建PCB,組裝
1.在最后一步中,我們已經在機器人的地板側安裝了 H 橋。我們還需要安裝兩個紅外傳感器,一個在前面,一個在后面。我們將使用一塊小金屬板將它們安裝在底盤上。金屬板將呈“L”形,并有兩個孔。我們將使用螺母和螺栓將其安裝在底盤上。傳感器將位于底盤的中間,一個在前面,一個在后面。
2.接下來是大燈部分,我為此使用了一個 5 伏的 LED 手電筒。我已經剪掉了頭燈,只暴露了“頭部”部分,并焊接了兩根電線為其供電。然后我將頭燈粘在機器人頂部的中間,并在頭燈附近鉆了一個孔,將電纜穿過孔并焊接一個小的母頭兩線連接器。
3.組裝樹莓派外殼。您將需要一個樹莓派、一個 pi 相機、至少 4 GB 的存儲卡、一個 pi 相機連接器。插入已安裝最新Raspian的卡,然后將pi相機連接器小心地插入樹莓派上,然后將其插入相機,然后關閉外殼。
4.用主要電子元件搭建PCB 。
焊接步驟:
a、切斷母 PCB 連接器,微控制器有兩個 12 針連接器和兩個 5 針連接器,紅外傳感器有兩個 3 針連接器,H 橋有一個六針連接器,樹莓派通信有一個針連接器(接地,TX,RX)
b、切斷所有連接器后,必須在 PCB 背面焊接
c、焊接 KF301-2P 連接器
d、將 NPN 晶體管和相應的電阻器焊接到它的基極
e、焊接 L7805CV 5V 穩壓器
f、將 arduino 上的3.3 伏穩壓器焊接到 raspeberry pi TX 線上
g、將公針焊接到 arduino pro mini
h、根據fritzig原理圖焊接所有紅色(+)、黑色(-)和白色(信號)細線
5. 連接器:
a、建立一個從 5V USB 電池組到樹莓派和 arduino 的連接器,您將需要一個 A 型公 USB 連接器、一個公微型 USB 連接器黑色和紅色線、熱縮管和一個母到母面包板連接器。首先將母對母連接器一分為二,這些部分將進入 arduino 負極和正極公針。A 型 USB 連接器將使用微型 USB 連接器向 arduino 和樹莓派供電。檢查圖像以焊接 USB 提示。
b、將 LiPo 電池的連接器連接到電子板,您將需要一個 XT-60 母 LiPo 連接器、紅線和黑線、熱縮管和一個能夠處理 10 A 的小開關。黑線將直接從XT-60到電子板(KF301-2P插入式螺絲連接器),紅線將通過小開關連接
c、使用母 - 公面包板連接器將機器人的兩個 IR 傳感器連接到 PCB 上相應的母連接器
d、使用公母面包板連接器將 H 橋連接到 PCB 的 6 針母連接器
e.、將電機正極和負極端子連接到 H 橋
F、將 H 橋主電源連接到 PCB 上的 KF301-2P 插入式螺釘連接器
6.在將 arduino 放置到 PCB 之前,使用放大鏡和萬用表仔細檢查所有內容
第 4 步:Arduino 代碼
首先我需要回答一個重要的問題:為什么必須存在一個中間 arduino 層而不是直接將 Pi 連接到電子設備?
1.更加模塊化,你可以在沒有PI的情況下在另一個項目中重復使用arduino機器人
2.為了安全起見,更換 3 美元的 arduino pro mini 比更換 Pi(35 美元)便宜
3. arduino 不會像 pi 那樣受到操作系統的干擾,因此為電機實現 PWM 控制會更有效,每秒輪詢前后傳感器幾次
4.如果python腳本中可能發生錯誤,機器人可能會永遠運行,耗盡電池并可能損壞它或著火,如果??沒有監督,在arduino草圖中它更可靠,因為它不依賴于操作系統
5.解耦系統更容易調試
好的,所以我已經涵蓋了為什么部分,我將稍微解釋一下 arduino 草圖。它基本上做了兩件事:
1.它接收來自串行線的電機和燈光命令并驅動電機或切換燈光
例如:
* “ M:-25:16; ” 表示(-25 左)和(16 功率),它將轉換為左電機 17% 和右電機 32%,并且方向向前 * “ M:44:19; ” 表示(向右 44)和(19 功率)它將轉換為:左電機 38%,右電機 5% 和前進方向
* “ L:1; ”表示燈亮,“ L:0 ”燈滅
2.它從機器人前后輪詢紅外傳感器,并通過串行線發送有關距離的數據
首先,您需要下載并安裝庫,主要代碼位于 github 存儲庫中,你可以從本文下方復制粘貼它。
使用 FTDI 適配器將代碼上傳到 arduino?,F在您可以向機器人發出命令以查看它的工作情況,為此只需連接第二條串行線并通過它發送電機或光。一種方法是使用 HC-05 之類的藍牙模塊,并使用藍牙應用程序將其連接到手機。然后給它像“L:1”這樣的串行命令
// source for TextMotorCommandsInterpretter: "https://github.com/danionescu0/arduino/tree/master/libraries/TextMotorCommandsInterpretter"?
#include
#include
const char MOTOR_COMMAND = 'M';?
const char LIGHT_COMMAND = 'L';?
/**?
* how long the motor command will take effect in ms?
* an incomming motor command will last for maxDurationForMottorCommand?
* if it's not going to be resetted by another motor command?
*/?
const long maxDurationForMottorCommand = 300;?
// adjust this value to limit robot speed?
const byte maxPwmValue = 230;?
// How long between successive distance transmissions in ms?
const long transmitingInterval = 500;?
const int maxObstacleDetection = 1000; // analog read max detection value?
const int minObstacleDetection = 500; // analog read min detection value?
const byte FLASH_PIN = 3;?
const byte RIGHT_MOTOR_PWM_PIN = 5;?
const byte RIGHT_MOTOR_EN1_PIN = A4;?
const byte RIGHT_MOTOR_EN2_PIN = A5;?
const byte LEFT_MOTOR_PWM_PIN = 6;?
const byte LEFT_MOTOR_EN1_PIN = A3;?
const byte LEFT_MOTOR_EN2_PIN = A2;?
const byte FRONT_DISTANCE_SENSOR = A0;?
const byte BACK_DISTANCE_SENSOR = A1;?
SoftwareSerial masterComm(11, 10); // RX, TX?
TextMotorCommandsInterpretter motorCommandsInterpretter(-50, 50, -50, 50);?
String currentCommand;?
long lastCheckedTime;?
long lastTransmitTime;?
boolean inMotion = false;?
void setup() ?
{?
? ?Serial.begin(9600);?
? ?masterComm.begin(9600);?
? ?masterComm.setTimeout(10); ??
? ?pinMode(FLASH_PIN, OUTPUT);?
? ?pinMode(LEFT_MOTOR_PWM_PIN, OUTPUT);?
? ?pinMode(LEFT_MOTOR_EN1_PIN, OUTPUT);?
? ?pinMode(LEFT_MOTOR_EN2_PIN, OUTPUT);?
? ?pinMode(RIGHT_MOTOR_PWM_PIN, OUTPUT);?
? ?pinMode(RIGHT_MOTOR_EN1_PIN, OUTPUT);?
? ?pinMode(RIGHT_MOTOR_EN2_PIN, OUTPUT);?
? ?lastCheckedTime = millis();?
? ?lastTransmitTime = millis();?
}?
void loop() ?
{?
? ?if (masterComm.available() > 0) { ? ?
? ? ? ?currentCommand = masterComm.readString();?
? ? ? ?processCommand();?
? ?}?
? ?if (inMotion && millis() - lastCheckedTime > maxDurationForMottorCommand) {?
? ? ? ?stopMotors();?
? ?}?
? ?if (millis() - lastTransmitTime > transmitingInterval) {?
? ? ? ?lastTransmitTime = millis();?
? ? ? ?masterComm.print(getObstacleData());?
? ? ? ?Serial.print(analogRead(BACK_DISTANCE_SENSOR));Serial.print("---");?
? ? ? ?Serial.println(getObstacleData());?
? ?}?
? ?/* FOR DEBUG?
? ?motorCommandsInterpretter.analizeText("M:-14:40;");?
? ?Serial.write("Left==");Serial.println(motorCommandsInterpretter.getPercentLeft());?
? ?Serial.write("Right==");Serial.println(motorCommandsInterpretter.getPercentRight()); ? ?
? ?delay(10000);*/?
}?
String getObstacleData()?
{?
? ?int frontDistance = analogRead(FRONT_DISTANCE_SENSOR);?
? ?int backDistace = analogRead(BACK_DISTANCE_SENSOR);?
? ?frontDistance = map(frontDistance, maxObstacleDetection, minObstacleDetection, 0, 10);?
? ?backDistace = map(backDistace, maxObstacleDetection, minObstacleDetection, 0, 10);?
? ?return String("F=" + String(frontDistance) + ":B=" + String(backDistace) + ";");?
}?
void processCommand() ?
{?
? ?switch (currentCommand.charAt(0)) {?
? ? ? ?case (MOTOR_COMMAND):?
? ? ? ? ? ?steerCar();?
? ? ? ? ? ?break;?
? ? ? ?case (LIGHT_COMMAND):?
? ? ? ? ? ?toggleLight(currentCommand.charAt(2));?
? ? ? ? ? ?break;?
? ?}?
}?
void steerCar() ?
{?
? ?motorCommandsInterpretter.analizeText(currentCommand);?
? ?float percentLeftMotor = motorCommandsInterpretter.getPercentLeft();?
? ?float percentRightMotor = motorCommandsInterpretter.getPercentRight();?
? ?Serial.write("Left=");Serial.println(percentLeftMotor);?
? ?Serial.write("Right=");Serial.println(percentRightMotor);?
? ?setMotorsDirection(motorCommandsInterpretter.getDirection());?
? ?analogWrite(LEFT_MOTOR_PWM_PIN, percentLeftMotor * maxPwmValue);?
? ?analogWrite(RIGHT_MOTOR_PWM_PIN, percentRightMotor * maxPwmValue); ? ??
? ?inMotion = true;?
? ?lastCheckedTime = millis();?
}?
void setMotorsDirection(boolean forward)?
{?
? ?if (forward) {?
? ? ? ?digitalWrite(LEFT_MOTOR_EN1_PIN, HIGH);?
? ? ? ?digitalWrite(LEFT_MOTOR_EN2_PIN, LOW);?
? ? ? ?digitalWrite(RIGHT_MOTOR_EN1_PIN, HIGH);?
? ? ? ?digitalWrite(RIGHT_MOTOR_EN2_PIN, LOW);?
? ?} else {?
? ? ? ?digitalWrite(LEFT_MOTOR_EN1_PIN, LOW);?
? ? ? ?digitalWrite(LEFT_MOTOR_EN2_PIN, HIGH);?
? ? ? ?digitalWrite(RIGHT_MOTOR_EN1_PIN, LOW);?
? ? ? ?digitalWrite(RIGHT_MOTOR_EN2_PIN, HIGH);?
? ?}?
}?
void stopMotors()?
{?
? ?Serial.println("Stopping motors");?
? ?analogWrite(LEFT_MOTOR_PWM_PIN, 0);?
? ?analogWrite(RIGHT_MOTOR_PWM_PIN, 0);?
? ?inMotion = false;?
}?
void toggleLight(char command)?
{?
? ?Serial.println("Toggle light");?
? ?if (command == '1') {?
? ? ? ?digitalWrite(FLASH_PIN, HIGH);?
? ?} else {?
? ? ? ?digitalWrite(FLASH_PIN, LOW);?
? ?}?
}??
第 5 步:安裝和配置 Raspberry Pi 項目和依賴項
它是如何工作的:
a、android 應用程序在 web 視圖中顯示 uv4l 流。uv4l 進程在樹莓派上運行,從攝像頭捕獲視頻輸入并將其流式傳輸。這是一個很棒的工具,具有許多功能
b、使用 android 應用程序中的控件將燈和引擎命令發送到 MQTT 服務器
c、樹莓派上 docker 容器內的 python 服務器偵聽 MQTT 命令并使用串行接口將它們傳遞給 arduino。arduino 板控制電機和燈。
d、arduino 感知機器人前后的距離,并通過串行接口將數據發送到 python 服務器,python 將它們轉發到 MQTT,它們被 android 接口拾取并顯示給用戶
首先需要在樹莓派上完全安裝和配置 Raspbian,并且相機需要進行心理連接和配置。此外,所有配置都將使用 ssh 完成,因此配置它是一件便利的功能。
如果您希望在 wifi 外部使用 android 應用程序控制您的機器人,您應該考慮在您的 wifi 路由器上進行端口轉發,否則您將被限制在 wifi 內使用您的本地 IP 地址。
要在樹莓派上找到您的本地 IP 地址,請使用“ifconfig”:
ifconfig?
.........?
eth0 ? ? ??
Link encap:Ethernet ?HWaddr b8:27:eb:16:e7:ff ??
? ? ? ? ?inet6 addr: fe80::ff00:f22f:9258:b92b/64 Scope:Link?
? ? ? ? ?UP BROADCAST MULTICAST ?MTU:1500 ?Metric:1?
? ? ? ? ?RX packets:0 errors:0 dropped:0 overruns:0 frame:0?
? ? ? ? ?TX packets:0 errors:0 dropped:0 overruns:0 carrier:0?
? ? ? ? ?collisions:0 txqueuelen:1000 ?
? ? ? ? ?RX bytes:0 (0.0 B) ?TX bytes:0 (0.0 B)?
........?
wlan0 ? ? Link encap:Ethernet ?HWaddr 00:c1:41:00:10:f6 ??
? ? ? ? ?inet addr:192.168.0.102 ?Bcast:192.168.0.255 ?Mask:255.255.255.0?
? ? ? ? ?inet6 addr: fe80::e1f4:5112:9cb2:3839/64 Scope:Link?
? ? ? ? ?UP BROADCAST RUNNING MULTICAST ?MTU:1500 ?Metric:1?
? ? ? ? ?RX packets:1678396 errors:0 dropped:0 overruns:0 frame:0?
? ? ? ? ?TX packets:381859 errors:0 dropped:0 overruns:0 carrier:0?
? ? ? ? ?collisions:0 txqueuelen:1000 ?
? ? ? ? ?RX bytes:259428527 (247.4 MiB) ?TX bytes:187573084 (178.8 MiB)?
.....??
在我們的例子中是“192.168.0.102”
要轉發的端口(默認)是:9090 用于 uv4l,1883 用于 mosquitto。如果這些端口被 Internet 提供商防火墻或其他端口禁止,您可以將此端口轉發到相同的輸出端口。
端口轉發在每個路由器上都有不同的做法,這里有一些教程:this,您也可以嘗試在 google 上搜索“ port forwarding your_router_model ”以查看更多相關結果。
文件夾位置很重要,因為在 docker-compose.yml 中,該位置被硬編碼為:/home/pi/robot-camera-platform:/root/debug 如果您需要更改位置,請更改 docker-compose 中的值也
git clone https://github.com/danionescu0/robot-camera-platform.git
安裝 Uv4l 流媒體:
chmod +x uv4l/install.sh
chmod +x uv4l/start.sh
sh 。/uv4l/install.sh
第 6 步:配置和構建 Android 應用程序
我們已經完成了大部分工作,在這一步中,我們將安裝 android 應用程序。這些都是先決條件:
1.克隆github項目:
git clone https://github.com/danionescu0/android-robot-camera
接下來的步驟涉及設置您的環境,我將列舉它們并提供指向專門教程的鏈接,以防您不知道如何操作。
2.在您的安卓手機上啟用開發者選項。您可以在此處了解更多信息:https://developer.android.com/studio/debug/dev-opt.。.
3.下載并安裝Android studio:https://developer.android.com/studio/index.html?ut.。.這個https://www.javaworld.com/article/3095406/android/。..
4.導入項目:https://developer.android.com/studio/intro/migrate.。.
現在我們要配置流和 MQTT 憑據:
5.編輯。/app/src/main/values/passwords.xml并配置 MQTT 和流式傳輸
MQTT 主機應該類似于:1883
流媒體主機應該是這樣的:
6.上傳并運行應用程序
第 7 步:使用機器人和調試
使用應用程序
該應用程序只有一個主屏幕,在屏幕左側顯示流媒體圖像,在右側有控制界面。主控是方向盤,按您希望機器人移動的方向觸摸方向盤。方向盤下方有一個大燈按鈕,輕觸可切換燈光。
在右上角有一個文本,如:“- Batt Connected”。
*第一個破折號表示沒有障礙物,如果機器人前面或后面有障礙物,它將用一個指向前面或后面的小箭頭發出信號。
* “Batt”狀態尚未實現。
* “Connected” 表示 MQTT 服務器已連接,因此機器人可以使用,其他可能的值為 “Disconnected”
可以在多個層上進行調試:
1.在arduino層
- 將 FTDI 適配器連接到筆記本電腦的第二條串行線(RX 連接到引腳 11,TX 連接到引腳 10)并發出電機命令和燈光命令以查看機器人是否響應這些命令
- 仔細檢查連接,如果電機向后移動,則將兩條電機線反向,如果一個電機向后移動,則將其線反向
- 檢查 arduino 是否正確連接到 H 橋
2. 在樹莓派層上
- 檢查 docker 是否正在運行兩個容器(mosquitto 和 python 服務器)
pi@raspberrypi:~ $ docker ps?
CONTAINER ID ? ? ? ?IMAGE ? ? ? ? ? ? ? ? ? ? ? ? ? COMMAND ? ? ? ? ? ? ? ? ?CREATED ? ? ? ? ? ? STATUS ? ? ? ? ? ? ?PORTS ? ? ? ? ? ? ? ? ? ?NAMES?
473a56da2230 ? ? ? ?dockercontainer_python-server ? "python /root/debu..." ? 9 months ago ? ? ? ?Up 4 hours ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dockercontainer_python-server_1?
3e0b1933d310 ? ? ? ?robot-camera-mosquitto ? ? ? ? ?"/usr/bin/entry.sh..." ? 9 months ago ? ? ? ?Up 4 hours ? ? ? ? ?0.0.0.0:1883->1883/tcp ? dockercontainer_mosquitto_1 ?
- 檢查進程是否在指定端口上運行,您應該尋找 9090和 1883
pi@raspberrypi:~ $ netstat -nltp?
(Not all processes could be identified, non-owned process info?
will not be shown, you would have to be root to see it all.)?
Active Internet connections (only servers)?
Proto Recv-Q Send-Q Local Address ? ? ? ? ? Foreign Address ? ? ? ? State ? ? ? PID/Program name?
tcp ? ? ? ?0 ? ? ?0 0.0.0.0:9090 ? ? ? ? ? ?0.0.0.0:* ? ? ? ? ? ? ? LISTEN ? ? ?- ? ? ? ? ? ? ? ?
tcp ? ? ? ?0 ? ? ?0 0.0.0.0:5900 ? ? ? ? ? ?0.0.0.0:* ? ? ? ? ? ? ? LISTEN ? ? ?- ? ? ? ? ? ? ? ?
tcp ? ? ? ?0 ? ? ?0 0.0.0.0:8080 ? ? ? ? ? ?0.0.0.0:* ? ? ? ? ? ? ? LISTEN ? ? ?- ? ? ? ? ? ? ? ?
tcp ? ? ? ?0 ? ? ?0 0.0.0.0:22 ? ? ? ? ? ? ?0.0.0.0:* ? ? ? ? ? ? ? LISTEN ? ? ?- ? ? ? ? ? ? ? ?
tcp6 ? ? ? 0 ? ? ?0 :::1883 ? ? ? ? ? ? ? ? :::* ? ? ? ? ? ? ? ? ? ?LISTEN ? ? ?- ? ? ? ? ? ? ? ?
tcp6 ? ? ? 0 ? ? ?0 :::5900 ? ? ? ? ? ? ? ? :::* ? ? ? ? ? ? ? ? ? ?LISTEN ? ? ?- ? ? ? ? ? ? ? ?
tcp6 ? ? ? 0 ? ? ?0 :::22 ? ? ? ? ? ? ? ? ? :::* ? ? ? ? ? ? ? ? ? ?LISTEN ? ? ?-?
- 檢查串口是否存在并且它在項目config.py中指定
pi@raspberrypi:~ $ ls -l /dev/ttyS0?
crw-rw---- 1 root dialout 4, 64 Jan 14 19:59 /dev/ttyS0?
- 停止 docker 進程并使用picocom手動連接到串口
然后直接發出電機和燈光指令,看機器人是否響應
sudo systemctl start robot-camera.service?
picocom -b 9600 /dev/ttyS0?
# now issue motor and light commands to test the robot?
- 檢查樹莓派上的串行控制臺是否已停用
- 檢查流媒體和 MQTT 是否可以在樹莓派外部訪問,起訴 mosquitto 客戶端(用于 MQTT)并在 Web 瀏覽器中檢查流媒體)
3.Android應用層
- 檢查所有必要步驟以使手機進入調試模式
- 確保您已在 passwords.xml 中正確設置密碼和端點
- 檢查流媒體和 MQTT 是否可以在樹莓派外部訪問,起訴 mosquitto 客戶端(用于 MQTT)并在 Web 瀏覽器中檢查流媒體)
- 查看應用程序的右上角并檢查“已連接”
- 使用 android 調試器檢查錯誤
評論
查看更多