2025.8.29機械臂實戰項目

? ? ? ? 好久沒給大家更新了,上周末大學大四開學,所以停更了幾天,回來后在做項目,接下來的幾篇文章,給大家帶來幾個項目,第一個介紹的是機械臂操作,說是機械臂操作,簡單來說,就是tcp網絡通信,完成相應的指令。

? ? ? ? 任務要求是:

????????1)基于TCP服務器的機械臂,端口號可指定暫時為8888, ip是Windows的ip;

????????查看Windows的IP:按住Windows+r 按鍵,輸入cmd , 輸入ipconfig

????????2)點擊軟件中的開啟監聽;

????????3)機械臂需要發送16進制數,共5個字節,協議如下

????????0xff 0x02 x y 0xff

????????0xff:起始結束協議,固定的;

????????0x02:控制機械手臂協議,固定的;

????????x:指定要操作的機械臂 0x00 紅色擺臂 0x01 藍色擺臂

????????y:指定角度

? ? ? ? 機械臂的小應用如下圖,因為涉及版權問題,先不貼給大家了,可以私信

????????首先我們來看一下完成這個任務需要怎么做,初始化階段,核心是建立客戶端與服務器的通信鏈路。先通過socket()函數創建 TCP 套接字(負責數據傳輸的 “通道”),若創建失敗則報錯退出;接著定義服務器的網絡信息(IP、端口、協議族),并通過connect()函數與目標服務器建立連接,確保后續指令能準確送達;同時初始化紅 / 藍臂的初始角度(紅 0°、藍 90°),并向用戶提示控制按鍵規則與角度范圍,為后續操作鋪墊。
然后是核心交互階段,以 “用戶輸入 - 角度計算 - 指令封裝 - 數據發送” 為循環邏輯。通過getchar()獲取用戶按鍵(w/s/d/a/q),先處理退出邏輯(按 q 則關閉連接并退出);若為控制按鍵,則先更新對應機械臂的角度(紅臂 ±1°、藍臂 ±1°),并強制將角度限制在規定范圍(紅 - 90°~90°、藍 0°~180°);再按固定協議封裝 5 字節指令(起始符 0xff + 類型 0x02 + 臂標識 + 角度 + 結束符 0xff),最后通過send()將指令發送給服務器,完成一次控制;若輸入無效按鍵,則提示用戶重新輸入。
最后是收尾階段,當用戶按 q 退出循環后,通過close()關閉之前創建的 TCP 套接字,釋放網絡資源,確保程序優雅退出,避免資源泄漏。

#include <myhead.h>  // 自定義頭文件,通常包含標準庫和項目通用定義// 宏定義服務器的端口號和IP地址
#define PORT 8888       // 服務器監聽的端口號
#define IP "192.168.0.74"  // 服務器的IP地址int main(int argc, const char *argv[])
{char key;             // 存儲用戶輸入的控制按鍵char buff[5];         // 用于發送數據的緩沖區,長度為5字節// 創建TCP套接字:AF_INET表示IPv4協議,SOCK_STREAM表示TCP協議,0表示自動選擇協議int oldfd = socket(AF_INET, SOCK_STREAM, 0);// 檢查套接字是否創建成功if (oldfd == -1){perror("socket");  // 打印錯誤信息return -1;         // 創建失敗,退出程序}// 定義服務器的網絡地址結構struct sockaddr_in server = {.sin_family = AF_INET,                // 使用IPv4地址族.sin_port = htons(PORT),              // 將端口號轉換為網絡字節序.sin_addr.s_addr = inet_addr(IP)      // 將字符串IP轉換為網絡字節序};// 連接到服務器if (connect(oldfd, (struct sockaddr *)&server, sizeof(server)) == -1){perror("connect");  // 打印連接失敗信息return -1;          // 連接失敗,退出程序}// 連接成功后,打印服務器信息和操作提示printf("已成功連接了服務器%s-%d\n", inet_ntoa(server.sin_addr), PORT);printf("控制命令為:w--(紅色臂順時針+1°) s--(紅色臂逆時針-1°) d--(藍色臂順時針+1°) a--(藍色臂逆時針-1°)\n");printf("角度范圍:紅色臂(-90°~90°)  藍色臂(0°~180°)\n");printf("按q鍵退出程序\n");// 初始化機械臂角度int red_angle = 0;    // 紅色臂初始角度設為0°int blue_angle = 90;  // 藍色臂初始角度設為90°// 主控制循環:持續接收用戶輸入并發送控制命令while (1){printf("\n請輸入控制按鍵:");key = getchar();               // 獲取用戶輸入的按鍵while(getchar()!='\n');        // 清空輸入緩沖區,避免殘留字符影響下次輸入// 檢查是否退出程序if (key == 'q'){printf("退出程序...\n");break;  // 跳出循環,結束程序}// 初始化數據緩沖區(通信協議格式)buff[0] = 0xff;  // 幀頭標志buff[1] = 0x02;  // 數據類型或長度標識buff[4] = 0xff;  // 幀尾標志// 根據用戶輸入的按鍵執行相應操作switch (key){case 'w':  // 紅色臂順時針旋轉+1°red_angle += 1;// 限制角度在有效范圍內if(red_angle > 90){red_angle = 90;  // 超過最大角度,強制設為最大值}else if(red_angle < -90) {red_angle = -90; // 小于最小角度,強制設為最小值}buff[2] = 0x00;     // 0x00表示控制紅色臂buff[3] = red_angle; // 存儲當前角度值printf("紅色臂角度更新:%d°\n", red_angle);break;case 's':  // 紅色臂逆時針旋轉-1°red_angle -= 1;// 限制角度在有效范圍內if(red_angle > 90){red_angle = 90;}else if(red_angle < -90){red_angle = -90;}buff[2] = 0x00;     // 0x00表示控制紅色臂buff[3] = red_angle; // 存儲當前角度值printf("紅色臂角度更新:%d°\n", red_angle);break;case 'd':  // 藍色臂順時針旋轉+1°blue_angle += 1;// 限制角度在有效范圍內if(blue_angle > 180){blue_angle = 180;}else if(blue_angle < 0){blue_angle = 0;}buff[2] = 0x01;     // 0x01表示控制藍色臂buff[3] = blue_angle;// 存儲當前角度值printf("藍色臂角度更新:%d°\n", blue_angle);break;case 'a':  // 藍色臂逆時針旋轉-1°blue_angle -= 1;// 限制角度在有效范圍內if(blue_angle > 180) {blue_angle = 180;}else if(blue_angle < 0){blue_angle = 0;}buff[2] = 0x01;     // 0x01表示控制藍色臂buff[3] = blue_angle;// 存儲當前角度值printf("藍色臂角度更新:%d°\n", blue_angle);break;default:  // 處理無效輸入printf("無效按鍵!請重新輸入(w/s/d/a/q)\n");continue;  // 跳過本次循環,不發送數據}// 發送數據到服務器int res = send(oldfd, buff, 5, 0);if (res == -1)  // 檢查發送是否成功{perror("send");    // 打印發送失敗信息close(oldfd);      // 關閉套接字return -1;         // 退出程序}}// 關閉套接字,釋放資源close(oldfd);return 0;
}

? ? ? ? 我的這個代碼主要以單次命令為主,即輸入wads回車完成對機械臂紅藍色機械臂的控制,在完善代碼的過程中,我發現紅藍色機械臂的角度受限紅色機械臂的可調角度為-90°-90°,而藍色機械臂可調角度為0-180°所以我加了個限制,使角度始終為這個區間內,來看一下效果。

? ? ? ? 先看一下自己電腦現在的IP地址

? ? ? ? 隨后我發現這樣一次次的操作再加上回車太過麻煩,效率非常低,我隨后通過init_curses()函數初始化終端為無緩沖、無回顯模式,支持實時按鍵響應(無需按回車確認)

#include <myhead.h>
#include <curses.h>  // 包含curses庫
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#define PORT 8888
#define IP "192.168.0.74"// 初始化curses模式
void init_curses() {initscr();          // 初始化屏幕cbreak();           // 關閉行緩沖,按鍵直接生效noecho();           // 關閉輸入回顯keypad(stdscr, TRUE); // 啟用特殊按鍵支持refresh();          // 刷新屏幕
}// 顯示程序信息和控制說明
void show_info(int red_angle, int blue_angle) {clear();            // 清空屏幕// 顯示標題和連接信息mvprintw(1, 2, "===== 機械臂控制系統 =====");mvprintw(3, 2, "已連接服務器: %s:%d", IP, PORT);// 顯示當前角度信息mvprintw(5, 2, "當前角度:");mvprintw(6, 4, "紅色臂: %d° (范圍: -90° ~ 90°)", red_angle);mvprintw(7, 4, "藍色臂: %d° (范圍: 0° ~ 180°)", blue_angle);// 顯示控制說明mvprintw(9, 2, "控制命令:");mvprintw(10, 4, "w: 紅色臂順時針 (+1°)");mvprintw(11, 4, "s: 紅色臂逆時針 (-1°)");mvprintw(12, 4, "d: 藍色臂順時針 (+1°)");mvprintw(13, 4, "a: 藍色臂逆時針 (-1°)");mvprintw(14, 4, "q: 退出程序");// 顯示狀態提示mvprintw(16, 2, "狀態: 就緒 (按任意控制鍵操作)");mvprintw(17, 2, "----------------------------------------");refresh();          // 刷新屏幕顯示
}// 顯示操作結果提示
void show_status(const char *msg) {mvprintw(16, 2, "狀態: %s", msg);  // 在固定位置顯示狀態mvprintw(18, 2, "按任意鍵繼續...");refresh();getch();            // 等待按鍵繼續
}int main(int argc, const char *argv[]) {char key;char buff[5]; int oldfd = socket(AF_INET, SOCK_STREAM, 0);int red_angle = 0;    // 紅色臂初始角度int blue_angle = 90;  // 藍色臂初始角度// 初始化cursesinit_curses();// 創建socketif (oldfd == -1) {endwin();  // 退出curses模式perror("socket創建失敗");return -1;}// 設置服務器地址struct sockaddr_in server = {.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = inet_addr(IP)};// 連接服務器if (connect(oldfd, (struct sockaddr *)&server, sizeof(server)) == -1) {endwin();  // 退出curses模式perror("連接服務器失敗");close(oldfd);return -1;}// 顯示初始界面show_info(red_angle, blue_angle);// 主控制循環while (1) {key = getch();  // 無緩沖讀取按鍵,無需回車// 退出程序if (key == 'q') {break;}buff[0] = 0xff;  buff[1] = 0x02;  buff[4] = 0xff;char status_msg[100] = {0};int send_flag = 0;// 處理按鍵邏輯switch (key) {case 'w':  // 紅色臂+1°if (red_angle < 90) {red_angle++;buff[2] = 0x00;buff[3] = red_angle;sprintf(status_msg, "紅色臂已更新至 %d° (發送成功)", red_angle);send_flag = 1;} else {sprintf(status_msg, "紅色臂已達最大角度 90° (無法繼續增加)");}break;case 's':  // 紅色臂-1°if (red_angle > -90) {red_angle--;buff[2] = 0x00;buff[3] = red_angle;sprintf(status_msg, "紅色臂已更新至 %d° (發送成功)", red_angle);send_flag = 1;} else {sprintf(status_msg, "紅色臂已達最小角度 -90° (無法繼續減小)");}break;case 'd':  // 藍色臂+1°if (blue_angle < 180) {blue_angle++;buff[2] = 0x01;buff[3] = blue_angle;sprintf(status_msg, "藍色臂已更新至 %d° (發送成功)", blue_angle);send_flag = 1;} else {sprintf(status_msg, "藍色臂已達最大角度 180° (無法繼續增加)");}break;case 'a':  // 藍色臂-1°if (blue_angle > 0) {blue_angle--;buff[2] = 0x01;buff[3] = blue_angle;sprintf(status_msg, "藍色臂已更新至 %d° (發送成功)", blue_angle);send_flag = 1;} else {sprintf(status_msg, "藍色臂已達最小角度 0° (無法繼續減小)");}break;default:sprintf(status_msg, "無效按鍵! 請使用 w/s/d/a/q");break;}// 發送數據if (send_flag) {int res = send(oldfd, buff, 5, 0);if (res == -1) {sprintf(status_msg, "發送失敗: %s", strerror(errno));}}// 更新界面和顯示狀態show_info(red_angle, blue_angle);show_status(status_msg);}// 清理資源close(oldfd);endwin();  // 退出curses模式,恢復終端printf("程序已退出\n");return 0;
}

? ? ? ? 單擊wads鍵無需緩沖直接執行,長按wads多次執行,就實現了無極控制機械臂的擺動幅度,基本完成了項目需求。

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

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

相關文章

【機器學習基礎】機器學習的要素:任務T、性能度量P和經驗E

第一章 機器學習的本質與理論框架 機器學習作為人工智能領域的核心支柱,其理論基礎可以追溯到20世紀中葉的統計學習理論。Tom Mitchell在其1997年的經典著作《Machine Learning》中給出了一個至今仍被廣泛引用的學習定義:"對于某類任務T和性能度量P,一個計算機程序被認…

wav音頻轉C語言樣點數組

WAV to C Header Converter 將WAV音頻文件轉換為C語言頭文件的Python腳本&#xff0c;支持將音頻數據嵌入到C/C項目中。 功能特性 音頻格式支持 PCM格式&#xff1a;支持8位、16位、24位、32位PCM音頻IEEE Float格式&#xff1a;支持32位浮點音頻多聲道&#xff1a;支持單聲道、…

01.《基礎入門:了解網絡的基本概念》

網絡基礎 文章目錄網絡基礎網絡通信核心原理網絡通信定義信息傳遞過程關鍵術語解釋網絡的分類網絡參考模型OSI 參考模型各層核心工作分層核心原則TCP/IP 參考模型&#xff08;4 層 / 5 層&#xff0c;實際應用模型&#xff09;TCP/IP 與 OSI 模型的對應關系傳輸層核心協議&…

基于vue駕校管理系統的設計與實現5hl93(程序+源碼+數據庫+調試部署+開發環境)帶論文文檔1萬字以上,文末可獲取,系統界面在最后面。

系統程序文件列表&#xff1a;項目功能&#xff1a;學員,教練,教練信息,預約信息,場地信息,時間安排,車輛信息,預約練車,時間段,駕校場地信息,駕校車輛信息,預約報名開題報告內容&#xff1a;一、選題背景與意義背景隨著汽車保有量持續增長&#xff0c;駕校行業規模不斷擴大&am…

灰度思維:解鎖世界原有本色的密碼

摘要本文深入探討灰度思維的概念內涵及其在處理他人評價中的應用價值。研究指出&#xff0c;灰度思維作為一種超越非黑即白的思維方式&#xff0c;能夠幫助個體以更客觀、全面的態度接受他人評價的片面性&#xff0c;從而促進個人成長和人際關系和諧。文章分析了他人評價片面性…

動態規劃--Day03--打家劫舍--198. 打家劫舍,213. 打家劫舍 II,2320. 統計放置房子的方式數

動態規劃–Day03–打家劫舍–198. 打家劫舍&#xff0c;213. 打家劫舍 II&#xff0c;2320. 統計放置房子的方式數 今天要訓練的題目類型是&#xff1a;【打家劫舍】&#xff0c;題單來自靈艾山茶府。 掌握動態規劃&#xff08;DP&#xff09;是沒有捷徑的&#xff0c;咱們唯一…

Nuxt.js@4 中管理 HTML <head> 標簽

可以在 nuxt.config.ts 中配置全局的 HTML 標簽&#xff0c;也可以在指定 index.vue 頁面中配置指定的 HTML 標簽。 在 nuxt.config.ts 中配置 HTML 標簽 export default defineNuxtConfig({compatibilityDate: 2025-07-15,devtools: { enabled: true },app: {head: {charse…

UCIE Specification詳解(十)

文章目錄4.5.3.7 PHYRETRAIN&#xff08;物理層重訓練&#xff09;4.5.3.7.1 Adapter initiated PHY retrain4.5.3.7.2 PHY initiated PHY retrain4.5.3.7.3 Remote Die requested PHY retrain4.5.3.8 TRAIN ERROR4.5.3.9 L1/L24.6 Runtime Recalibration4.7 Multi-module Link…

電商數據的獲取方式:API、爬蟲、第三方服務及更多

在競爭激烈的電商領域&#xff0c;數據是驅動業務增長的關鍵。準確、及時地獲取電商數據&#xff0c;并進行深入分析&#xff0c;能夠幫助企業洞察市場趨勢、優化運營策略、提升用戶體驗。本文將全面介紹電商數據的獲取方式&#xff0c;涵蓋API接口、網絡爬蟲技術、第三方數據服…

《WINDOWS 環境下32位匯編語言程序設計》第8章 通用對話框

Windows操作系統為一些常用功能提供了一些通用對話框&#xff08;Common Dialog Box&#xff09;&#xff0c;比如&#xff0c;在不同的應用程序中進行打開文件、選擇字體、選擇顏色等操作時&#xff0c;不同程序顯示的對話框的模樣都是一樣的。另外&#xff0c;把同樣的應用程…

SOME/IP-SD協議中組播IP地址和端口號應從何處獲取、由誰設置?

<摘要> AUTOSAR SOME/IP-SD協議中組播通信參數的核心配置規則明確規定了在服務端傳輸&#xff08;Server-Transmits&#xff09;和客戶端傳輸&#xff08;Client-Transmits&#xff09;兩種模式下&#xff0c;組播IP地址和端口號應從何處獲取、由誰設置&#xff0c;從而確…

DAY49打卡

追到第45天內容浙大疏錦行

十四、測試 (Testing)

Rust內置了強大的測試框架,使得編寫和運行測試變得非常簡單。Rust的測試系統主要包括單元測試、集成測試和文檔測試。 1. 單元測試 單元測試通常放在與被測試代碼相同的文件中,使用#[cfg(test)]模塊和#[test]屬性標記。 1.1 基本測試結構 // 在src/lib.rs或任何模塊中pub…

LeetCode 刷題【56. 合并區間】

56. 合并區間 自己做 解&#xff1a;排序合并 class Solution { public:static bool compare(const vector<int> &p1, const vector<int> &p2){ //按第一個數排序return p1[0] < p2[0]; }vector<vector<int>> merge(ve…

DistributedLock 實現.Net分布式鎖

在分布式系統中&#xff0c;經常會遇到多個實例同時訪問同一份資源的情況&#xff0c;例如&#xff1a; ? 多個服務節點同時寫入數據庫同一行數據? 定時任務在多個節點上同時運行&#xff0c;導致重復執行? 多實例寫緩存時出現數據覆蓋問題 為了解決 并發沖突 和 數據一致…

Flutter:ios打包ipa,證書申請,Xcode打包,完整流程

步驟1 - 5 為 申請ios的簽名文件&#xff0c;App ID&#xff0c;證書&#xff0c;描述文件&#xff0c;并添加測試打包設備。 步驟1&#xff1a;生成證書簽名文件&#xff08;打開鑰匙串訪問>證書助理>從證書頒發機構請求證書&#xff09; 存儲后得到了一個簽名文件&…

Shell 秘典(卷二)——號令延展秘術 與 流程掌控心法?if 天機判語篇精解

文章目錄前言一、命令擴展詳解1.1 邏輯運算符1.1.1 邏輯與運算符&#xff08;&&&#xff09;1.1.2 邏輯或運算符&#xff08;||&#xff09;1.1.3 組合使用注意事項1.2 echo 命令1.2.1 基本用法1.2.2 輸出到標準錯誤&#xff08;stderr&#xff09;1.3 標準文件描述符&…

Agent實戰教程:深度解析async異步編程在Langgraph中的性能優化

在現代Python開發中&#xff0c;異步編程已經成為提高程序性能的重要手段&#xff0c;特別是在處理網絡請求、數據庫操作或AI模型調用等耗時操作時。本文將通過實際的LangGraph 示例&#xff0c;深入解析async的真正作用&#xff0c;并揭示一個常見誤區&#xff1a;為什么異步順…

coalesce在sql中什么作用

COALESCE?是SQL中的一個函數&#xff0c;用于返回參數列表中的第一個非空值&#xff0c;若所有參數均為NULL則返回NULL&#xff0c;常用于處理數據中的空值情況。 ?核心功能與語法? COALESCE函數的基本語法為&#xff1a;COALESCE(expression1, expression2, ..., express…

【Rust】 6. 字符串學習筆記

一、Rust 字符串概述 Rust 字符串是 UTF-8 編碼的文本序列&#xff0c;提供兩種主要類型&#xff1a; &str - 字符串切片&#xff08;通常作為引用出現&#xff09;String - 動態可變的、擁有所有權的字符串 二、字符串字面量 (&str) 編譯時已知大小&#xff0c;靜態分…