ESP32開發入門(七):HTTP開發實踐

一、HTTP協議基礎

1.1 什么是HTTP?

HTTP(HyperText Transfer Protocol,超文本傳輸協議)是互聯網上應用最為廣泛的一種網絡協議,用于從服務器傳輸超文本到本地瀏覽器。它是一種無狀態的請求/響應協議,工作在客戶端-服務器計算模型中。

1.2 HTTP的工作原理

HTTP協議基于請求-響應模型,主要包含以下組件:

  • 客戶端(Client):發送HTTP請求(如瀏覽器、ESP32等設備)

  • 服務器(Server):接收請求并返回響應

  • 請求方法:GET、POST、PUT、DELETE等

  • 狀態碼:200(成功)、404(未找到)、500(服務器錯誤)等

ESP32設備(客戶端) --HTTP請求--> Web服務器 <--HTTP響應-- 瀏覽器或其他客戶端

1.3 HTTP的核心特性

  1. 簡單快速:基于文本的簡單協議

  2. 無連接:每次連接只處理一個請求

  3. 無狀態:協議不保留之前的請求信息

  4. 靈活:可以傳輸任意類型的數據

  5. 支持多種請求方法:滿足不同場景需求

1.4 HTTP在物聯網中的應用

  1. 設備數據上報:向服務器發送傳感器數據

  2. 遠程配置:從服務器獲取設備配置

  3. 固件升級:通過HTTP下載固件包

  4. Web控制界面:提供設備管理頁面

  5. API交互:與其他系統集成

二、ESP32-S3 HTTP通信程序 (FreeRTOS + Arduino框架)

下面是一個基于ESP32-S3的HTTP通信程序,使用FreeRTOS和Arduino框架實現。這個程序包含HTTP客戶端功能,可以向服務器發送GET和POST請求。

#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
?
// WiFi配置
const char* ssid = "你的WiFi名稱";
const char* password = "你的WiFi密碼";
?
// 服務器配置
const char* serverUrl = "http://你的服務器地址:端口/api/data"; // 示例:"http://192.168.1.100:3000/api/data"
?
// FreeRTOS任務句柄
TaskHandle_t httpTaskHandle = NULL;
TaskHandle_t wifiTaskHandle = NULL;
?
// 連接WiFi函數
void connectToWiFi() {Serial.println();Serial.print("正在連接WiFi: ");Serial.println(ssid);
?WiFi.begin(ssid, password);
?while (WiFi.status() != WL_CONNECTED) {vTaskDelay(500 / portTICK_PERIOD_MS);Serial.print(".");}
?Serial.println("");Serial.println("WiFi已連接");Serial.print("IP地址: ");Serial.println(WiFi.localIP());
}
?
// 發送HTTP GET請求
void sendHttpGetRequest() {if (WiFi.status() == WL_CONNECTED) {HTTPClient http;Serial.print("發送GET請求到: ");Serial.println(serverUrl);http.begin(serverUrl);int httpCode = http.GET();if (httpCode > 0) {Serial.printf("HTTP響應碼: %d\n", httpCode);if (httpCode == HTTP_CODE_OK) {String payload = http.getString();Serial.println("服務器響應:");Serial.println(payload);}} else {Serial.printf("GET請求失敗, 錯誤: %s\n", http.errorToString(httpCode).c_str());}http.end();} else {Serial.println("WiFi未連接,無法發送請求");}
}
?
// 發送HTTP POST請求
void sendHttpPostRequest() {if (WiFi.status() == WL_CONNECTED) {HTTPClient http;Serial.print("發送POST請求到: ");Serial.println(serverUrl);http.begin(serverUrl);http.addHeader("Content-Type", "application/json");// 創建JSON格式的POST數據String httpRequestData = "{\"deviceId\":\"ESP32-S3\",\"temperature\":25.5,\"humidity\":60}";int httpCode = http.POST(httpRequestData);if (httpCode > 0) {Serial.printf("HTTP響應碼: %d\n", httpCode);if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_CREATED) {String payload = http.getString();Serial.println("服務器響應:");Serial.println(payload);}} else {Serial.printf("POST請求失敗, 錯誤: %s\n", http.errorToString(httpCode).c_str());}http.end();} else {Serial.println("WiFi未連接,無法發送請求");}
}
?
// HTTP任務函數
void httpTask(void *pvParameters) {while (1) {// 每隔10秒發送一次請求static uint32_t lastRequestTime = 0;uint32_t now = millis();if (now - lastRequestTime > 10000) {lastRequestTime = now;// 交替發送GET和POST請求static bool sendGet = true;if (sendGet) {sendHttpGetRequest();} else {sendHttpPostRequest();}sendGet = !sendGet;}vTaskDelay(100 / portTICK_PERIOD_MS);}
}
?
// WiFi監控任務函數
void wifiMonitorTask(void *pvParameters) {while (1) {if (WiFi.status() != WL_CONNECTED) {Serial.println("WiFi連接丟失,嘗試重新連接...");connectToWiFi();}vTaskDelay(10000 / portTICK_PERIOD_MS); // 每10秒檢查一次}
}
?
void setup() {Serial.begin(115200);// 初始化WiFi連接connectToWiFi();// 創建HTTP任務xTaskCreatePinnedToCore(httpTask, ? ? ? ? ? // 任務函數"HTTP Task", ? ? ? ?// 任務名稱8192, ? ? ? ? ? ? ? // 堆棧大小NULL, ? ? ? ? ? ? ? // 參數1, ? ? ? ? ? ? ? ? ?// 優先級&httpTaskHandle, ? ?// 任務句柄1 ? ? ? ? ? ? ? ? ? // 運行在核心1上);// 創建WiFi監控任務xTaskCreatePinnedToCore(wifiMonitorTask, ? ?// 任務函數"WiFi Task", ? ? ? ?// 任務名稱4096, ? ? ? ? ? ? ? // 堆棧大小NULL, ? ? ? ? ? ? ? // 參數1, ? ? ? ? ? ? ? ? ?// 優先級&wifiTaskHandle, ? ?// 任務句柄0 ? ? ? ? ? ? ? ? ? // 運行在核心0上);
}
?
void loop() {// 主循環為空,所有功能由FreeRTOS任務處理vTaskDelay(1000 / portTICK_PERIOD_MS);
}

2.1 代碼說明

  1. WiFi連接

    • 使用WiFi.begin()連接到指定的WiFi網絡

    • 單獨的WiFi監控任務持續檢查連接狀態并在斷開時重新連接

  2. HTTP功能

    • 使用HTTPClient庫實現HTTP協議

    • 支持GET和POST請求

    • POST請求發送JSON格式數據

    • 自動處理HTTP響應

  3. FreeRTOS集成

    • 創建了兩個任務:一個用于HTTP通信,一個用于WiFi監控

    • 任務運行在不同的核心上以提高效率

    • 使用vTaskDelay()代替delay()以確保不阻塞其他任務

  4. 多任務處理

    • HTTP任務負責定期發送HTTP請求

    • WiFi任務持續監控網絡連接狀態

2.2 使用說明

  1. 修改ssidpassword為你自己的WiFi配置

  2. 修改serverUrl為你的服務器地址和API端點

  3. 根據需要調整POST請求的內容和格式

  4. 請求頻率可以在httpTask函數中調整

2.3 所需庫

  • WiFi.h (Arduino ESP32核心自帶)

  • HTTPClient (Arduino ESP32核心自帶)

三、HTTP驗證步驟 - 搭建Node.js服務器

為了驗證ESP32的HTTP功能,我們可以使用Node.js搭建一個簡單的服務器,接收ESP32的請求并返回響應。

下面我將詳細介紹如何搭建一個完整的Node.js服務器,并將HTML頁面數據整合到server.js文件中,以便于ESP32通過HTTP協議與服務器進行通信。

注意:若你電腦沒安裝node,請自行百度安裝,網上教程較多,這里就不贅述了。

3.1 創建Node.js服務器

  1. 新建一個文件夾作為項目目錄

  2. 在該目錄下創建server.js文件,內容如下:

const express = require('express');
const bodyParser = require('body-parser');
?
const app = express();
const port = 3000;
?
// 中間件
app.use(bodyParser.json());
?
// 存儲接收到的數據
let receivedData = [];
?
// HTML頁面內容
const htmlPage = `
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ESP32 數據監控</title><style>body {font-family: Arial, sans-serif;margin: 20px;}.data-container {margin-top: 20px;padding: 15px;border: 1px solid #ddd;border-radius: 5px;background-color: #f9f9f9;}button {padding: 10px 15px;background-color: #4CAF50;color: white;border: none;border-radius: 4px;cursor: pointer;}button:hover {background-color: #45a049;}.data-item {margin-bottom: 10px;padding: 10px;border-bottom: 1px solid #eee;}.timestamp {color: #666;font-size: 0.9em;}</style>
</head>
<body><h1>ESP32 數據監控</h1><button id="refreshBtn">刷新數據</button><div class="data-container"><h2>最新上報數據 (共<span id="dataCount">0</span>條)</h2><div id="dataDisplay"><p>暫無數據...</p></div></div>
?<script>const refreshBtn = document.getElementById('refreshBtn');const dataDisplay = document.getElementById('dataDisplay');const dataCount = document.getElementById('dataCount');// 格式化數據顯示function formatData(data) {if (data.receivedData && data.receivedData.length > 0) {return data.receivedData.map(item => \`<div class="data-item"><div><strong>設備ID:</strong> \${item.data.deviceId || '未知'}</div><div><strong>溫度:</strong> \${item.data.temperature || 'N/A'}°C</div><div><strong>濕度:</strong> \${item.data.humidity || 'N/A'}%</div><div class="timestamp">\${new Date(item.timestamp).toLocaleString()}</div></div>\`).join('');}return '<p>暫無數據...</p>';}// 獲取數據函數async function fetchData() {try {const response = await fetch('/api/data');const data = await response.json();dataCount.textContent = data.receivedData ? data.receivedData.length : 0;dataDisplay.innerHTML = formatData(data);} catch (error) {dataDisplay.innerHTML = \`<p style="color:red;">獲取數據失敗: \${error.message}</p>\`;}}// 初始加載數據document.addEventListener('DOMContentLoaded', fetchData);// 按鈕點擊事件refreshBtn.addEventListener('click', fetchData);// 每5秒自動刷新setInterval(fetchData, 5000);</script>
</body>
</html>
`;
?
// 首頁路由 - 返回HTML頁面
app.get('/', (req, res) => {res.send(htmlPage);
});
?
// GET請求處理 - 獲取所有數據
app.get('/api/data', (req, res) => {console.log('收到GET請求');res.status(200).json({message: '數據獲取成功',receivedData: receivedData,timestamp: new Date().toISOString()});
});
?
// POST請求處理 - 接收ESP32數據
app.post('/api/data', (req, res) => {console.log('收到POST請求:', req.body);// 驗證數據if (!req.body.deviceId) {return res.status(400).json({error: '缺少必要字段: deviceId'});}// 存儲數據receivedData.push({data: req.body,timestamp: new Date().toISOString()});// 限制存儲的數據量if (receivedData.length > 50) {receivedData = receivedData.slice(-50);}res.status(201).json({message: '數據接收成功',yourData: req.body});
});
?
// 清空數據接口
app.delete('/api/data', (req, res) => {receivedData = [];res.status(200).json({message: '所有數據已清空'});
});
?
// 啟動服務器
app.listen(port, () => {console.log(`服務器運行在 http://localhost:${port}`);console.log(`API端點:`);console.log(`GET / ? ? ? ? ?  - 查看數據監控頁面`);console.log(`GET /api/data ?  - 獲取所有接收到的數據`);console.log(`POST /api/data ? - 接收ESP32發送的數據`);console.log(`DELETE /api/data - 清空所有數據`);
});
3.1.1 代碼詳細說明
3.1.1.1 初始化設置
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
  • 引入Express框架和body-parser中間件

  • 創建Express應用實例

  • 設置服務器端口為3000

3.1.1.2 數據存儲
let receivedData = [];
  • 使用一個數組來存儲ESP32發來的所有數據

  • 每個數據項包含原始數據和接收時間戳

3.1.1.3 HTML頁面整合
const htmlPage = `...`;
  • 將完整的HTML頁面內容作為模板字符串存儲在變量中

  • 包含CSS樣式和內聯JavaScript

  • 使用ES6模板字符串語法方便插入變量

3.1.1.4 路由處理
  1. 首頁路由

    app.get('/', (req, res) => {res.send(htmlPage);
    });
    • 處理根路徑請求

    • 直接返回HTML頁面內容

  2. GET API接口

    app.get('/api/data', (req, res) => {res.json({message: '數據獲取成功',receivedData: receivedData,timestamp: new Date().toISOString()});
    });
    • 返回所有存儲的數據

    • 包含狀態信息和時間戳

  3. POST API接口

    app.post('/api/data', (req, res) => {// 數據驗證和存儲res.status(201).json({message: '數據接收成功',yourData: req.body});
    });
    • 接收ESP32發來的JSON數據

    • 驗證必要字段

    • 存儲數據并返回確認

  4. DELETE API接口

    app.delete('/api/data', (req, res) => {receivedData = [];res.json({ message: '所有數據已清空' });
    });
    • 清空存儲的數據

    • 用于測試和調試

3.1.1.5 前端JavaScript功能
// 格式化數據顯示
function formatData(data) {// 將JSON數據轉換為HTML顯示
}
?
// 獲取數據函數
async function fetchData() {// 從/api/data獲取數據并更新頁面
}
?
// 事件監聽和自動刷新
document.addEventListener('DOMContentLoaded', fetchData);
refreshBtn.addEventListener('click', fetchData);
setInterval(fetchData, 5000);
  • 使用Fetch API獲取數據

  • 動態更新頁面內容

  • 自動刷新和手動刷新功能

  • 數據格式化顯示

3.2 安裝依賴

在項目目錄下運行以下命令安裝必要的依賴:

npm init -y
npm install express body-parser

3.3 啟動服務器

node server.js

服務器啟動后,你將在控制臺看到:

服務器運行在 http://localhost:3000

現在你可以通過瀏覽器訪問http://localhost:3000來查看ESP32上報的數據。

3.4 驗證步驟

  1. 確保你的PC和ESP32在同一個局域網

  2. 修改ESP32代碼中的serverUrl為你的PC的IP地址和端口(如http://192.168.1.100:3000/api/data

  3. 上傳ESP32代碼并打開串口監視器

  4. 在瀏覽器中訪問http://localhost:3000

  5. 觀察串口輸出和網頁顯示的數據

3.6 預期結果

  • 串口輸出

    發送GET請求到: http://192.168.1.100:3000/api/data
    HTTP響應碼: 200
    服務器響應:
    {"message":"Hello from Node.js server!","receivedData":[...],"timestamp":"..."}
    ?
    發送POST請求到: http://192.168.1.100:3000/api/data
    HTTP響應碼: 201
    服務器響應:
    {"message":"Data received successfully","yourData":{"deviceId":"ESP32-S3","temperature":25.5,"humidity":60}}
  • 網頁顯示

    最新上報數據
    {"message": "Hello from Node.js server!","receivedData": [{"data": {"deviceId": "ESP32-S3","temperature": 25.5,"humidity": 60},"timestamp": "..."}],"timestamp": "..."
    }

四、實際項目應用示例

4.1 環境監測系統

功能設計

  • 定期上報溫濕度數據

  • 從服務器獲取配置參數

  • 實現固件升級檢查

void checkForUpdates() {HTTPClient http;http.begin("http://yourserver.com/api/update");int httpCode = http.GET();if (httpCode == HTTP_CODE_OK) {String payload = http.getString();DynamicJsonDocument doc(1024);deserializeJson(doc, payload);if (doc["available"] == true) {String newVersion = doc["version"];String firmwareUrl = doc["url"];if (newVersion != currentFirmwareVersion) {startFirmwareUpdate(firmwareUrl);}}}http.end();
}

4.2 遠程控制面板

功能設計

  • 提供Web控制界面

  • 實現設備狀態實時顯示

  • 支持多設備管理

void handleRoot() {String html = "<html><body>";html += "<h1>ESP32 Control Panel</h1>";html += "<p>Temperature: " + String(readTemperature()) + "°C</p>";html += "<p>Humidity: " + String(readHumidity()) + "%</p>";html += "<form method='post' action='/control'>";html += "<button name='led' value='on'>Turn LED On</button>";html += "<button name='led' value='off'>Turn LED Off</button>";html += "</form>";html += "</body></html>";server.send(200, "text/html", html);
}

五、HTTP最佳實踐與優化

  1. 安全考慮

    • 使用HTTPS替代HTTP

    • 實現API密鑰驗證

    • 限制請求頻率

  2. 性能優化

    • 復用HTTPClient對象

    • 減少不必要的頭信息

    • 使用連接池

  3. 錯誤處理

    • 實現自動重試機制

    • 添加超時設置

    • 記錄錯誤日志

  4. 數據格式

    • 使用JSON進行數據交換

    • 壓縮大數據量

    • 分頁獲取大量數據

六、常見HTTP服務器選擇

  1. 本地測試

    • Node.js + Express

    • Python Flask

    • PHP內置服務器

  2. 生產環境

    • Nginx

    • Apache

    • IIS

  3. 云服務

    • AWS API Gateway

    • 阿里云API網關

    • 騰訊云API網關

七、總結與擴展

HTTP作為互聯網的基礎協議,與ESP32的結合為物聯網設備提供了簡單可靠的數據通信方案,相對于上一篇MQTT協議,HTTP協議的開發和驗證更為簡單,若你對MQTT開發感興趣,可查看ESP32開發入門(六):MQTT開發實踐。掌握HTTP開發后,您可以進一步:

  1. 研究HTTPS安全連接

  2. 學習WebSocket實現實時通信

  3. 探索RESTful API設計

  4. 了解gRPC等高效協議

通過本篇教程,您應該已經掌握了ESP32上HTTP開發的核心知識。實際項目中,建議從簡單的原型開始,逐步增加功能復雜度,并始終考慮安全性和性能問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82427.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82427.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82427.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python 對象引用、可變性和垃圾 回收(變量不是盒子)

變量不是盒子 1997 年夏天&#xff0c;我在 MIT 學了一門 Java 課程。Lynn Andrea Stein 教授 &#xff08;一位獲獎的計算機科學教育工作者&#xff0c;目前在歐林工程學院教書&#xff09;指 出&#xff0c;人們經常使用“變量是盒子”這樣的比喻&#xff0c;但是這有礙于理…

局域網常用的測速工具,Iperf3使用教程

目錄 下載方式 Windows Linux 使用方法&#xff1a;測試局域網帶寬 步驟一&#xff1a;服務端準備 步驟二&#xff1a;客戶端發起連接 步驟三&#xff1a;查看結果 參數說明 1. Iperf常用參數&#xff08;測試夠用&#xff09; 2. 通用參數&#xff08;Server端和Cli…

《深入理解分布式系統》之認識分布式系統

本文是閱讀深入理解分布式系統第一章認識分布式系統時的筆記。 分布式系統的特點 多進程不共享操作系統不共享時鐘 分布式系統 由多個可獨立運行的子系統組成。每個子系統可以獨立選擇運行平臺。不同的運行平臺存在差異&#xff0c;比如操作系統&#xff0c;硬件規格等。由…

UE5 PCG學習筆記

https://www.bilibili.com/video/BV1onUdY2Ei3/?spm_id_from333.337.search-card.all.click&vd_source707ec8983cc32e6e065d5496a7f79ee6 一、安裝PCG 插件里選擇以下進行安裝 移動目錄后&#xff0c;可以使用 Update Redirector References&#xff0c;更新下&#xff0…

工業現場ModbusTCP轉EtherNETIP網關引領生物現場領新浪潮

生物質發生器是一種能夠產生、培養生物的設備。客戶現場需要將生物發生器連接到羅克韋爾系統&#xff0c;但是二者協議無法直接通訊&#xff0c;需要通過ModbusTCP轉Ethernet/IP網關將兩者進行通訊連接&#xff0c;生物質發生器以其獨特的工作原理和優勢&#xff0c;使得生物的…

寶藍德中間件部署war包時,配置的絕對路徑讀取錯誤。

文章目錄 問題場景解決辦法寶藍德是什么&#xff1f;&#xff1f;一、基礎環境與依賴配置二、自動化部署工具鏈三、高可用性與集群配置四、安全與合規性措施五、產品線差異化部署六、典型部署流程示例七、運維與優化 原因1. 明確“當前工作目錄”與“絕對路徑”的關系2. 問題根…

Java、Python、NodeJS等開發環境安裝及配置鏡像加速到國內源

文章目錄 Java1.Windows1.1 scoop方式安裝JDK 2.Linux2.1 apt方式安裝JDK2.1.1 切換JDK2.1.2 驗證版本2.1.3 原理 Python1.Windows1.1 scoop方式安裝Python1.2 uv方式安裝Python&#xff08;推薦&#xff09; 2.Linux2.1 apt方式安裝Python2.1.1 配置版本切換2.1.2 切換Python2…

Linux系統管理與編程16:PXE自動化安裝部署centos7.9操作系統

蘭生幽谷&#xff0c;不為莫服而不芳&#xff1b; 君子行義&#xff0c;不為莫知而止休。 0.準備 1&#xff09;防火墻和SELinux systemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i s/^SELINUX.*/SELINUXdisabled/ /etc/selinux/config (很不好的…

MCP(Model Context Protocol)是專為LLM(大語言模型)應用設計的標準化協議

核心定義 MCP&#xff08;Model Context Protocol&#xff09;是專為LLM&#xff08;大語言模型&#xff09;應用設計的標準化協議&#xff0c;通過安全可控的方式向AI應用暴露數據和功能。主要提供以下能力&#xff1a; 標準化的上下文管理安全的功能調用接口跨平臺的數據交…

Fiori學習專題三十四:Responsiveness

在這一步中&#xff0c;我們提高了應用程序的響應能力。SAPUI5應用程序可以在手機、平板電腦和臺式機設備上運行&#xff0c;我們可以配置應用程序以充分利用每種場景的屏幕狀態。幸運的是&#xff0c;像sap.m.Table這樣的SAPUI5控件已經提供了許多我們可以使用的功能。 1.修改…

解決 TimeoutError: [WinError 10060] 在 FramePack項目中連接 Hugging Face 超時的問題

#工作記錄 以下是針對 TimeoutError: [WinError 10060] 的完整排查方案&#xff0c;適用于 FramePack項目中。 &#xff08;一般該錯誤的發生原因請重點排查Hugging Face模型倉庫受限需要登錄的情形&#xff09; FramePack項目參考資料 FramePack部署&#xff08;從PyCharm解…

obj = null; 賦值null之前沒有其他引用指向obj對象,那么,當obj=null時,會被垃圾回收機制立即回收嗎?

不會立即回收。 具體原因是&#xff1a; 賦值 obj null; 后&#xff0c;對象變成“不可達”&#xff0c;符合垃圾回收條件&#xff0c;但垃圾回收器并不會立刻回收它。垃圾回收是CLR自動控制的非確定性過程&#xff0c;什么時候執行回收取決于系統內存壓力、GC策略、分代情況…

【Ubuntu 安裝Docker CE-Jenkins】

安裝Docker CE(Ubuntu) Install | Docker Docs官網 使用apt倉庫安裝 DNS配置(可選) #手動替換 sudo vim /etc/systemd/resolved.conf #典型配置如下 [Resolve] DNS8.8.8.8 DNS114.114.114.114 FallbackDNS1.1.1.1 # 備用 DNS#sed替換 sudo sed -i /^#DNS/ {s/#DNS/DNS8.8.8…

5、開放式PLC梯形圖編程組件 - /自動化與控制組件/open-plc-programming

76個工業組件庫示例匯總 開放式PLC編程環境 這是一個開放式PLC編程環境的自定義組件&#xff0c;提供了一個面向智能倉儲堆垛機控制的開放式PLC編程環境。該組件采用蘋果科技風格設計&#xff0c;支持多廠商PLC硬件&#xff0c;具有直觀的界面和豐富的功能。 功能特點 多語…

內網和外網怎么互通?外網訪問內網的幾種簡單方式

在企業或家庭網絡中&#xff0c;經常會遇到不同內網環境下網絡互通問題。例如&#xff0c;當公司本地局域網內有個辦公OA網站&#xff0c;在辦公室內電腦上網可以登錄使用&#xff0c;但在家帶寬下就無法直接通信訪問到。這就需要我們采取一些實用的內外網互通技巧來解決這個問…

使用大語言模型進行機器人規劃(Robot planning with LLMs)

李升偉 編譯 長期規劃在機器人學領域可以從經典控制方法與大型語言模型在現實世界知識能力的結合中獲益。 在20世紀80年代&#xff0c;機器人學和人工智能&#xff08;AI&#xff09;領域的專家提出了莫雷奇悖論&#xff0c;觀察到人類看似簡單的涉及移動和感知的任務&#x…

【計算機視覺】OpenCV實戰項目: opencv-text-deskew:實時文本圖像校正

opencv-text-deskew&#xff1a;基于OpenCV的實時文本圖像校正 一、項目概述與技術背景1.1 核心功能與創新點1.2 技術指標對比1.3 技術演進路線 二、環境配置與算法原理2.1 硬件要求2.2 軟件部署2.3 核心算法流程 三、核心算法解析3.1 文本區域定位3.2 角度檢測優化3.3 仿射變換…

可視化圖解算法33:判斷是不是平衡二叉樹

1. 題目 描述 輸入一棵節點數為 n 的二叉樹&#xff0c;判斷該二叉樹是否是平衡二叉樹。 在這里&#xff0c;我們只需要考慮其平衡性&#xff0c;不需要考慮其是不是排序二叉樹 平衡二叉樹&#xff08;Balanced Binary Tree&#xff09;&#xff0c;具有以下性質&#xff1…

【Linux網絡】應用層自定義協議與序列化

應用層自定義協議與序列化 應用層 我們程序員寫的一個個解決我們實際問題,滿足我們日常需求的網絡程序,都是在應用層. 協議是一種"約定".Socket的接口,在讀寫數據時,都是按"字符串"的方式來發送接收的.如果我們要傳輸一些"結構化的數據"怎么辦…

MySQL + Elasticsearch:為什么要使用ES,使用場景與架構設計詳解

MySQL Elasticsearch&#xff1a;為什么要使用ES&#xff0c;使用場景與架構設計詳解 前言一、MySQL Elasticsearch的背景與需求1.1 為什么要使用Elasticsearch&#xff08;ES&#xff09;&#xff1f;1.2 為什么MySQL在某些場景下不足以滿足需求&#xff1f;1.3 MySQL Elas…