精品视频日韩无码,伊人久久无码av一区二区三区,久久艹视频国产视频,欧美成A人免费观看久久

  1. <tt id="u23fe"><i id="u23fe"><sub id="u23fe"></sub></i></tt>

      <b id="u23fe"><address id="u23fe"><kbd id="u23fe"></kbd></address></b>

      <source id="u23fe"><track id="u23fe"></track></source>
    1. 位置: IT常識 - 正文

      最全ROS 入門(ros入門21講)

      編輯:rootadmin
      最全ROS 入門

      目錄

      簡介

      ROS誕生背景

      ROS的設(shè)計目標(biāo)

      ROS與ROS2

      安裝ROS

      1.配置ubuntu的軟件和更新

      2.設(shè)置安裝源

      3.設(shè)置key

      4.安裝

      5.配置環(huán)境變量

      安裝可能出現(xiàn)的問題

      安裝構(gòu)建依賴

      卸載

      ROS架構(gòu)

      1.設(shè)計者

      2.維護(hù)者

      3. 立足系統(tǒng)架構(gòu): ROS 可以劃分為三層

      ROS通信機(jī)制

      話題通信

      理論模型

      流程

      通信樣例

      自定義消息的通信

      服務(wù)通信

      理論模型

      服務(wù)通信自定義srv

      參數(shù)服務(wù)器

      理論模型

      參數(shù)操作

      常用命令

      簡介

      rosnode

      rostopic

      rosmsg

      rosservice

      rossrv

      rosparam

      常用API

      初始化

      話題與服務(wù)相關(guān)對象

      C++

      回旋函數(shù)

      C++

      對比

      時間

      1.時刻

      2.持續(xù)時間

      3.持續(xù)時間與時刻運(yùn)算

      4.設(shè)置運(yùn)行頻率(非常常用)

      5.定時器

      其他

      ROS 的運(yùn)行管理

      ROS元功能包

      概念

      作用

      實現(xiàn)

      ROS節(jié)點運(yùn)行管理launch文件

      概念

      作用

      使用

      launch文件 結(jié)構(gòu)

      ROS工作空間覆蓋

      實現(xiàn)

      原因

      結(jié)論

      隱患

      ROS節(jié)點名稱重名

      rosrun設(shè)置命名空間與重映射

      launch文件設(shè)置命名空間與重映射

      編碼設(shè)置命名空間與重映射

      ROS話題名稱重復(fù)

      概念

      rosrun設(shè)置話題重映射

      launch文件設(shè)置話題重映射

      編碼設(shè)置話題名稱

      ROS參數(shù)名稱重復(fù)

      概念

      rosrun設(shè)置參數(shù)

      launch文件設(shè)置參數(shù)

      編碼設(shè)置參數(shù)

      ROS分布式通信

      實現(xiàn)

      ROS 常用組件

      TF坐標(biāo)變換

      rosbag

      概念

      作用

      本質(zhì)

      rosbag使用_命令行

      rosbag使用_編碼

      ROS進(jìn)階通信

      action通信

      概念

      作用

      action通信自定義action文件

      動態(tài)參數(shù)

      概念

      作用

      動態(tài)參數(shù)客戶端

      動態(tài)參數(shù)服務(wù)端A(C++)

      pluginlib

      概念

      作用

      實現(xiàn)流程:

      創(chuàng)建基類

      創(chuàng)建插件

      注冊插件

      構(gòu)建插件庫

      使插件可用于ROS工具鏈

      Nodelet

      概念

      作用

      流程說明

      準(zhǔn)備

      創(chuàng)建插件類并注冊插件

      構(gòu)建插件庫

      使插件可用于ROS工具鏈


      簡介ROS誕生背景

      機(jī)器人是一種高度復(fù)雜的系統(tǒng)性實現(xiàn),機(jī)器人設(shè)計包含了機(jī)械加工、機(jī)械結(jié)構(gòu)設(shè)計、硬件設(shè)計、嵌入式軟件設(shè)計、上層軟件設(shè)計....是各種硬件與軟件集成,甚至可以說機(jī)器人系統(tǒng)是當(dāng)今工業(yè)體系的集大成者。

      機(jī)器人體系是相當(dāng)龐大的,其復(fù)雜度之高,以至于沒有任何個人、組織甚至公司能夠獨立完成系統(tǒng)性的機(jī)器人研發(fā)工作。

      一種更合適的策略是:讓機(jī)器人研發(fā)者專注于自己擅長的領(lǐng)域,其他模塊則直接復(fù)用相關(guān)領(lǐng)域更專業(yè)研發(fā)團(tuán)隊的實現(xiàn),當(dāng)然自身的研究也可以被他人繼續(xù)復(fù)用。這種基于"復(fù)用"的分工協(xié)作,遵循了不重復(fù)發(fā)明輪子的原則,顯然是可以大大提高機(jī)器人的研發(fā)效率的,尤其是隨著機(jī)器人硬件越來越豐富,軟件庫越來越龐大,這種復(fù)用性和模塊化開發(fā)需求也愈發(fā)強(qiáng)烈。

      ROS的設(shè)計目標(biāo)代碼復(fù)用:ROS的目標(biāo)不是成為具有最多功能的框架,ROS的主要目標(biāo)是支持機(jī)器人技術(shù)研發(fā)中的代碼重用。分布式:ROS是進(jìn)程(也稱為Nodes)的分布式框架,ROS中的進(jìn)程可分布于不同主機(jī),不同主機(jī)協(xié)同工作,從而分散計算壓力松耦合:ROS中功能模塊封裝于獨立的功能包或元功能包,便于分享,功能包內(nèi)的模塊以節(jié)點為單位運(yùn)行,以ROS標(biāo)準(zhǔn)的IO作為接口,開發(fā)者不需要關(guān)注模塊內(nèi)部實現(xiàn),只要了解接口規(guī)則就能實現(xiàn)復(fù)用,實現(xiàn)了模塊間點對點的松耦合連接精簡:ROS被設(shè)計為盡可能精簡,以便為ROS編寫的代碼可以與其他機(jī)器人軟件框架一起使用。ROS易于與其他機(jī)器人軟件框架集成:ROS已與OpenRAVE,Orocos和Player集成。語言獨立性:包括Java,C++,Python等。為了支持更多應(yīng)用開發(fā)和移植,ROS設(shè)計為一種語言弱相關(guān)的框架結(jié)構(gòu),使用簡潔,中立的定義語言描述模塊間的消息接口,在編譯中再產(chǎn)生所使用語言的目標(biāo)文件,為消息交互提供支持,同時允許消息接口的嵌套使用易于測試:ROS具有稱為rostest的內(nèi)置單元/集成測試框架,可輕松安裝和拆卸測試工具。大型應(yīng)用:ROS適用于大型運(yùn)行時系統(tǒng)和大型開發(fā)流程。豐富的組件化工具包:ROS可采用組件化方式集成一些工具和軟件到系統(tǒng)中并作為一個組件直接使用,如RVIZ(3D可視化工具),開發(fā)者根據(jù)ROS定義的接口在其中顯示機(jī)器人模型等,組件還包括仿真環(huán)境和消息查看工具等免費且開源:開發(fā)者眾多,功能包多ROS與ROS2

      ROS 目前已經(jīng)發(fā)布了ROS1 的終極版本: noetic,并建議后期過渡至 ROS2 版本。noetic 版本之前默認(rèn)使用的是 Python2,noetic 支持 Python3。

      ROS本身存在很多問題,比如:

      強(qiáng)依賴master節(jié)點,一旦master節(jié)點掛掉,通信就可能出現(xiàn)問題。通信基于TCP實現(xiàn),實時性差、系統(tǒng)開銷大消息機(jī)制不兼容,想要使用protobuf就需要改其中的源碼沒有加密機(jī)制、安全性不高

      而ROS2做了很多的改進(jìn):

      從原來的只支持linux平臺變成了支持windows、mac甚至是嵌入式RTOS平臺去中心化master,ROS和ROS2中間件不同之處在于,ROS2取消了master節(jié)點。去中心化后,各個節(jié)點之間可以通過DDS的節(jié)點相互發(fā)現(xiàn),各個節(jié)點都是平等的,且可以1對1、1對n、n對n進(jìn)行互相通信。通信直接更換為DDS進(jìn)行實現(xiàn),這里的DDS不是具體的哪一個模塊,而是一種協(xié)議。編譯系統(tǒng)的改進(jìn)(catkin到ament)軟件包更新到c++11可用Python編寫的Launch文件多機(jī)器人協(xié)同通信支持支持安全加密通信同一個進(jìn)程支持多個節(jié)點支持Qos服務(wù)質(zhì)量支持節(jié)點生命周期管理安裝ROS

      Ubuntu 安裝完畢后,就可以安裝 ROS 操作系統(tǒng)了,大致步驟如下:

      配置ubuntu的軟件和更新;設(shè)置安裝源;設(shè)置key;安裝;配置環(huán)境變量。
      1.配置ubuntu的軟件和更新

      配置ubuntu的軟件和更新,允許安裝不經(jīng)認(rèn)證的軟件。

      首先打開“軟件和更新”對話框,具體可以在 Ubuntu 搜索按鈕中搜索。

      打開后按照下圖進(jìn)行配置(確保勾選了"restricted", "universe," 和 "multiverse.")

      2.設(shè)置安裝源

      官方默認(rèn)安裝源:

      sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

      或來自國內(nèi)清華的安裝源

      sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'

      或來自國內(nèi)中科大的安裝源

      sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'

      PS:

      回車后,可能需要輸入管理員密碼建議使用國內(nèi)資源,安裝速度更快。3.設(shè)置key

      sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

      4.安裝

      首先需要更新 apt(以前是 apt-get, 官方建議使用 apt 而非 apt-get),apt 是用于從互聯(lián)網(wǎng)倉庫搜索、安裝、升級、卸載軟件或操作系統(tǒng)的工具。

      sudo apt update

      等待...

      然后,再安裝所需類型的 ROS:ROS 多個類型:Desktop-Full、Desktop、ROS-Base。這里介紹較為常用的Desktop-Full(官方推薦)安裝: ROS, rqt, rviz, robot-generic libraries, 2D/3D simulators, navigation and 2D/3D perception

      sudo apt install ros-noetic-desktop-full

      等待......(比較耗時)

      友情提示: 由于網(wǎng)絡(luò)原因,導(dǎo)致連接超時,可能會安裝失敗,如下所示:

      可以多次重復(fù)調(diào)用 更新 和 安裝命令,直至成功。

      5.配置環(huán)境變量

      配置環(huán)境變量,方便在任意 終端中使用 ROS。

      echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc source ~/.bashrc

      安裝可能出現(xiàn)的問題安裝構(gòu)建依賴

      在 noetic 最初發(fā)布時,和其他歷史版本稍有差異的是:沒有安裝構(gòu)建依賴這一步驟。隨著 noetic 不斷完善,官方補(bǔ)齊了這一操作。

      首先安裝構(gòu)建依賴的相關(guān)工具

      sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential

      ROS中使用許多工具前,要求需要初始化rosdep(可以安裝系統(tǒng)依賴) -- 上一步實現(xiàn)已經(jīng)安裝過了。

      sudo apt install python3-rosdep

      初始化rosdep

      sudo rosdep init rosdep update

      如果一切順利的話,rosdep 初始化與更新的打印結(jié)果如下:


      但是,在 rosdep 初始化時,多半會拋出異常。

      問題:

      原因:

      境外資源被屏蔽。

      解決:

      百度或google搜索,解決方式有多種(https://github.com/ros/rosdistro/issues/9721),可惜在 ubuntu20.04 下,集體失效。

      新思路:將相關(guān)資源備份到 gitee,修改 rosdep 源碼,重新定位資源。

      實現(xiàn):

      1.先打開資源備份路徑:趙虛左/rosdistro,打開 rosdistro/rosdep/sources.list.d/20-default.list文件留作備用(主要是復(fù)用URL的部分內(nèi)容:gitee.com/zhao-xuzuo/rosdistro/raw/master)。

      2.進(jìn)入"/usr/lib/python3/dist-packages/" 查找rosdep中和raw.githubusercontent.com相關(guān)的內(nèi)容,調(diào)用命令:

      find . -type f | xargs grep "raw.githubusercontent"

      3.修改相關(guān)文件,主要有: ./rosdistro/__init__.py、./rosdep2/gbpdistro_support.py、./rosdep2/sources_list.py 、./rosdep2/rep3.py??梢允褂胹udo gedit命令修改文件:

      文件中涉及的 URL 內(nèi)容,如果是:raw.githubusercontent.com/ros/rosdistro/master都替換成步驟1中準(zhǔn)備的gitee.com/zhao-xuzuo/rosdistro/raw/master即可。

      修改完畢,再重新執(zhí)行命令:

      sudo rosdep init rosdep update

      就可以正常實現(xiàn) rosdep 的初始化與更新了。


      卸載

      如果需要卸載ROS可以調(diào)用如下命令:

      sudo apt remove ros-noetic-*

      注意: 在 ROS 版本 noetic 中無需構(gòu)建軟件包的依賴關(guān)系,沒有rosdep的相關(guān)安裝與配置。


      另請參考:noetic/Installation/Ubuntu - ROS Wiki。

      ROS架構(gòu)

      一般我們可以從設(shè)計者、維護(hù)者、系統(tǒng)結(jié)構(gòu)與自身結(jié)構(gòu)4個角度來描述ROS結(jié)構(gòu):

      1.設(shè)計者

      ROS設(shè)計者將ROS表述為“ROS = Plumbing + Tools + Capabilities + Ecosystem”

      Plumbing: 通訊機(jī)制(實現(xiàn)ROS不同節(jié)點之間的交互)Tools :工具軟件包(ROS中的開發(fā)和調(diào)試工具)Capabilities :機(jī)器人高層技能(ROS中某些功能的集合,比如:導(dǎo)航)Ecosystem:機(jī)器人生態(tài)系統(tǒng)(跨地域、跨軟件與硬件的ROS聯(lián)盟)2.維護(hù)者

      立足維護(hù)者的角度: ROS 架構(gòu)可劃分為兩大部分

      main:核心部分,主要由Willow Garage 和一些開發(fā)者設(shè)計、提供以及維護(hù)。它提供了一些分布式計算的基本工具,以及整個ROS的核心部分的程序編寫。universe:全球范圍的代碼,有不同國家的ROS社區(qū)組織開發(fā)和維護(hù)。一種是庫的代碼,如OpenCV、PCL等;庫的上一層是從功能角度提供的代碼,如人臉識別,他們調(diào)用下層的庫;最上層的代碼是應(yīng)用級的代碼,讓機(jī)器人完成某一確定的功能。3. 立足系統(tǒng)架構(gòu): ROS 可以劃分為三層OS 層,也即經(jīng)典意義的操作系統(tǒng)ROS 只是元操作系統(tǒng),需要依托真正意義的操作系統(tǒng),目前兼容性最好的是 Linux 的 Ubuntu,Mac、Windows 也支持 ROS 的較新版本中間層是 ROS 封裝的關(guān)于機(jī)器人開發(fā)的中間件,比如:基于 TCP/UDP 繼續(xù)封裝的 TCPROS/UDPROS 通信系統(tǒng)用于進(jìn)程間通信 Nodelet,為數(shù)據(jù)的實時性傳輸提供支持另外,還提供了大量的機(jī)器人開發(fā)實現(xiàn)庫,如:數(shù)據(jù)類型定義、坐標(biāo)變換、運(yùn)動控制....應(yīng)用層功能包,以及功能包內(nèi)的節(jié)點,比如: master、turtlesim的控制與運(yùn)動節(jié)點...ROS通信機(jī)制話題通信

      話題通信是ROS中使用頻率最高的一種通信模式,話題通信是基于發(fā)布訂閱模式的,也即:一個節(jié)點發(fā)布消息,另一個節(jié)點訂閱該消息。話題通信的應(yīng)用場景也極其廣泛。

      用于不斷更新的、少邏輯處理的數(shù)據(jù)傳輸場景。

      理論模型

      話題通信實現(xiàn)模型是比較復(fù)雜的,該模型如下圖所示,該模型中涉及到三個角色:

      ROS Master (管理者)Talker (發(fā)布者)Listener (訂閱者)

      ROS Master 負(fù)責(zé)保管 Talker 和 Listener 注冊的信息,并匹配話題相同的 Talker 與 Listener,幫助 Talker 與 Listener 建立連接,連接建立后,Talker 可以發(fā)布消息,且發(fā)布的消息會被 Listener 訂閱。

      流程

      推薦整理分享最全ROS 入門(ros入門21講),希望有所幫助,僅作參考,歡迎閱讀內(nèi)容。

      文章相關(guān)熱門搜索詞:ros快速入門,ros教程推薦,ros快速入門,ros入門中文官方教程,ros教程推薦,ros教程推薦,ros入門21講,ros入門教程,內(nèi)容如對您有幫助,希望把文章鏈接給更多的朋友!

      0.Talker注冊

      Talker啟動后,會通過RPC在 ROS Master 中注冊自身信息,其中包含所發(fā)布消息的話題名稱。ROS Master 會將節(jié)點的注冊信息加入到注冊表中。

      1.Listener注冊

      Listener啟動后,也會通過RPC在 ROS Master 中注冊自身信息,包含需要訂閱消息的話題名。ROS Master 會將節(jié)點的注冊信息加入到注冊表中。

      2.ROS Master實現(xiàn)信息匹配

      ROS Master 會根據(jù)注冊表中的信息匹配Talker 和 Listener,并通過 RPC 向 Listener 發(fā)送 Talker 的 RPC 地址信息。

      3.Listener向Talker發(fā)送請求

      Listener 根據(jù)接收到的 RPC 地址,通過 RPC 向 Talker 發(fā)送連接請求,傳輸訂閱的話題名稱、消息類型以及通信協(xié)議(TCP/UDP)。

      4.Talker確認(rèn)請求

      Talker 接收到 Listener 的請求后,也是通過 RPC 向 Listener 確認(rèn)連接信息,并發(fā)送自身的 TCP 地址信息。

      5.Listener與Talker件里連接

      Listener 根據(jù)步驟4 返回的消息使用 TCP 與 Talker 建立網(wǎng)絡(luò)連接。

      6.Talker向Listener發(fā)送消息

      連接建立后,Talker 開始向 Listener 發(fā)布消息。

      注意1:上述實現(xiàn)流程中,前五步使用的 RPC協(xié)議,最后兩步使用的是 TCP 協(xié)議

      注意2: Talker 與 Listener 的啟動無先后順序要求

      注意3: Talker 與 Listener 都可以有多個

      注意4: Talker 與 Listener 連接建立后,不再需要 ROS Master。也即,即便關(guān)閉ROS Master,Talker 與 Listern 照常通信。

      通信樣例

      發(fā)布方

      /*需求: 實現(xiàn)基本的話題通信,一方發(fā)布數(shù)據(jù),一方接收數(shù)據(jù),實現(xiàn)的關(guān)鍵點:1.發(fā)送方2.接收方3.數(shù)據(jù)(此處為普通文本)PS: 二者需要設(shè)置相同的話題消息發(fā)布方:循環(huán)發(fā)布信息:HelloWorld 后綴數(shù)字編號實現(xiàn)流程:1.包含頭文件2.初始化 ROS 節(jié)點:命名(唯一)3.實例化 ROS 句柄4.實例化 發(fā)布者 對象5.組織被發(fā)布的數(shù)據(jù),并編寫邏輯發(fā)布數(shù)據(jù)*/// 1.包含頭文件#include "ros/ros.h"#include "std_msgs/String.h" //普通文本類型的消息#include <sstream>int main(int argc, char *argv[]){//設(shè)置編碼setlocale(LC_ALL,"");//2.初始化 ROS 節(jié)點:命名(唯一)// 參數(shù)1和參數(shù)2 后期為節(jié)點傳值會使用// 參數(shù)3 是節(jié)點名稱,是一個標(biāo)識符,需要保證運(yùn)行后,在 ROS 網(wǎng)絡(luò)拓?fù)渲形ㄒ籸os::init(argc,argv,"talker");//3.實例化 ROS 句柄ros::NodeHandle nh;//該類封裝了 ROS 中的一些常用功能//4.實例化 發(fā)布者 對象//泛型: 發(fā)布的消息類型//參數(shù)1: 要發(fā)布到的話題//參數(shù)2: 隊列中最大保存的消息數(shù),超出此閥值時,先進(jìn)的先銷毀(時間早的先銷毀)ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);//5.組織被發(fā)布的數(shù)據(jù),并編寫邏輯發(fā)布數(shù)據(jù)//數(shù)據(jù)(動態(tài)組織)std_msgs::String msg;// msg.data = "你好啊!!!";std::string msg_front = "Hello 你好!"; //消息前綴int count = 0; //消息計數(shù)器//邏輯(一秒10次)ros::Rate r(1);//節(jié)點不死while (ros::ok()){//使用 stringstream 拼接字符串與編號std::stringstream ss;ss << msg_front << count;msg.data = ss.str();//發(fā)布消息pub.publish(msg);//加入調(diào)試,打印發(fā)送的消息ROS_INFO("發(fā)送的消息:%s",msg.data.c_str());//根據(jù)前面制定的發(fā)送貧頻率自動休眠 休眠時間 = 1/頻率;r.sleep();count++;//循環(huán)結(jié)束前,讓 count 自增//暫無應(yīng)用ros::spinOnce();}return 0;}

      訂閱方

      /*需求: 實現(xiàn)基本的話題通信,一方發(fā)布數(shù)據(jù),一方接收數(shù)據(jù),實現(xiàn)的關(guān)鍵點:1.發(fā)送方2.接收方3.數(shù)據(jù)(此處為普通文本)消息訂閱方:訂閱話題并打印接收到的消息實現(xiàn)流程:1.包含頭文件2.初始化 ROS 節(jié)點:命名(唯一)3.實例化 ROS 句柄4.實例化 訂閱者 對象5.處理訂閱的消息(回調(diào)函數(shù))6.設(shè)置循環(huán)調(diào)用回調(diào)函數(shù)*/// 1.包含頭文件#include "ros/ros.h"#include "std_msgs/String.h"void doMsg(const std_msgs::String::ConstPtr& msg_p){ROS_INFO("我聽見:%s",msg_p->data.c_str());// ROS_INFO("我聽見:%s",(*msg_p).data.c_str());}int main(int argc, char *argv[]){setlocale(LC_ALL,"");//2.初始化 ROS 節(jié)點:命名(唯一)ros::init(argc,argv,"listener");//3.實例化 ROS 句柄ros::NodeHandle nh;//4.實例化 訂閱者 對象ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);//5.處理訂閱的消息(回調(diào)函數(shù))// 6.設(shè)置循環(huán)調(diào)用回調(diào)函數(shù)ros::spin();//循環(huán)讀取接收的數(shù)據(jù),并調(diào)用回調(diào)函數(shù)處理return 0;}

      CmakeList

      add_executable(Hello_pubsrc/Hello_pub.cpp)add_executable(Hello_subsrc/Hello_sub.cpp)target_link_libraries(Hello_pub${catkin_LIBRARIES})target_link_libraries(Hello_sub${catkin_LIBRARIES})

      執(zhí)行過程

      1.啟動 roscore;

      2.啟動發(fā)布節(jié)點;

      3.啟動訂閱節(jié)點。

      自定義消息的通信

      簡介

      在 ROS 通信協(xié)議中,數(shù)據(jù)載體是一個較為重要組成部分,ROS 中通過 std_msgs 封裝了一些原生的數(shù)據(jù)類型,比如:String、Int32、Int64、Char、Bool、Empty.... 但是,這些數(shù)據(jù)一般只包含一個 data 字段,結(jié)構(gòu)的單一意味著功能上的局限性,當(dāng)傳輸一些復(fù)雜的數(shù)據(jù),比如: 激光雷達(dá)的信息... std_msgs 由于描述性較差而顯得力不從心,這種場景下可以使用自定義的消息類型

      msgs只是簡單的文本文件,每行具有字段類型和字段名稱,可以使用的字段類型有:

      int8, int16, int32, int64 (或者無符號類型: uint*)float32, float64stringtime, durationother msg filesvariable-length array[] and fixed-length array[C]

      ROS中還有一種特殊類型:Header,標(biāo)頭包含時間戳和ROS中常用的坐標(biāo)幀信息。會經(jīng)??吹絤sg文件的第一行具有Header標(biāo)頭。

      1.定義msg文件

      string nameuint16 agefloat64 height

      2.編輯配置文件

      <build_depend>message_generation</build_depend><exec_depend>message_runtime</exec_depend><!--exce_depend 以前對應(yīng)的是 run_depend 現(xiàn)在非法-->find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generation)# 需要加入 message_generation,必須有 std_msgs## 配置 msg 源文件add_message_files(FILESPerson.msg)# 生成消息時依賴于 std_msgsgenerate_messages(DEPENDENCIESstd_msgs)#執(zhí)行時依賴catkin_package(# INCLUDE_DIRS include# LIBRARIES demo02_talker_listenerCATKIN_DEPENDS roscpp rospy std_msgs message_runtime# DEPENDS system_lib)

      發(fā)布方

      /*需求: 循環(huán)發(fā)布人的信息*/#include "ros/ros.h"#include "demo02_talker_listener/Person.h"int main(int argc, char *argv[]){setlocale(LC_ALL,"");//1.初始化 ROS 節(jié)點ros::init(argc,argv,"talker_person");//2.創(chuàng)建 ROS 句柄ros::NodeHandle nh;//3.創(chuàng)建發(fā)布者對象ros::Publisher pub = nh.advertise<demo02_talker_listener::Person>("chatter_person",1000);//4.組織被發(fā)布的消息,編寫發(fā)布邏輯并發(fā)布消息demo02_talker_listener::Person p;p.name = "sunwukong";p.age = 2000;p.height = 1.45;ros::Rate r(1);while (ros::ok()){pub.publish(p);p.age += 1;ROS_INFO("我叫:%s,今年%d歲,高%.2f米", p.name.c_str(), p.age, p.height);r.sleep();ros::spinOnce();}return 0;}

      訂閱方

      /*需求: 訂閱人的信息*/#include "ros/ros.h"#include "demo02_talker_listener/Person.h"void doPerson(const demo02_talker_listener::Person::ConstPtr& person_p){ROS_INFO("訂閱的人信息:%s, %d, %.2f", person_p->name.c_str(), person_p->age, person_p->height);}int main(int argc, char *argv[]){setlocale(LC_ALL,"");//1.初始化 ROS 節(jié)點ros::init(argc,argv,"listener_person");//2.創(chuàng)建 ROS 句柄ros::NodeHandle nh;//3.創(chuàng)建訂閱對象ros::Subscriber sub = nh.subscribe<demo02_talker_listener::Person>("chatter_person",10,doPerson);//4.回調(diào)函數(shù)中處理 person//5.ros::spin();ros::spin();return 0;}

      Cmakelist

      add_executable(person_talker src/person_talker.cpp)add_executable(person_listener src/person_listener.cpp)add_dependencies(person_talker ${PROJECT_NAME}_generate_messages_cpp)add_dependencies(person_listener ${PROJECT_NAME}_generate_messages_cpp)target_link_libraries(person_talker${catkin_LIBRARIES})target_link_libraries(person_listener${catkin_LIBRARIES})

      Vscode配置

      為了方便代碼提示以及避免誤拋異常,需要先配置 vscode,將前面生成的 head 文件路徑配置進(jìn) c_cpp_properties.json 的 includepath屬性:

      {"configurations": [{"browse": {"databaseFilename": "","limitSymbolsToIncludedHeaders": true},"includePath": ["/opt/ros/noetic/include/**","/usr/include/**","/xxx/yyy工作空間/devel/include/**" //配置 head 文件的路徑],"name": "ROS","intelliSenseMode": "gcc-x64","compilerPath": "/usr/bin/gcc","cStandard": "c11","cppStandard": "c++17"}],"version": 4}服務(wù)通信

      服務(wù)通信也是ROS中一種極其常用的通信模式,服務(wù)通信是基于請求響應(yīng)模式的,是一種應(yīng)答機(jī)制。也即: 一個節(jié)點A向另一個節(jié)點B發(fā)送請求,B接收處理請求并產(chǎn)生響應(yīng)結(jié)果返回給A。比如如下場景:

      機(jī)器人巡邏過程中,控制系統(tǒng)分析傳感器數(shù)據(jù)發(fā)現(xiàn)可疑物體或人... 此時需要拍攝照片并留存。

      在上述場景中,就使用到了服務(wù)通信。

      一個節(jié)點需要向相機(jī)節(jié)點發(fā)送拍照請求,相機(jī)節(jié)點處理請求,并返回處理結(jié)果

      與上述應(yīng)用類似的,服務(wù)通信更適用于對時時性有要求、具有一定邏輯處理的應(yīng)用場景。

      理論模型

      服務(wù)通信較之于話題通信更簡單些,理論模型如下圖所示,該模型中涉及到三個角色:

      ROS master(管理者)Server(服務(wù)端)Client(客戶端)

      ROS Master 負(fù)責(zé)保管 Server 和 Client 注冊的信息,并匹配話題相同的 Server 與 Client ,幫助 Server 與 Client 建立連接,連接建立后,Client 發(fā)送請求信息,Server 返回響應(yīng)信息。

      整個流程由以下步驟實現(xiàn):

      0.Server注冊

      Server 啟動后,會通過RPC在 ROS Master 中注冊自身信息,其中包含提供的服務(wù)的名稱。ROS Master 會將節(jié)點的注冊信息加入到注冊表中。

      1.Client注冊

      Client 啟動后,也會通過RPC在 ROS Master 中注冊自身信息,包含需要請求的服務(wù)的名稱。ROS Master 會將節(jié)點的注冊信息加入到注冊表中。

      2.ROS Master實現(xiàn)信息匹配

      ROS Master 會根據(jù)注冊表中的信息匹配Server和 Client,并通過 RPC 向 Client 發(fā)送 Server 的 TCP地址信息。

      最全ROS 入門(ros入門21講)

      3.Client發(fā)送請求

      Client 根據(jù)步驟2 響應(yīng)的信息,使用 TCP 與 Server 建立網(wǎng)絡(luò)連接,并發(fā)送請求數(shù)據(jù)。

      4.Server發(fā)送響應(yīng)

      Server 接收、解析請求的數(shù)據(jù),并產(chǎn)生響應(yīng)結(jié)果返回給 Client。

      注意:

      1.客戶端請求被處理時,需要保證服務(wù)器已經(jīng)啟動;

      2.服務(wù)端和客戶端都可以存在多個。

      服務(wù)通信自定義srv

      流程:

      srv 文件內(nèi)的可用數(shù)據(jù)類型與 msg 文件一致,且定義 srv 實現(xiàn)流程與自定義 msg 實現(xiàn)流程類似:

      按照固定格式創(chuàng)建srv文件編輯配置文件編譯生成中間文件

      1.定義srv文件

      服務(wù)通信中,數(shù)據(jù)分成兩部分,請求與響應(yīng),在 srv 文件中請求和響應(yīng)使用---分割,具體實現(xiàn)如下:

      功能包下新建 srv 目錄,添加 xxx.srv 文件,內(nèi)容:

      # 客戶端請求時發(fā)送的兩個數(shù)字int32 num1int32 num2---# 服務(wù)器響應(yīng)發(fā)送的數(shù)據(jù)int32 sum

      2.編輯配置文件

      package.xml中添加編譯依賴與執(zhí)行依賴

      <build_depend>message_generation</build_depend><exec_depend>message_runtime</exec_depend><!-- exce_depend 以前對應(yīng)的是 run_depend 現(xiàn)在非法 -->

      CMakeLists.txt編輯 srv 相關(guān)配置

      find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generation)# 需要加入 message_generation,必須有 std_msgsadd_service_files(FILESAddInts.srv)generate_messages(DEPENDENCIESstd_msgs)

      3.編譯

      編譯后的中間文件查看:

      C++ 需要調(diào)用的中間文件(.../工作空間/devel/include/包名/xxx.h)

      Python 需要調(diào)用的中間文件(.../工作空間/devel/lib/python3/dist-packages/包名/srv)

      后續(xù)調(diào)用相關(guān) srv 時,是從這些中間文件調(diào)用的

      4. 服務(wù)端

      /*需求:編寫兩個節(jié)點實現(xiàn)服務(wù)通信,客戶端節(jié)點需要提交兩個整數(shù)到服務(wù)器服務(wù)器需要解析客戶端提交的數(shù)據(jù),相加后,將結(jié)果響應(yīng)回客戶端,客戶端再解析服務(wù)器實現(xiàn):1.包含頭文件2.初始化 ROS 節(jié)點3.創(chuàng)建 ROS 句柄4.創(chuàng)建 服務(wù) 對象5.回調(diào)函數(shù)處理請求并產(chǎn)生響應(yīng)6.由于請求有多個,需要調(diào)用 ros::spin()*/#include "ros/ros.h"#include "demo03_server_client/AddInts.h"// bool 返回值由于標(biāo)志是否處理成功bool doReq(demo03_server_client::AddInts::Request& req,demo03_server_client::AddInts::Response& resp){int num1 = req.num1;int num2 = req.num2;ROS_INFO("服務(wù)器接收到的請求數(shù)據(jù)為:num1 = %d, num2 = %d",num1, num2);//邏輯處理if (num1 < 0 || num2 < 0){ROS_ERROR("提交的數(shù)據(jù)異常:數(shù)據(jù)不可以為負(fù)數(shù)");return false;}//如果沒有異常,那么相加并將結(jié)果賦值給 respresp.sum = num1 + num2;return true;}int main(int argc, char *argv[]){setlocale(LC_ALL,"");// 2.初始化 ROS 節(jié)點ros::init(argc,argv,"AddInts_Server");// 3.創(chuàng)建 ROS 句柄ros::NodeHandle nh;// 4.創(chuàng)建 服務(wù) 對象ros::ServiceServer server = nh.advertiseService("AddInts",doReq);ROS_INFO("服務(wù)已經(jīng)啟動....");// 5.回調(diào)函數(shù)處理請求并產(chǎn)生響應(yīng)// 6.由于請求有多個,需要調(diào)用 ros::spin()ros::spin();return 0;}

      5. 客戶端

      /*需求:編寫兩個節(jié)點實現(xiàn)服務(wù)通信,客戶端節(jié)點需要提交兩個整數(shù)到服務(wù)器服務(wù)器需要解析客戶端提交的數(shù)據(jù),相加后,將結(jié)果響應(yīng)回客戶端,客戶端再解析服務(wù)器實現(xiàn):1.包含頭文件2.初始化 ROS 節(jié)點3.創(chuàng)建 ROS 句柄4.創(chuàng)建 客戶端 對象5.請求服務(wù),接收響應(yīng)*/// 1.包含頭文件#include "ros/ros.h"#include "demo03_server_client/AddInts.h"int main(int argc, char *argv[]){setlocale(LC_ALL,"");// 調(diào)用時動態(tài)傳值,如果通過 launch 的 args 傳參,需要傳遞的參數(shù)個數(shù) +3if (argc != 3)// if (argc != 5)//launch 傳參(0-文件路徑 1傳入的參數(shù) 2傳入的參數(shù) 3節(jié)點名稱 4日志路徑){ROS_ERROR("請?zhí)峤粌蓚€整數(shù)");return 1;}// 2.初始化 ROS 節(jié)點ros::init(argc,argv,"AddInts_Client");// 3.創(chuàng)建 ROS 句柄ros::NodeHandle nh;// 4.創(chuàng)建 客戶端 對象ros::ServiceClient client = nh.serviceClient<demo03_server_client::AddInts>("AddInts");//等待服務(wù)啟動成功//方式1ros::service::waitForService("AddInts");//方式2// client.waitForExistence();// 5.組織請求數(shù)據(jù)demo03_server_client::AddInts ai;ai.request.num1 = atoi(argv[1]);ai.request.num2 = atoi(argv[2]);// 6.發(fā)送請求,返回 bool 值,標(biāo)記是否成功bool flag = client.call(ai);// 7.處理響應(yīng)if (flag){ROS_INFO("請求正常處理,響應(yīng)結(jié)果:%d",ai.response.sum);}else{ROS_ERROR("請求處理失敗....");return 1;}return 0;}

      6. CmakeList

      add_executable(AddInts_Server src/AddInts_Server.cpp)add_executable(AddInts_Client src/AddInts_Client.cpp)add_dependencies(AddInts_Server ${PROJECT_NAME}_gencpp)add_dependencies(AddInts_Client ${PROJECT_NAME}_gencpp)target_link_libraries(AddInts_Server${catkin_LIBRARIES})target_link_libraries(AddInts_Client${catkin_LIBRARIES})

      7. 注意(客戶端等待服務(wù)端連接)

      在客戶端發(fā)送請求前添加:client.waitForExistence();

      或:ros::service::waitForService("AddInts");

      這是一個阻塞式函數(shù),只有服務(wù)啟動成功后才會繼續(xù)執(zhí)行

      此處可以使用 launch 文件優(yōu)化,但是需要注意 args 傳參特點

      參數(shù)服務(wù)器

      簡單的說就是全局變量。

      參數(shù)服務(wù)器在ROS中主要用于實現(xiàn)不同節(jié)點之間的數(shù)據(jù)共享。參數(shù)服務(wù)器相當(dāng)于是獨立于所有節(jié)點的一個公共容器,可以將數(shù)據(jù)存儲在該容器中,被不同的節(jié)點調(diào)用,當(dāng)然不同的節(jié)點也可以往其中存儲數(shù)據(jù),關(guān)于參數(shù)服務(wù)器的典型應(yīng)用場景如下:

      導(dǎo)航實現(xiàn)時,會進(jìn)行路徑規(guī)劃,比如: 全局路徑規(guī)劃,設(shè)計一個從出發(fā)點到目標(biāo)點的大致路徑。本地路徑規(guī)劃,會根據(jù)當(dāng)前路況生成時時的行進(jìn)路徑

      上述場景中,全局路徑規(guī)劃和本地路徑規(guī)劃時,就會使用到參數(shù)服務(wù)器:

      路徑規(guī)劃時,需要參考小車的尺寸,我們可以將這些尺寸信息存儲到參數(shù)服務(wù)器,全局路徑規(guī)劃節(jié)點與本地路徑規(guī)劃節(jié)點都可以從參數(shù)服務(wù)器中調(diào)用這些參數(shù)

      參數(shù)服務(wù)器,一般適用于存在數(shù)據(jù)共享的一些應(yīng)用場景。

      理論模型

      參數(shù)服務(wù)器實現(xiàn)是最為簡單的,該模型如下圖所示,該模型中涉及到三個角色:

      ROS Master (管理者)Talker (參數(shù)設(shè)置者)Listener (參數(shù)調(diào)用者)

      ROS Master 作為一個公共容器保存參數(shù),Talker 可以向容器中設(shè)置參數(shù),Listener 可以獲取參數(shù)。

      整個流程由以下步驟實現(xiàn):

      1.Talker 設(shè)置參數(shù)

      Talker 通過 RPC 向參數(shù)服務(wù)器發(fā)送參數(shù)(包括參數(shù)名與參數(shù)值),ROS Master 將參數(shù)保存到參數(shù)列表中。

      2.Listener 獲取參數(shù)

      Listener 通過 RPC 向參數(shù)服務(wù)器發(fā)送參數(shù)查找請求,請求中包含要查找的參數(shù)名。

      3.ROS Master 向 Listener 發(fā)送參數(shù)值

      ROS Master 根據(jù)步驟2請求提供的參數(shù)名查找參數(shù)值,并將查詢結(jié)果通過 RPC 發(fā)送給 Listener。


      參數(shù)可使用數(shù)據(jù)類型:

      32-bit integersbooleansstringsdoublesiso8601 dateslistsbase64-encoded binary data字典參數(shù)操作

      設(shè)置

      在 C++ 中實現(xiàn)參數(shù)服務(wù)器數(shù)據(jù)的增刪改查,可以通過兩套 API 實現(xiàn):

      ros::NodeHandleros::param/*參數(shù)服務(wù)器操作之新增與修改(二者API一樣)_C++實現(xiàn):在 roscpp 中提供了兩套 API 實現(xiàn)參數(shù)操作ros::NodeHandlesetParam("鍵",值)ros::paramset("鍵","值")示例:分別設(shè)置整形、浮點、字符串、bool、列表、字典等類型參數(shù)修改(相同的鍵,不同的值)*/#include "ros/ros.h"int main(int argc, char *argv[]){ros::init(argc,argv,"set_update_param");std::vector<std::string> stus;stus.push_back("zhangsan");stus.push_back("李四");stus.push_back("王五");stus.push_back("孫大腦袋");std::map<std::string,std::string> friends;friends["guo"] = "huang";friends["yuang"] = "xiao";//NodeHandle--------------------------------------------------------ros::NodeHandle nh;nh.setParam("nh_int",10); //整型nh.setParam("nh_double",3.14); //浮點型nh.setParam("nh_bool",true); //boolnh.setParam("nh_string","hello NodeHandle"); //字符串nh.setParam("nh_vector",stus); // vectornh.setParam("nh_map",friends); // map//修改演示(相同的鍵,不同的值)nh.setParam("nh_int",10000);//param--------------------------------------------------------ros::param::set("param_int",20);ros::param::set("param_double",3.14);ros::param::set("param_string","Hello Param");ros::param::set("param_bool",false);ros::param::set("param_vector",stus);ros::param::set("param_map",friends);//修改演示(相同的鍵,不同的值)ros::param::set("param_int",20000);return 0;}

      獲取

      在 roscpp 中提供了兩套 API 實現(xiàn)參數(shù)操作

      ros::NodeHandle

      param(鍵,默認(rèn)值)

      存在,返回對應(yīng)結(jié)果,否則返回默認(rèn)值

      getParam(鍵,存儲結(jié)果的變量)

      存在,返回 true,且將值賦值給參數(shù)2

      若果鍵不存在,那么返回值為 false,且不為參數(shù)2賦值

      getParamCached鍵,存儲結(jié)果的變量)--提高變量獲取效率

      存在,返回 true,且將值賦值給參數(shù)2

      若果鍵不存在,那么返回值為 false,且不為參數(shù)2賦值

      getParamNames(std::vector<std::string>)

      獲取所有的鍵,并存儲在參數(shù) vector 中

      hasParam(鍵)

      是否包含某個鍵,存在返回 true,否則返回 false

      searchParam(參數(shù)1,參數(shù)2)

      搜索鍵,參數(shù)1是被搜索的鍵,參數(shù)2存儲搜索結(jié)果的變量

      ros::param ----- 與 NodeHandle 類似

      #include "ros/ros.h"int main(int argc, char *argv[]){setlocale(LC_ALL,"");ros::init(argc,argv,"get_param");//NodeHandle--------------------------------------------------------/*ros::NodeHandle nh;// param 函數(shù)int res1 = nh.param("nh_int",100); // 鍵存在int res2 = nh.param("nh_int2",100); // 鍵不存在ROS_INFO("param獲取結(jié)果:%d,%d",res1,res2);// getParam 函數(shù)int nh_int_value;double nh_double_value;bool nh_bool_value;std::string nh_string_value;std::vector<std::string> stus;std::map<std::string, std::string> friends;nh.getParam("nh_int",nh_int_value);nh.getParam("nh_double",nh_double_value);nh.getParam("nh_bool",nh_bool_value);nh.getParam("nh_string",nh_string_value);nh.getParam("nh_vector",stus);nh.getParam("nh_map",friends);ROS_INFO("getParam獲取的結(jié)果:%d,%.2f,%s,%d",nh_int_value,nh_double_value,nh_string_value.c_str(),nh_bool_value);for (auto &&stu : stus){ROS_INFO("stus 元素:%s",stu.c_str());}for (auto &&f : friends){ROS_INFO("map 元素:%s = %s",f.first.c_str(), f.second.c_str());}// getParamCached()nh.getParamCached("nh_int",nh_int_value);ROS_INFO("通過緩存獲取數(shù)據(jù):%d",nh_int_value);//getParamNames()std::vector<std::string> param_names1;nh.getParamNames(param_names1);for (auto &&name : param_names1){ROS_INFO("名稱解析name = %s",name.c_str());}ROS_INFO("----------------------------");ROS_INFO("存在 nh_int 嗎? %d",nh.hasParam("nh_int"));ROS_INFO("存在 nh_intttt 嗎? %d",nh.hasParam("nh_intttt"));std::string key;nh.searchParam("nh_int",key);ROS_INFO("搜索鍵:%s",key.c_str());*///param--------------------------------------------------------ROS_INFO("++++++++++++++++++++++++++++++++++++++++");int res3 = ros::param::param("param_int",20); //存在int res4 = ros::param::param("param_int2",20); // 不存在返回默認(rèn)ROS_INFO("param獲取結(jié)果:%d,%d",res3,res4);// getParam 函數(shù)int param_int_value;double param_double_value;bool param_bool_value;std::string param_string_value;std::vector<std::string> param_stus;std::map<std::string, std::string> param_friends;ros::param::get("param_int",param_int_value);ros::param::get("param_double",param_double_value);ros::param::get("param_bool",param_bool_value);ros::param::get("param_string",param_string_value);ros::param::get("param_vector",param_stus);ros::param::get("param_map",param_friends);ROS_INFO("getParam獲取的結(jié)果:%d,%.2f,%s,%d",param_int_value,param_double_value,param_string_value.c_str(),param_bool_value);for (auto &&stu : param_stus){ROS_INFO("stus 元素:%s",stu.c_str());}for (auto &&f : param_friends){ROS_INFO("map 元素:%s = %s",f.first.c_str(), f.second.c_str());}// getParamCached()ros::param::getCached("param_int",param_int_value);ROS_INFO("通過緩存獲取數(shù)據(jù):%d",param_int_value);//getParamNames()std::vector<std::string> param_names2;ros::param::getParamNames(param_names2);for (auto &&name : param_names2){ROS_INFO("名稱解析name = %s",name.c_str());}ROS_INFO("----------------------------");ROS_INFO("存在 param_int 嗎? %d",ros::param::has("param_int"));ROS_INFO("存在 param_intttt 嗎? %d",ros::param::has("param_intttt"));std::string key;ros::param::search("param_int",key);ROS_INFO("搜索鍵:%s",key.c_str());return 0;}

      刪除

      ros::NodeHandle

      deleteParam("鍵")

      根據(jù)鍵刪除參數(shù),刪除成功,返回 true,否則(參數(shù)不存在),返回 false

      ros::param

      del("鍵")

      根據(jù)鍵刪除參數(shù),刪除成功,返回 true,否則(參數(shù)不存在),返回 false

      #include "ros/ros.h"int main(int argc, char *argv[]){setlocale(LC_ALL,"");ros::init(argc,argv,"delete_param");ros::NodeHandle nh;bool r1 = nh.deleteParam("nh_int");ROS_INFO("nh 刪除結(jié)果:%d",r1);bool r2 = ros::param::del("param_int");ROS_INFO("param 刪除結(jié)果:%d",r2);return 0;}常用命令簡介

      在 ROS 同提供了一些實用的命令行工具,可以用于獲取不同節(jié)點的各類信息,常用的命令如下:

      rosnode : 操作節(jié)點rostopic : 操作話題rosservice : 操作服務(wù)rosmsg : 操作msg消息rossrv : 操作srv消息rosparam : 操作參數(shù)

      ROS/CommandLineTools - ROS Wiki

      rosnode

      rosnode 是用于獲取節(jié)點信息的命令

      rosnode ping 測試到節(jié)點的連接狀態(tài)rosnode list 列出活動節(jié)點rosnode info 打印節(jié)點信息rosnode machine 列出指定設(shè)備上節(jié)點rosnode kill 殺死某個節(jié)點rosnode cleanup 清除不可連接的節(jié)點rosnode ping測試到節(jié)點的連接狀態(tài)rosnode list列出活動節(jié)點rosnode info打印節(jié)點信息rosnode machine列出指定設(shè)備上的節(jié)點rosnode kill殺死某個節(jié)點rosnode cleanup清除無用節(jié)點,啟動烏龜節(jié)點,然后 ctrl + c 關(guān)閉,該節(jié)點并沒被徹底清除,可以使用 cleanup 清除節(jié)點rostopic

      rostopic包含rostopic命令行工具,用于顯示有關(guān)ROS 主題的調(diào)試信息,包括發(fā)布者,訂閱者,發(fā)布頻率和ROS消息。它還包含一個實驗性Python庫,用于動態(tài)獲取有關(guān)主題的信息并與之交互。

      rostopic bw 顯示主題使用的帶寬rostopic delay 顯示帶有 header 的主題延遲rostopic echo 打印消息到屏幕rostopic find 根據(jù)類型查找主題rostopic hz 顯示主題的發(fā)布頻率rostopic info 顯示主題相關(guān)信息rostopic list 顯示所有活動狀態(tài)下的主題rostopic pub 將數(shù)據(jù)發(fā)布到主題rostopic type 打印主題類型rosmsg

      rosmsg是用于顯示有關(guān) ROS消息類型的 信息的命令行工具。

      rosmsg show 顯示消息描述rosmsg info 顯示消息信息rosmsg list 列出所有消息rosmsg md5 顯示 md5 加密后的消息rosmsg package 顯示某個功能包下的所有消息rosmsg packages 列出包含消息的功能包rosservicerosservice args 打印服務(wù)參數(shù)rosservice call 使用提供的參數(shù)調(diào)用服務(wù)rosservice find 按照服務(wù)類型查找服務(wù)rosservice info 打印有關(guān)服務(wù)的信息rosservice list 列出所有活動的服務(wù)rosservice type 打印服務(wù)類型rosservice uri 打印服務(wù)的 ROSRPC urirossrv

      對標(biāo)rosmsg

      rossrv是用于顯示有關(guān)ROS服務(wù)類型的信息的命令行工具,與 rosmsg 使用語法高度雷同。

      rossrv show 顯示服務(wù)消息詳情rossrv info 顯示服務(wù)消息相關(guān)信息rossrv list 列出所有服務(wù)信息rossrv md5 顯示 md5 加密后的服務(wù)消息rossrv package 顯示某個包下所有服務(wù)消息rossrv packages 顯示包含服務(wù)消息的所有包rosparamrosparam set 設(shè)置參數(shù)rosparam get 獲取參數(shù)rosparam load 從外部文件加載參數(shù)rosparam dump 將參數(shù)寫出到外部文件rosparam delete 刪除參數(shù)rosparam list 列出所有參數(shù)常用API初始化/** @brief ROS初始化函數(shù)。** 該函數(shù)可以解析并使用節(jié)點啟動時傳入的參數(shù)(通過參數(shù)設(shè)置節(jié)點名稱、命名空間...)** 該函數(shù)有多個重載版本,如果使用NodeHandle建議調(diào)用該版本。** \param argc 參數(shù)個數(shù)* \param argv 參數(shù)列表* \param name 節(jié)點名稱,需要保證其唯一性,不允許包含命名空間* \param options 節(jié)點啟動選項,被封裝進(jìn)了ros::init_options**/void init(int &argc, char **argv, const std::string& name, uint32_t options = 0);def init_node(name, argv=None, anonymous=False, log_level=None, disable_rostime=False, disable_rosout=False, disable_signals=False, xmlrpc_port=0, tcpros_port=0):"""在ROS msater中注冊節(jié)點@param name: 節(jié)點名稱,必須保證節(jié)點名稱唯一,節(jié)點名稱中不能使用命名空間(不能包含 '/')@type name: str@param anonymous: 取值為 true 時,為節(jié)點名稱后綴隨機(jī)編號@type anonymous: bool"""話題與服務(wù)相關(guān)對象C++

      在 roscpp 中,話題和服務(wù)的相關(guān)對象一般由 NodeHandle 創(chuàng)建。

      1.發(fā)布對象

      /*** \brief 根據(jù)話題生成發(fā)布對象** 在 ROS master 注冊并返回一個發(fā)布者對象,該對象可以發(fā)布消息** 使用示例如下:** ros::Publisher pub = handle.advertise<std_msgs::Empty>("my_topic", 1);** \param topic 發(fā)布消息使用的話題** \param queue_size 等待發(fā)送給訂閱者的最大消息數(shù)量** \param latch (optional) 如果為 true,該話題發(fā)布的最后一條消息將被保存,并且后期當(dāng)有訂閱者連接時會將該消息發(fā)送給訂閱者** \return 調(diào)用成功時,會返回一個發(fā)布對象***/template <class M>Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false)

      2.訂閱對象

      /*** \brief 生成某個話題的訂閱對象** 該函數(shù)將根據(jù)給定的話題在ROS master 注冊,并自動連接相同主題的發(fā)布方,每接收到一條消息,都會調(diào)用回調(diào)* 函數(shù),并且傳入該消息的共享指針,該消息不能被修改,因為可能其他訂閱對象也會使用該消息。** 使用示例如下:void callback(const std_msgs::Empty::ConstPtr& message){}ros::Subscriber sub = handle.subscribe("my_topic", 1, callback);** \param M [template] M 是指消息類型* \param topic 訂閱的話題* \param queue_size 消息隊列長度,超出長度時,頭部的消息將被棄用* \param fp 當(dāng)訂閱到一條消息時,需要執(zhí)行的回調(diào)函數(shù)* \return 調(diào)用成功時,返回一個訂閱者對象,失敗時,返回空對象*void callback(const std_msgs::Empty::ConstPtr& message){...}ros::NodeHandle nodeHandle;ros::Subscriber sub = nodeHandle.subscribe("my_topic", 1, callback);if (sub) // Enter if subscriber is valid{...}*/template<class M>Subscriber subscribe(const std::string& topic, uint32_t queue_size, void(*fp)(const boost::shared_ptr<M const>&), const TransportHints& transport_hints = TransportHints())

      3.服務(wù)對象

      /*** \brief 生成服務(wù)端對象** 該函數(shù)可以連接到 ROS master,并提供一個具有給定名稱的服務(wù)對象。** 使用示例如下:\verbatimbool callback(std_srvs::Empty& request, std_srvs::Empty& response){return true;}ros::ServiceServer service = handle.advertiseService("my_service", callback);\endverbatim** \param service 服務(wù)的主題名稱* \param srv_func 接收到請求時,需要處理請求的回調(diào)函數(shù)* \return 請求成功時返回服務(wù)對象,否則返回空對象:\verbatimbool Foo::callback(std_srvs::Empty& request, std_srvs::Empty& response){return true;}ros::NodeHandle nodeHandle;Foo foo_object;ros::ServiceServer service = nodeHandle.advertiseService("my_service", callback);if (service) // Enter if advertised service is valid{...}\endverbatim*/template<class MReq, class MRes>ServiceServer advertiseService(const std::string& service, bool(*srv_func)(MReq&, MRes&))

      4.客戶端對象

      對象獲取:

      /*** @brief 創(chuàng)建一個服務(wù)客戶端對象** 當(dāng)清除最后一個連接的引用句柄時,連接將被關(guān)閉。** @param service_name 服務(wù)主題名稱*/template<class Service>ServiceClient serviceClient(const std::string& service_name, bool persistent = false,const M_string& header_values = M_string())

      請求發(fā)送函數(shù):

      /*** @brief 發(fā)送請求* 返回值為 bool 類型,true,請求處理成功,false,處理失敗。*/template<class Service>bool call(Service& service)

      等待服務(wù)函數(shù)1:

      /*** ros::service::waitForService("addInts");* \brief 等待服務(wù)可用,否則一致處于阻塞狀態(tài)* \param service_name 被"等待"的服務(wù)的話題名稱* \param timeout 等待最大時常,默認(rèn)為 -1,可以永久等待直至節(jié)點關(guān)閉* \return 成功返回 true,否則返回 false。*/ROSCPP_DECL bool waitForService(const std::string& service_name, ros::Duration timeout = ros::Duration(-1));

      等待服務(wù)函數(shù)2:

      /*** client.waitForExistence();* \brief 等待服務(wù)可用,否則一致處于阻塞狀態(tài)* \param timeout 等待最大時常,默認(rèn)為 -1,可以永久等待直至節(jié)點關(guān)閉* \return 成功返回 true,否則返回 false。*/bool waitForExistence(ros::Duration timeout = ros::Duration(-1));回旋函數(shù)C++

      在ROS程序中,頻繁的使用了 ros::spin() 和 ros::spinOnce() 兩個回旋函數(shù),可以用于處理回調(diào)函數(shù)。

      1.spinOnce()

      /*** \brief 處理一輪回調(diào)** 一般應(yīng)用場景:* 在循環(huán)體內(nèi),處理所有可用的回調(diào)函數(shù)**/ROSCPP_DECL void spinOnce();

      2.spin()

      /*** \brief 進(jìn)入循環(huán)處理回調(diào)*/ROSCPP_DECL void spin();對比

      相同點:二者都用于處理回調(diào)函數(shù);

      不同點:ros::spin() 是進(jìn)入了循環(huán)執(zhí)行回調(diào)函數(shù),而 ros::spinOnce() 只會執(zhí)行一次回調(diào)函數(shù)(沒有循環(huán)),在 ros::spin() 后的語句不會執(zhí)行到,而 ros::spinOnce() 后的語句可以執(zhí)行。

      時間1.時刻

      獲取時刻,或是設(shè)置指定時刻:

      ros::init(argc,argv,"hello_time");ros::NodeHandle nh;//必須創(chuàng)建句柄,否則時間沒有初始化,導(dǎo)致后續(xù)API調(diào)用失敗ros::Time right_now = ros::Time::now();//將當(dāng)前時刻封裝成對象ROS_INFO("當(dāng)前時刻:%.2f",right_now.toSec());//獲取距離 1970年01月01日 00:00:00 的秒數(shù)ROS_INFO("當(dāng)前時刻:%d",right_now.sec);//獲取距離 1970年01月01日 00:00:00 的秒數(shù)ros::Time someTime(100,100000000);// 參數(shù)1:秒數(shù) 參數(shù)2:納秒ROS_INFO("時刻:%.2f",someTime.toSec()); //100.10ros::Time someTime2(100.3);//直接傳入 double 類型的秒數(shù)ROS_INFO("時刻:%.2f",someTime2.toSec()); //100.302.持續(xù)時間

      設(shè)置一個時間區(qū)間(間隔):

      ROS_INFO("當(dāng)前時刻:%.2f",ros::Time::now().toSec());ros::Duration du(10);//持續(xù)10秒鐘,參數(shù)是double類型的,以秒為單位du.sleep();//按照指定的持續(xù)時間休眠ROS_INFO("持續(xù)時間:%.2f",du.toSec());//將持續(xù)時間換算成秒ROS_INFO("當(dāng)前時刻:%.2f",ros::Time::now().toSec());3.持續(xù)時間與時刻運(yùn)算

      為了方便使用,ROS中提供了時間與時刻的運(yùn)算:

      ROS_INFO("時間運(yùn)算");ros::Time now = ros::Time::now();ros::Duration du1(10);ros::Duration du2(20);ROS_INFO("當(dāng)前時刻:%.2f",now.toSec());//1.time 與 duration 運(yùn)算ros::Time after_now = now + du1;ros::Time before_now = now - du1;ROS_INFO("當(dāng)前時刻之后:%.2f",after_now.toSec());ROS_INFO("當(dāng)前時刻之前:%.2f",before_now.toSec());//2.duration 之間相互運(yùn)算ros::Duration du3 = du1 + du2;ros::Duration du4 = du1 - du2;ROS_INFO("du3 = %.2f",du3.toSec());ROS_INFO("du4 = %.2f",du4.toSec());//PS: time 與 time 不可以運(yùn)算// ros::Time nn = now + before_now;//異常4.設(shè)置運(yùn)行頻率(非常常用)ros::Rate rate(1);//指定頻率while (true){ROS_INFO("-----------code----------");rate.sleep();//休眠,休眠時間 = 1 / 頻率。}5.定時器

      ROS 中內(nèi)置了專門的定時器,可以實現(xiàn)與 ros::Rate 類似的效果:

      ros::NodeHandle nh;//必須創(chuàng)建句柄,否則時間沒有初始化,導(dǎo)致后續(xù)API調(diào)用失敗// ROS 定時器/*** \brief 創(chuàng)建一個定時器,按照指定頻率調(diào)用回調(diào)函數(shù)。** \param period 時間間隔* \param callback 回調(diào)函數(shù)* \param oneshot 如果設(shè)置為 true,只執(zhí)行一次回調(diào)函數(shù),設(shè)置為 false,就循環(huán)執(zhí)行。* \param autostart 如果為true,返回已經(jīng)啟動的定時器,設(shè)置為 false,需要手動啟動。*///Timer createTimer(Duration period, const TimerCallback& callback, bool oneshot = false,// bool autostart = true) const;// ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing);ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing,true);//只執(zhí)行一次// ros::Timer timer = nh.createTimer(ros::Duration(0.5),doSomeThing,false,false);//需要手動啟動// timer.start();ros::spin(); //必須 spin其他

      在發(fā)布實現(xiàn)時,一般會循環(huán)發(fā)布消息,循環(huán)的判斷條件一般由節(jié)點狀態(tài)來控制,C++中可以通過 ros::ok() 來判斷節(jié)點狀態(tài)是否正常,而 python 中則通過 rospy.is_shutdown() 來實現(xiàn)判斷,導(dǎo)致節(jié)點退出的原因主要有如下幾種:

      節(jié)點接收到了關(guān)閉信息,比如常用的 ctrl + c 快捷鍵就是關(guān)閉節(jié)點的信號;同名節(jié)點啟動,導(dǎo)致現(xiàn)有節(jié)點退出;程序中的其他部分調(diào)用了節(jié)點關(guān)閉相關(guān)的API(C++中是ros::shutdown(),python中是rospy.signal_shutdown())

      另外,日志相關(guān)的函數(shù)也是極其常用的,在ROS中日志被劃分成如下級別:

      DEBUG(調(diào)試):只在調(diào)試時使用,此類消息不會輸出到控制臺;INFO(信息):標(biāo)準(zhǔn)消息,一般用于說明系統(tǒng)內(nèi)正在執(zhí)行的操作;WARN(警告):提醒一些異常情況,但程序仍然可以執(zhí)行;ERROR(錯誤):提示錯誤信息,此類錯誤會影響程序運(yùn)行;FATAL(嚴(yán)重錯誤):此類錯誤將阻止節(jié)點繼續(xù)運(yùn)行。ROS 的運(yùn)行管理ROS元功能包

      顯而易見的,逐一安裝功能包的效率低下,在ROS中,提供了一種方式可以將不同的功能包打包成一個功能包,當(dāng)安裝某個功能模塊時,直接調(diào)用打包后的功能包即可,該包又稱之為元功能包(metapackage)。

      概念

      MetaPackage是Linux的一個文件管理系統(tǒng)的概念。是ROS中的一個虛包,里面沒有實質(zhì)性的內(nèi)容,但是它依賴了其他的軟件包,通過這種方法可以把其他包組合起來,我們可以認(rèn)為它是一本書的目錄索引,告訴我們這個包集合中有哪些子包,并且該去哪里下載。

      作用

      方便用戶的安裝,我們只需要這一個包就可以把其他相關(guān)的軟件包組織到一起安裝了。

      實現(xiàn)

      首先:新建一個功能包

      然后:修改package.xml ,內(nèi)容如下:

      <exec_depend>被集成的功能包</exec_depend>.....<export><metapackage /></export>

      最后:修改 CMakeLists.txt,內(nèi)容如下:

      cmake_minimum_required(VERSION 3.0.2)project(demo)find_package(catkin REQUIRED)catkin_metapackage()ROS節(jié)點運(yùn)行管理launch文件

      一個程序中可能需要啟動多個節(jié)點,比如:ROS 內(nèi)置的小烏龜案例,如果要控制烏龜運(yùn)動,要啟動多個窗口,分別啟動 roscore、烏龜界面節(jié)點、鍵盤控制節(jié)點。如果每次都調(diào)用 rosrun 逐一啟動,顯然效率低下,如何優(yōu)化?

      采用的優(yōu)化策略便是使用roslaunch 命令集合 launch 文件啟動管理節(jié)點

      概念

      launch 文件是一個 XML 格式的文件,可以啟動本地和遠(yuǎn)程的多個節(jié)點,還可以在參數(shù)服務(wù)器中設(shè)置參數(shù)。

      作用

      簡化節(jié)點的配置與啟動,提高ROS程序的啟動效率。

      使用

      以 turtlesim 為例演示

      1.新建launch文件

      在功能包下添加 launch目錄, 目錄下新建 xxxx.launch 文件,編輯 launch 文件

      <launch><node pkg="turtlesim" type="turtlesim_node" name="myTurtle" output="screen" /><node pkg="turtlesim" type="turtle_teleop_key" name="myTurtleContro" output="screen" /></launch>

      2.調(diào)用 launch 文件

      roslaunch 包名 xxx.launch

      注意:roslaunch 命令執(zhí)行l(wèi)aunch文件時,首先會判斷是否啟動了 roscore,如果啟動了,則不再啟動,否則,會自動調(diào)用 roscore

      launch文件 結(jié)構(gòu)

      launch文件標(biāo)簽之launch

      <launch>標(biāo)簽是所有 launch 文件的根標(biāo)簽,充當(dāng)其他標(biāo)簽的容器

      1.屬性

      deprecated = "棄用
      本文鏈接地址:http://esstyw.cn/zhishi/296158.html 轉(zhuǎn)載請保留說明!

      上一篇:ChatGPT API接口使用+fine tune微調(diào)+prompt介紹(api接口長什么樣)

      下一篇:Vue3 項目中使用setup()函數(shù)報錯,script setup cannot contain ES module exports(vue3使用教程)

    2. 抖音直播在哪里看(抖音直播在哪里開通)

      抖音直播在哪里看(抖音直播在哪里開通)

    3. 閑魚發(fā)布地址怎么修改(閑魚發(fā)布地址怎么關(guān)閉)

      閑魚發(fā)布地址怎么修改(閑魚發(fā)布地址怎么關(guān)閉)

    4. iqooneo5活力版電池容量(iqooneo5活力版電池?fù)p耗怎么看)

      iqooneo5活力版電池容量(iqooneo5活力版電池?fù)p耗怎么看)

    5. 小米主題怎么自己制作(小米主題怎么自己做主題發(fā)布)

      小米主題怎么自己制作(小米主題怎么自己做主題發(fā)布)

    6. qq看點視頻播放不了(qq看點視頻播放在哪里)

      qq看點視頻播放不了(qq看點視頻播放在哪里)

    7. 騰訊會議可以同時進(jìn)兩個嗎(騰訊會議app下載免費)

      騰訊會議可以同時進(jìn)兩個嗎(騰訊會議app下載免費)

    8. 華為手機(jī)指紋解鎖不靈敏是怎么回事(華為手機(jī)指紋解鎖后還要輸入密碼才能解鎖)

      華為手機(jī)指紋解鎖不靈敏是怎么回事(華為手機(jī)指紋解鎖后還要輸入密碼才能解鎖)

    9. 打電話串號是什么原因(打電話串號是什么意思)

      打電話串號是什么原因(打電話串號是什么意思)

    10. 微信交電費最晚多久到賬(微信交電費最晚到幾點)

      微信交電費最晚多久到賬(微信交電費最晚到幾點)

    11. qq收藏怎么設(shè)置隱私(qq收藏怎么設(shè)置私密)

      qq收藏怎么設(shè)置隱私(qq收藏怎么設(shè)置私密)

    12. 全民k歌sss什么水平(全民k歌中的s,ss,sss,b是什么意思)

      全民k歌sss什么水平(全民k歌中的s,ss,sss,b是什么意思)

    13. qq群消失了沒任何通知(qq群沒了是被踢了嗎)

      qq群消失了沒任何通知(qq群沒了是被踢了嗎)

    14. 電腦藍(lán)屏后重啟一直黑屏(電腦藍(lán)屏后重啟又正常是什么原因?)

      電腦藍(lán)屏后重啟一直黑屏(電腦藍(lán)屏后重啟又正常是什么原因?)

    15. 華為怎么掃一掃連無線(華為怎么掃一掃連接wifi)

      華為怎么掃一掃連無線(華為怎么掃一掃連接wifi)

    16. 電腦電源線顏色分別代表什么(電腦電源線顏色詳解)

      電腦電源線顏色分別代表什么(電腦電源線顏色詳解)

    17. 電腦顯示器有電源線嗎(電腦顯示器有電池嗎)

      電腦顯示器有電源線嗎(電腦顯示器有電池嗎)

    18. iphone降頻是什么意思(蘋果降頻是什么)

      iphone降頻是什么意思(蘋果降頻是什么)

    19. 華為matex折疊屏怎么打開

      華為matex折疊屏怎么打開

    20. 如何把電腦恢復(fù)出廠設(shè)置(如何把電腦恢復(fù)到原來的系統(tǒng))

      如何把電腦恢復(fù)出廠設(shè)置(如何把電腦恢復(fù)到原來的系統(tǒng))

    21. 大紅色cmyk數(shù)值(大紅色cmyk色值為多少)

      大紅色cmyk數(shù)值(大紅色cmyk色值為多少)

    22. 連接計算機(jī)系統(tǒng)結(jié)構(gòu)的五大基本組成部件(連接計算機(jī)系統(tǒng)各部件的總線包括())

      連接計算機(jī)系統(tǒng)結(jié)構(gòu)的五大基本組成部件(連接計算機(jī)系統(tǒng)各部件的總線包括())

    23. 金立m6如何找到出廠設(shè)置(金立手機(jī)m6怎么恢復(fù)出廠設(shè)置)

      金立m6如何找到出廠設(shè)置(金立手機(jī)m6怎么恢復(fù)出廠設(shè)置)

    24. vivox27怎么設(shè)置全面屏手勢(vivox27怎么設(shè)置后運(yùn)行的程序)

      vivox27怎么設(shè)置全面屏手勢(vivox27怎么設(shè)置后運(yùn)行的程序)

    25. 魅族16怎么隱藏應(yīng)用(魅族16怎么隱藏應(yīng)用軟件)

      魅族16怎么隱藏應(yīng)用(魅族16怎么隱藏應(yīng)用軟件)

    26. 公眾號閱讀量怎么統(tǒng)計(公眾號的閱讀量)

      公眾號閱讀量怎么統(tǒng)計(公眾號的閱讀量)

    27. 安全生產(chǎn)費實際發(fā)生必須是付款嗎還是掛帳也可以
    28. 事業(yè)單位資產(chǎn)負(fù)責(zé)比往年增加表明什么
    29. 法人轉(zhuǎn)錢入公戶怎么做會計分錄
    30. 預(yù)期報酬率和期望報酬率一樣嗎
    31. 2019年小型微利企業(yè)優(yōu)惠政策
    32. 待認(rèn)證進(jìn)項稅是借方還是貸方
    33. 專票上的電話號碼應(yīng)該是哪個
    34. 土地增值稅申報流程
    35. 房地產(chǎn)開發(fā)企業(yè)增值稅稅率
    36. 債務(wù)清償?shù)殖涞陌咐?/a>
    37. 出口貨物的進(jìn)項發(fā)票什么時候認(rèn)證
    38. 免稅農(nóng)產(chǎn)品如何填報企業(yè)所得稅季報
    39. 稅控專用設(shè)備抵扣分錄
    40. 估價入賬固定資產(chǎn)實際入賬時補(bǔ)提折舊嗎?
    41. 沒有費用報銷單發(fā)票可以直接報銷嗎
    42. 保險代理的傭金怎么算
    43. 個人轉(zhuǎn)讓怎么寫
    44. 研發(fā)費用進(jìn)成本嗎
    45. 會議費稅前扣除最新稅務(wù)規(guī)定
    46. 免稅單位出租房產(chǎn)如何繳納房產(chǎn)稅
    47. 委托貸款是流動資金貸款嗎
    48. 合同付款會計分錄
    49. 忘記用戶登錄密碼怎么辦
    50. 我國稅收法律制度不采用的稅率是
    51. win10更新失敗怎么回事
    52. 如何給寬帶加速使用
    53. 稅額差異會計分錄
    54. 紅沖暫估需要附件嗎
    55. 實收資本可以大于注冊資本嗎
    56. 梅德威海灘棕櫚樹間散步的沖浪者,印尼巴厘島 (? helivideo/GettyImages)
    57. php實現(xiàn)日歷
    58. 長期股權(quán)投資期末按什么計量
    59. 費用沖賬的會計分錄
    60. php dao
    61. php+ mysql教程
    62. win11更新22468
    63. php設(shè)置title
    64. 沖以前年度成本分錄
    65. 出差補(bǔ)貼要扣稅嗎
    66. python中模塊的概念
    67. 企業(yè)應(yīng)設(shè)置的賬簿包括什么
    68. 映射器可以定義參數(shù)類型
    69. 怎樣進(jìn)行制造費用的歸集
    70. 即征即退的收入如何處理
    71. 建筑企業(yè)異地施工預(yù)繳企業(yè)所得稅
    72. 醫(yī)院購買醫(yī)療器械
    73. 預(yù)算收入的退付范圍
    74. 匯算清繳期間費用社保填哪里
    75. 2017年6月,小張買了一臺筆記本電腦,其主要硬件參數(shù)
    76. 企業(yè)取得土地補(bǔ)償款
    77. 紙質(zhì)銀行承兌到期怎么辦
    78. 購買員工福利品會計分錄
    79. 專利技術(shù)會計分錄怎么做
    80. 退稅政策調(diào)整
    81. 互聯(lián)網(wǎng)企業(yè)招商手冊
    82. 環(huán)保局罰款記什么科目
    83. 技術(shù)合同免稅備案稅務(wù)局
    84. 會計可以用收據(jù)做賬嗎
    85. 母子公司可以合并嗎
    86. 免費獲取windows8.1
    87. windows10右鍵菜單打開太慢
    88. vista win
    89. linux crontab命令詳解
    90. win10系統(tǒng)預(yù)覽版
    91. windowsxp怎么改windows7
    92. 遠(yuǎn)程文件管理器
    93. 新款apple macbook air
    94. linux charon
    95. 如何關(guān)閉win8快速啟動
    96. windows8怎么去除廣告
    97. win7提示計算機(jī)內(nèi)存不足
    98. android中的動畫有哪幾類,它們的特點和區(qū)別是什么?
    99. jquery checkbox的相關(guān)操作總結(jié)
    100. python獲取list集合中某一元素的值
    101. python的排序方法
    102. 出口發(fā)票與報關(guān)單名稱不一致影響退稅嗎
    103. 本期應(yīng)納稅額怎么算
    104. 什么叫關(guān)聯(lián)單位
    105. etc可以抵扣嗎
    106. 土地分割抵押 如何實現(xiàn)抵押權(quán)
    107. 免責(zé)聲明:網(wǎng)站部分圖片文字素材來源于網(wǎng)絡(luò),如有侵權(quán),請及時告知,我們會第一時間刪除,謝謝! 郵箱:opceo@qq.com

      鄂ICP備2023003026號

      網(wǎng)站地圖: 企業(yè)信息 工商信息 財稅知識 網(wǎng)絡(luò)常識 編程技術(shù)

      友情鏈接: 武漢網(wǎng)站建設(shè)