ROS串列埠程式設計學習筆記

詩筱涵發表於2020-10-01

 

摘自:https://blog.csdn.net/u014695839/article/details/81209082

ROS串列埠程式設計學習筆記

 

培培哥 2018-07-25 21:15:13 11172 收藏 67

分類專欄: ROS

版權

串列埠是一種裝置間常用的通訊介面,本文將記錄如何在ROS上使用其提供的serial包進行串列埠通訊。

首先,這裡要引入一個名稱為serial的包,這個包的安裝命令為:

$ sudo apt-get install ros-<版本號>-serial

serial包的介紹:http://wiki.ros.org/serial

接下來,建立一個自己的包,藉助serial這個包來編寫串列埠通訊的程式碼。

1、建立一個包,依賴roscpp和serial兩個包

$ catkin_create_pkg serial_port roscpp serial

2、在這個包的目錄下面建立src目錄,並在src目錄中編寫串列埠通訊的程式碼

 
  1. //serial_port.cpp

  2. #include <ros/ros.h>

  3. #include <serial/serial.h>

  4. #include <iostream>

  5.  
  6. int main(int argc, char** argv)

  7. {

  8. ros::init(argc, argv, "serial_port");

  9. //建立控制程式碼(雖然後面沒用到這個控制程式碼,但如果不建立,執行時程式會出錯)

  10. ros::NodeHandle n;

  11.  
  12. //建立一個serial類

  13. serial::Serial sp;

  14. //建立timeout

  15. serial::Timeout to = serial::Timeout::simpleTimeout(100);

  16. //設定要開啟的串列埠名稱

  17. sp.setPort("/dev/ttyUSB0");

  18. //設定串列埠通訊的波特率

  19. sp.setBaudrate(115200);

  20. //串列埠設定timeout

  21. sp.setTimeout(to);

  22.  
  23. try

  24. {

  25. //開啟串列埠

  26. sp.open();

  27. }

  28. catch(serial::IOException& e)

  29. {

  30. ROS_ERROR_STREAM("Unable to open port.");

  31. return -1;

  32. }

  33.  
  34. //判斷串列埠是否開啟成功

  35. if(sp.isOpen())

  36. {

  37. ROS_INFO_STREAM("/dev/ttyUSB0 is opened.");

  38. }

  39. else

  40. {

  41. return -1;

  42. }

  43.  
  44. ros::Rate loop_rate(500);

  45. while(ros::ok())

  46. {

  47. //獲取緩衝區內的位元組數

  48. size_t n = sp.available();

  49. if(n!=0)

  50. {

  51. uint8_t buffer[1024];

  52. //讀出資料

  53. n = sp.read(buffer, n);

  54.  
  55. for(int i=0; i<n; i++)

  56. {

  57. //16進位制的方式列印到螢幕

  58. std::cout << std::hex << (buffer[i] & 0xff) << " ";

  59. }

  60. std::cout << std::endl;

  61. //把資料傳送回去

  62. sp.write(buffer, n);

  63. }

  64. loop_rate.sleep();

  65. }

  66.  
  67. //關閉串列埠

  68. sp.close();

  69.  
  70. return 0;

  71. }

serial包的文件有對每個類和函式的解釋,可以參考:http://docs.ros.org/kinetic/api/serial/html/annotated.html

其中解釋一下timeout的作用,在serial::Timeout結構體中有這麼5個成員:

 
  1.  
  2. serial::Timeout::Timeout (

  3. uint32_t inter_byte_timeout_ = 0,

  4. uint32_t read_timeout_constant_ = 0,

  5. uint32_t read_timeout_multiplier_ = 0,

  6. uint32_t write_timeout_constant_ = 0,

  7. uint32_t write_timeout_multiplier_ = 0

  8. )

參考另一個大神的解釋:(出處:https://www.cnblogs.com/visionfeng/p/5614066.html

“間隔超時=ReadIntervalTimeout
總超時   =   ReadTotalTimeoutMultiplier   * 位元組數   +   ReadTotalTimeoutConstant 

串列埠讀取事件分為兩個階段(我以Win32 API函式ReadFile讀取串列埠過程來說明一下)
第一個階段是:串列埠執行到ReadFile()函式時,串列埠還沒有開始傳輸資料,所以串列埠緩衝區的第一個位元組是沒有裝資料的,這時候總超時起作用,如果在總超時時間內沒有進行串列埠資料的傳輸,ReadFile()函式就返回,當然 沒有讀取到任何資料。而且,間隔超時並沒有起作用。
第二階段:假設總超時為20秒,程式執行到ReadFile(),總超時開始從0 計時,如果在計時到達10秒時,串列埠開始了資料的傳輸,那麼從接收的第一個位元組開始,間隔超時就開始計時,假如間隔超時為1ms,那麼在讀取完第一個位元組後,串列埠開始等待1ms,如果1ms之內接收到了第二個位元組,就讀取第二個位元組,間隔超時重置為0並計時,等待第三個位元組的到來,如果第三個位元組到來的時間超過了1ms,那麼ReadFile()函式立即返回,這時候總超時計時是沒到20秒的。如果在20秒總計時時間結束之前,所有的資料都遵守資料間隔為1ms的約定並陸陸續續的到達串列埠緩衝區,那麼就成功進行了一次串列埠傳輸和讀取;如果20秒總計時時間到,串列埠還陸陸續續的有資料到達,即使遵守位元組間隔為1ms的約定,ReadFile()函式也會立即返回,這時候總超時就起作用了。
總結起來,總超時在兩種情況下起作用
第一:串列埠沒進行資料傳輸,等待總超時時間那麼長ReadFile()才返回。非正常資料傳輸
第二:資料太長,總超時設定太短,資料還沒讀取完就返回了。讀取的資料是不全的
間隔超時觸發是有條件的
第一:在總超時時間內。
第二:串列埠進行了資料的傳輸。
成功的進行一次串列埠資料的傳輸和讀取,只有總超時和間隔超時相互參與配合才能完成”

3、修改CMakeList檔案,新增選項

 
  1. add_executable(serial_port src/serial_port.cpp)

  2.  
  3. add_dependencies(serial_port ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

  4.  
  5. target_link_libraries(serial_port

  6. ${catkin_LIBRARIES}

  7. )

4、編譯,執行即可看到結果(記得執行roscore和在工程目錄下source devel/setup.bash)

相關文章