?編輯
風紊
現役大學牲,半退休robomaster視覺隊員
寫在前面
本文章主要介紹的是如何通過開源的serial
庫和虛擬串口實現上位機和下位機通信。
需求
假設下位機有這樣一個數據報發送給上位機
struct DataRecv {char start = 's';TeamColor color = TeamColor::Blue;Mode mode = Mode::Armor;float speed = 20;float euler[3] = {}; //(0,1,2) = (yaw,roll,pitch)char shoot_bool = 0;char RuneFlag = 0; char unused[10] = {};char end = 'e';
}//TeamColor是一個char類型的迭代類,Mode也是一個char類型的迭代類
其他數據我都不需要,只需要歐拉角,也就是一個浮點數數組,euler[3]
解決方法
serial庫的github倉庫
先clone下來,安裝,得到頭文件和動態庫。
我們來看看serial庫的構造函數:
class Serial {
public:/*!* Creates a Serial object and opens the port if a port is specified,* otherwise it remains closed until serial::Serial::open is called.** \param port A std::string containing the address of the serial port,* which would be something like 'COM1' on Windows and '/dev/ttyS0'* on Linux.** \param baudrate An unsigned 32-bit integer that represents the baudrate** \param timeout A serial::Timeout struct that defines the timeout* conditions for the serial port. \see serial::Timeout** \param bytesize Size of each byte in the serial transmission of data,* default is eightbits, possible values are: fivebits, sixbits, sevenbits,* eightbits** \param parity Method of parity, default is parity_none, possible values* are: parity_none, parity_odd, parity_even** \param stopbits Number of stop bits used, default is stopbits_one,* possible values are: stopbits_one, stopbits_one_point_five, stopbits_two** \param flowcontrol Type of flowcontrol used, default is* flowcontrol_none, possible values are: flowcontrol_none,* flowcontrol_software, flowcontrol_hardware** \throw serial::PortNotOpenedException* \throw serial::IOException* \throw std::invalid_argument*/Serial (const std::string &port = "" //需要打開的端口uint32_t baudrate = 9600, //設置波特率,缺省值位9600Timeout timeout = Timeout(), //打開超時的時間,缺省值時間為0bytesize_t bytesize = eightbits, //字節大小,缺省值位8位parity_t parity = parity_none, //奇偶校驗位,默認無奇偶校驗stopbits_t stopbits = stopbits_one, //停止位,缺省值為1位flowcontrol_t flowcontrol = flowcontrol_none);//流控制,默認五流控制,可選擇軟件流控制和硬件流控制
選項都設置好后,直接調用對象的open()方法就能打開串口通信。
讀數據的方法:
size_t
Serial::read (uint8_t *buffer, size_t size)
{ScopedReadLock lock(this->pimpl_);return this->pimpl_->read (buffer, size);
}
所以我們只需要將數據包轉為uint8_t的類型的存儲格式指針,傳給函數,并指定字節數size就能讀取數據了。
通信實現文件test.cpp
的代碼
#include <serial/serial.h>
#include <iostream>struct data_package
{char start = 's';char unused1[2];float speed = 20;float euler[3] = {}; //(0,1,2) = (yaw,roll,pitch)char shoot_bool = 0;char RuneFlag = 0; //char unused2[10] = {};char end = 'e';
} __attribute__((packed));
static_assert(sizeof(data_package) == 32);data_package data;
int main()
{std::cout << "helloworld" << std::endl;serial::Serial ser; // 實例化一個串口的對象ser.setPort("/dev/serial_sdk"); // 設置串口設備ser.setBaudrate(115200); // 設置波特率try{ser.open(); // 打開串口while (true){std::cout << "number" << ser.available() << std::endl; // 讀取到緩存區數據的字節數ser.read(reinterpret_cast<uint8_t *>(&data), 32);//將data_package類型結構體強制轉換位uint8_t類型的指針,來接收32字節的數據std::cout << data.start << data.unused1[0] << data.unused1[1] << std::endl;std::cout << "(yaw,pitch,roll)" << data.euler[0] << " " << data.euler[1] << " " << data.euler[2] << std::endl;}}catch (std::exception &e){std::cerr << e.what() << std::endl;}
}
使用g++編譯代碼失敗的話,可以參考關于庫不在默認搜索路徑時,g++鏈接庫時找不到函數實現的問題。
如果要給設備起別名,可以參考Linux下給外部掛載的設備起別名,而不使用內核名稱
Notice
如果結構體最后不接?attribute((packed)),經筆者測試,數據包大小變為36位。