[{"data":1,"prerenderedAt":4798},["ShallowReactive",2],{"wiki-page-\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng":3,"wiki-doc-items-\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng":4378,"language-switcher-data-\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng":4782,"wiki-i18n-paths-\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng":4797},{"id":4,"title":5,"body":6,"canonicalPath":4360,"chapterDepth":93,"chapterOrder":4361,"date":4362,"description":26,"docI18nKey":4363,"docKey":4364,"docRoot":4365,"docTitle":4366,"extension":4367,"i18nKey":4368,"isBlogPost":4369,"isWikiDoc":112,"isWikiIndex":4369,"layout":4370,"legacyPath":4370,"locale":4371,"localeSlug":4372,"meta":4373,"navigation":112,"path":4360,"seo":4374,"sourcePath":4375,"sourceStem":4368,"stem":4376,"wikiDepth":82,"__hash__":4377},"content\u002F_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0600-机器人工程写法与ROS2集成.md","Robot Engineering Approach and ROS2 Integration",{"type":7,"value":8,"toc":4312},"minimark",[9,16,19,30,37,40,48,53,56,62,67,71,764,771,775,804,808,814,818,821,824,830,833,835,839,842,845,848,1411,1415,1418,1442,1445,1451,1454,1457,1463,1465,1469,1472,1475,1481,1484,2685,2689,2692,2695,2721,2724,2758,2761,2791,2795,2798,2804,2807,2813,2816,2822,2825,2828,2831,2853,2856,2858,2862,2865,2868,2871,2877,2881,3673,3677,3680,3686,3689,3695,3698,3704,3707,3710,3722,3725,3741,3744,3747,3753,3757,3760,3766,3769,3772,3778,3780,3784,3787,3790,3794,3979,3983,3986,3992,3995,4001,4004,4010,4013,4015,4019,4022,4028,4031,4037,4040,4042,4046,4054,4060,4063,4091,4095,4098,4124,4128,4131,4183,4190,4240,4244,4247,4253,4256,4262,4266,4269,4273,4276,4278,4282,4285,4305,4308],[10,11,12],"blockquote",{},[13,14,15],"p",{},"The previous sections discussed Boost.Asio itself.\nThis section discusses how to organize code when you are actually working on a robot project, especially the relationships between serial port drivers, TCP\u002FUDP communication modules, and ROS2 nodes.",[13,17,18],{},"Core Principles:",[20,21,27],"pre",{"className":22,"code":24,"language":25,"meta":26},[23],"language-text","不要在 ROS2 回调里写长时间阻塞的串口 read \u002F TCP read。\n通信模块应该自己用 Asio 异步运行。\nROS2 节点只负责发布、订阅、参数、生命周期和业务逻辑。\n","text","",[28,29,24],"code",{"__ignoreMap":26},[13,31,32,33,36],{},"This section still uses ",[28,34,35],{},"std::bind",".",[38,39],"hr",{},[41,42,44,45],"h2",{"id":43},"example-1-simulating-robot-protocol-parsing-in-a-common-main","Example 1: Simulating robot protocol parsing in a common ",[28,46,47],{},"main()",[49,50,52],"h3",{"id":51},"program-objective","program objective",[13,54,55],{},"Many serial protocols for lower-level devices are a single line of text, for example:",[20,57,60],{"className":58,"code":59,"language":25,"meta":26},[23],"ODOM 1.0 2.0 0.5\nBAT 24.3\nIMU 0.1 0.2 9.8\n",[28,61,59],{"__ignoreMap":26},[13,63,64,65,36],{},"In this example, we won't connect the serial port yet, but will simulate parsing these strings in a regular ",[28,66,47],{},[49,68,70],{"id":69},"full-code","Full code",[20,72,76],{"className":73,"code":74,"language":75,"meta":26,"style":26},"language-cpp shiki shiki-themes github-light github-dark","#include \u003Ciostream>\n#include \u003Csstream>\n#include \u003Cstring>\n\nvoid parse_line(const std::string& line)\n{\n    std::istringstream iss(line);\n    std::string type;\n    iss >> type;\n\n    if (type == \"ODOM\")\n    {\n        double x = 0.0;\n        double y = 0.0;\n        double yaw = 0.0;\n        iss >> x >> y >> yaw;\n\n        std::cout \u003C\u003C \"解析里程计：x = \" \u003C\u003C x\n                  \u003C\u003C \"，y = \" \u003C\u003C y\n                  \u003C\u003C \"，yaw = \" \u003C\u003C yaw \u003C\u003C std::endl;\n    }\n    else if (type == \"BAT\")\n    {\n        double voltage = 0.0;\n        iss >> voltage;\n\n        std::cout \u003C\u003C \"解析电池电压：\" \u003C\u003C voltage \u003C\u003C \" V\" \u003C\u003C std::endl;\n    }\n    else if (type == \"IMU\")\n    {\n        double ax = 0.0;\n        double ay = 0.0;\n        double az = 0.0;\n        iss >> ax >> ay >> az;\n\n        std::cout \u003C\u003C \"解析 IMU 加速度：\"\n                  \u003C\u003C ax \u003C\u003C \", \" \u003C\u003C ay \u003C\u003C \", \" \u003C\u003C az \u003C\u003C std::endl;\n    }\n    else\n    {\n        std::cout \u003C\u003C \"未知协议行：\" \u003C\u003C line \u003C\u003C std::endl;\n    }\n}\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    std::cout \u003C\u003C \"main：开始模拟协议解析\" \u003C\u003C std::endl;\n\n    parse_line(\"ODOM 1.0 2.0 0.5\");\n    parse_line(\"BAT 24.3\");\n    parse_line(\"IMU 0.1 0.2 9.8\");\n    parse_line(\"HELLO STM32\");\n\n    std::cout \u003C\u003C \"main：结束\" \u003C\u003C std::endl;\n\n    \u002F\u002F 返回 0 表示程序正常结束。\n    return 0;\n}\n","cpp",[28,77,78,91,99,107,114,150,156,171,179,191,196,213,219,238,252,266,285,290,311,325,344,350,368,373,387,397,402,429,434,450,455,469,483,497,515,520,532,562,567,573,578,601,606,612,617,629,634,641,659,664,678,690,702,714,719,737,742,748,759],{"__ignoreMap":26},[79,80,83,87],"span",{"class":81,"line":82},"line",1,[79,84,86],{"class":85},"szBVR","#include",[79,88,90],{"class":89},"sZZnC"," \u003Ciostream>\n",[79,92,94,96],{"class":81,"line":93},2,[79,95,86],{"class":85},[79,97,98],{"class":89}," \u003Csstream>\n",[79,100,102,104],{"class":81,"line":101},3,[79,103,86],{"class":85},[79,105,106],{"class":89}," \u003Cstring>\n",[79,108,110],{"class":81,"line":109},4,[79,111,113],{"emptyLinePlaceholder":112},true,"\n",[79,115,117,120,124,128,131,134,137,140,143,147],{"class":81,"line":116},5,[79,118,119],{"class":85},"void",[79,121,123],{"class":122},"sScJk"," parse_line",[79,125,127],{"class":126},"sVt8B","(",[79,129,130],{"class":85},"const",[79,132,133],{"class":122}," std",[79,135,136],{"class":126},"::",[79,138,139],{"class":122},"string",[79,141,142],{"class":85},"&",[79,144,146],{"class":145},"s4XuR"," line",[79,148,149],{"class":126},")\n",[79,151,153],{"class":81,"line":152},6,[79,154,155],{"class":126},"{\n",[79,157,159,162,165,168],{"class":81,"line":158},7,[79,160,161],{"class":122},"    std",[79,163,164],{"class":126},"::istringstream ",[79,166,167],{"class":122},"iss",[79,169,170],{"class":126},"(line);\n",[79,172,174,176],{"class":81,"line":173},8,[79,175,161],{"class":122},[79,177,178],{"class":126},"::string type;\n",[79,180,182,185,188],{"class":81,"line":181},9,[79,183,184],{"class":126},"    iss ",[79,186,187],{"class":85},">>",[79,189,190],{"class":126}," type;\n",[79,192,194],{"class":81,"line":193},10,[79,195,113],{"emptyLinePlaceholder":112},[79,197,199,202,205,208,211],{"class":81,"line":198},11,[79,200,201],{"class":85},"    if",[79,203,204],{"class":126}," (type ",[79,206,207],{"class":85},"==",[79,209,210],{"class":89}," \"ODOM\"",[79,212,149],{"class":126},[79,214,216],{"class":81,"line":215},12,[79,217,218],{"class":126},"    {\n",[79,220,222,225,228,231,235],{"class":81,"line":221},13,[79,223,224],{"class":85},"        double",[79,226,227],{"class":126}," x ",[79,229,230],{"class":85},"=",[79,232,234],{"class":233},"sj4cs"," 0.0",[79,236,237],{"class":126},";\n",[79,239,241,243,246,248,250],{"class":81,"line":240},14,[79,242,224],{"class":85},[79,244,245],{"class":126}," y ",[79,247,230],{"class":85},[79,249,234],{"class":233},[79,251,237],{"class":126},[79,253,255,257,260,262,264],{"class":81,"line":254},15,[79,256,224],{"class":85},[79,258,259],{"class":126}," yaw ",[79,261,230],{"class":85},[79,263,234],{"class":233},[79,265,237],{"class":126},[79,267,269,272,274,276,278,280,282],{"class":81,"line":268},16,[79,270,271],{"class":126},"        iss ",[79,273,187],{"class":85},[79,275,227],{"class":126},[79,277,187],{"class":85},[79,279,245],{"class":126},[79,281,187],{"class":85},[79,283,284],{"class":126}," yaw;\n",[79,286,288],{"class":81,"line":287},17,[79,289,113],{"emptyLinePlaceholder":112},[79,291,293,296,299,302,305,308],{"class":81,"line":292},18,[79,294,295],{"class":122},"        std",[79,297,298],{"class":126},"::cout ",[79,300,301],{"class":85},"\u003C\u003C",[79,303,304],{"class":89}," \"解析里程计：x = \"",[79,306,307],{"class":85}," \u003C\u003C",[79,309,310],{"class":126}," x\n",[79,312,314,317,320,322],{"class":81,"line":313},19,[79,315,316],{"class":85},"                  \u003C\u003C",[79,318,319],{"class":89}," \"，y = \"",[79,321,307],{"class":85},[79,323,324],{"class":126}," y\n",[79,326,328,330,333,335,337,339,341],{"class":81,"line":327},20,[79,329,316],{"class":85},[79,331,332],{"class":89}," \"，yaw = \"",[79,334,307],{"class":85},[79,336,259],{"class":126},[79,338,301],{"class":85},[79,340,133],{"class":122},[79,342,343],{"class":126},"::endl;\n",[79,345,347],{"class":81,"line":346},21,[79,348,349],{"class":126},"    }\n",[79,351,353,356,359,361,363,366],{"class":81,"line":352},22,[79,354,355],{"class":85},"    else",[79,357,358],{"class":85}," if",[79,360,204],{"class":126},[79,362,207],{"class":85},[79,364,365],{"class":89}," \"BAT\"",[79,367,149],{"class":126},[79,369,371],{"class":81,"line":370},23,[79,372,218],{"class":126},[79,374,376,378,381,383,385],{"class":81,"line":375},24,[79,377,224],{"class":85},[79,379,380],{"class":126}," voltage ",[79,382,230],{"class":85},[79,384,234],{"class":233},[79,386,237],{"class":126},[79,388,390,392,394],{"class":81,"line":389},25,[79,391,271],{"class":126},[79,393,187],{"class":85},[79,395,396],{"class":126}," voltage;\n",[79,398,400],{"class":81,"line":399},26,[79,401,113],{"emptyLinePlaceholder":112},[79,403,405,407,409,411,414,416,418,420,423,425,427],{"class":81,"line":404},27,[79,406,295],{"class":122},[79,408,298],{"class":126},[79,410,301],{"class":85},[79,412,413],{"class":89}," \"解析电池电压：\"",[79,415,307],{"class":85},[79,417,380],{"class":126},[79,419,301],{"class":85},[79,421,422],{"class":89}," \" V\"",[79,424,307],{"class":85},[79,426,133],{"class":122},[79,428,343],{"class":126},[79,430,432],{"class":81,"line":431},28,[79,433,349],{"class":126},[79,435,437,439,441,443,445,448],{"class":81,"line":436},29,[79,438,355],{"class":85},[79,440,358],{"class":85},[79,442,204],{"class":126},[79,444,207],{"class":85},[79,446,447],{"class":89}," \"IMU\"",[79,449,149],{"class":126},[79,451,453],{"class":81,"line":452},30,[79,454,218],{"class":126},[79,456,458,460,463,465,467],{"class":81,"line":457},31,[79,459,224],{"class":85},[79,461,462],{"class":126}," ax ",[79,464,230],{"class":85},[79,466,234],{"class":233},[79,468,237],{"class":126},[79,470,472,474,477,479,481],{"class":81,"line":471},32,[79,473,224],{"class":85},[79,475,476],{"class":126}," ay ",[79,478,230],{"class":85},[79,480,234],{"class":233},[79,482,237],{"class":126},[79,484,486,488,491,493,495],{"class":81,"line":485},33,[79,487,224],{"class":85},[79,489,490],{"class":126}," az ",[79,492,230],{"class":85},[79,494,234],{"class":233},[79,496,237],{"class":126},[79,498,500,502,504,506,508,510,512],{"class":81,"line":499},34,[79,501,271],{"class":126},[79,503,187],{"class":85},[79,505,462],{"class":126},[79,507,187],{"class":85},[79,509,476],{"class":126},[79,511,187],{"class":85},[79,513,514],{"class":126}," az;\n",[79,516,518],{"class":81,"line":517},35,[79,519,113],{"emptyLinePlaceholder":112},[79,521,523,525,527,529],{"class":81,"line":522},36,[79,524,295],{"class":122},[79,526,298],{"class":126},[79,528,301],{"class":85},[79,530,531],{"class":89}," \"解析 IMU 加速度：\"\n",[79,533,535,537,539,541,544,546,548,550,552,554,556,558,560],{"class":81,"line":534},37,[79,536,316],{"class":85},[79,538,462],{"class":126},[79,540,301],{"class":85},[79,542,543],{"class":89}," \", \"",[79,545,307],{"class":85},[79,547,476],{"class":126},[79,549,301],{"class":85},[79,551,543],{"class":89},[79,553,307],{"class":85},[79,555,490],{"class":126},[79,557,301],{"class":85},[79,559,133],{"class":122},[79,561,343],{"class":126},[79,563,565],{"class":81,"line":564},38,[79,566,349],{"class":126},[79,568,570],{"class":81,"line":569},39,[79,571,572],{"class":85},"    else\n",[79,574,576],{"class":81,"line":575},40,[79,577,218],{"class":126},[79,579,581,583,585,587,590,592,595,597,599],{"class":81,"line":580},41,[79,582,295],{"class":122},[79,584,298],{"class":126},[79,586,301],{"class":85},[79,588,589],{"class":89}," \"未知协议行：\"",[79,591,307],{"class":85},[79,593,594],{"class":126}," line ",[79,596,301],{"class":85},[79,598,133],{"class":122},[79,600,343],{"class":126},[79,602,604],{"class":81,"line":603},42,[79,605,349],{"class":126},[79,607,609],{"class":81,"line":608},43,[79,610,611],{"class":126},"}\n",[79,613,615],{"class":81,"line":614},44,[79,616,113],{"emptyLinePlaceholder":112},[79,618,620,623,626],{"class":81,"line":619},45,[79,621,622],{"class":85},"int",[79,624,625],{"class":122}," main",[79,627,628],{"class":126},"()\n",[79,630,632],{"class":81,"line":631},46,[79,633,155],{"class":126},[79,635,637],{"class":81,"line":636},47,[79,638,640],{"class":639},"sJ8bj","    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n",[79,642,644,646,648,650,653,655,657],{"class":81,"line":643},48,[79,645,161],{"class":122},[79,647,298],{"class":126},[79,649,301],{"class":85},[79,651,652],{"class":89}," \"main：开始模拟协议解析\"",[79,654,307],{"class":85},[79,656,133],{"class":122},[79,658,343],{"class":126},[79,660,662],{"class":81,"line":661},49,[79,663,113],{"emptyLinePlaceholder":112},[79,665,667,670,672,675],{"class":81,"line":666},50,[79,668,669],{"class":122},"    parse_line",[79,671,127],{"class":126},[79,673,674],{"class":89},"\"ODOM 1.0 2.0 0.5\"",[79,676,677],{"class":126},");\n",[79,679,681,683,685,688],{"class":81,"line":680},51,[79,682,669],{"class":122},[79,684,127],{"class":126},[79,686,687],{"class":89},"\"BAT 24.3\"",[79,689,677],{"class":126},[79,691,693,695,697,700],{"class":81,"line":692},52,[79,694,669],{"class":122},[79,696,127],{"class":126},[79,698,699],{"class":89},"\"IMU 0.1 0.2 9.8\"",[79,701,677],{"class":126},[79,703,705,707,709,712],{"class":81,"line":704},53,[79,706,669],{"class":122},[79,708,127],{"class":126},[79,710,711],{"class":89},"\"HELLO STM32\"",[79,713,677],{"class":126},[79,715,717],{"class":81,"line":716},54,[79,718,113],{"emptyLinePlaceholder":112},[79,720,722,724,726,728,731,733,735],{"class":81,"line":721},55,[79,723,161],{"class":122},[79,725,298],{"class":126},[79,727,301],{"class":85},[79,729,730],{"class":89}," \"main：结束\"",[79,732,307],{"class":85},[79,734,133],{"class":122},[79,736,343],{"class":126},[79,738,740],{"class":81,"line":739},56,[79,741,113],{"emptyLinePlaceholder":112},[79,743,745],{"class":81,"line":744},57,[79,746,747],{"class":639},"    \u002F\u002F 返回 0 表示程序正常结束。\n",[79,749,751,754,757],{"class":81,"line":750},58,[79,752,753],{"class":85},"    return",[79,755,756],{"class":233}," 0",[79,758,237],{"class":126},[79,760,762],{"class":81,"line":761},59,[79,763,611],{"class":126},[13,765,766,770],{},[767,768,769],"strong",{},"Running Results",": See below for “Execution Output and Timeline”; specific times and sequences may vary slightly with the environment if the example involves timers, threads, networks, or external devices.",[49,772,774],{"id":773},"compile-and-run","Compile and run",[20,776,780],{"className":777,"code":778,"language":779,"meta":26,"style":26},"language-bash shiki shiki-themes github-light github-dark","g++ demo1_protocol_parse.cpp -o demo1_protocol_parse -std=c++17\n.\u002Fdemo1_protocol_parse\n","bash",[28,781,782,799],{"__ignoreMap":26},[79,783,784,787,790,793,796],{"class":81,"line":82},[79,785,786],{"class":122},"g++",[79,788,789],{"class":89}," demo1_protocol_parse.cpp",[79,791,792],{"class":233}," -o",[79,794,795],{"class":89}," demo1_protocol_parse",[79,797,798],{"class":233}," -std=c++17\n",[79,800,801],{"class":81,"line":93},[79,802,803],{"class":122},".\u002Fdemo1_protocol_parse\n",[49,805,807],{"id":806},"run-output","Run output",[20,809,812],{"className":810,"code":811,"language":25,"meta":26},[23],"main：开始模拟协议解析\n解析里程计：x = 1，y = 2，yaw = 0.5\n解析电池电压：24.3 V\n解析 IMU 加速度：0.1, 0.2, 9.8\n未知协议行：HELLO STM32\nmain：结束\n",[28,813,811],{"__ignoreMap":26},[49,815,817],{"id":816},"points-to-note-for-this-example","Points to note for this example",[13,819,820],{},"Before connecting the serial port, first write and test the protocol parsing function separately. This makes debugging more efficient.",[13,822,823],{},"Don't start by:",[20,825,828],{"className":826,"code":827,"language":25,"meta":26},[23],"串口读取\n协议解析\nROS2 发布\n控制逻辑\n",[28,829,827],{"__ignoreMap":26},[13,831,832],{},"All mixed together in one function.",[38,834],{},[41,836,838],{"id":837},"example-2-encapsulating-robot-protocol-parser-in-a-class","Example 2: Encapsulating Robot Protocol Parser in a Class",[49,840,52],{"id":841},"program-objective-1",[13,843,844],{},"Change Example 1 to a class encapsulation, to prepare for connecting serial port callbacks later.",[49,846,70],{"id":847},"full-code-1",[20,849,851],{"className":73,"code":850,"language":75,"meta":26,"style":26},"#include \u003Ciostream>\n#include \u003Csstream>\n#include \u003Cstring>\n\nclass RobotProtocolParser\n{\npublic:\n    void parse_line(const std::string& line)\n    {\n        std::istringstream iss(line);\n        std::string type;\n        iss >> type;\n\n        if (type == \"ODOM\")\n        {\n            parse_odom(iss);\n        }\n        else if (type == \"BAT\")\n        {\n            parse_battery(iss);\n        }\n        else\n        {\n            std::cout \u003C\u003C \"未知协议行：\" \u003C\u003C line \u003C\u003C std::endl;\n        }\n    }\n\nprivate:\n    void parse_odom(std::istringstream& iss)\n    {\n        double x = 0.0;\n        double y = 0.0;\n        double yaw = 0.0;\n        iss >> x >> y >> yaw;\n\n        std::cout \u003C\u003C \"RobotProtocolParser：ODOM x = \" \u003C\u003C x\n                  \u003C\u003C \"，y = \" \u003C\u003C y\n                  \u003C\u003C \"，yaw = \" \u003C\u003C yaw \u003C\u003C std::endl;\n    }\n\n    void parse_battery(std::istringstream& iss)\n    {\n        double voltage = 0.0;\n        iss >> voltage;\n\n        std::cout \u003C\u003C \"RobotProtocolParser：BAT voltage = \"\n                  \u003C\u003C voltage \u003C\u003C \" V\" \u003C\u003C std::endl;\n    }\n};\n\nint main()\n{\n    \u002F\u002F 程序从 main 函数开始执行，下面的语句会按顺序运行。\n    RobotProtocolParser parser;\n\n    std::cout \u003C\u003C \"main：开始解析\" \u003C\u003C std::endl;\n\n    parser.parse_line(\"ODOM 0.1 0.2 0.3\");\n    parser.parse_line(\"BAT 23.8\");\n    parser.parse_line(\"ERROR abc\");\n\n    std::cout \u003C\u003C \"main：结束\" \u003C\u003C std::endl;\n\n    \u002F\u002F 返回 0 表示程序正常结束。\n    return 0;\n}\n",[28,852,853,859,865,871,875,883,887,892,915,919,929,935,943,947,960,965,973,978,993,997,1004,1008,1013,1017,1038,1042,1046,1050,1055,1079,1083,1095,1107,1119,1135,1139,1154,1164,1180,1184,1188,1209,1213,1225,1233,1237,1248,1264,1268,1273,1277,1285,1289,1293,1298,1302,1319,1323,1338,1351,1365,1370,1387,1392,1397,1406],{"__ignoreMap":26},[79,854,855,857],{"class":81,"line":82},[79,856,86],{"class":85},[79,858,90],{"class":89},[79,860,861,863],{"class":81,"line":93},[79,862,86],{"class":85},[79,864,98],{"class":89},[79,866,867,869],{"class":81,"line":101},[79,868,86],{"class":85},[79,870,106],{"class":89},[79,872,873],{"class":81,"line":109},[79,874,113],{"emptyLinePlaceholder":112},[79,876,877,880],{"class":81,"line":116},[79,878,879],{"class":85},"class",[79,881,882],{"class":122}," RobotProtocolParser\n",[79,884,885],{"class":81,"line":152},[79,886,155],{"class":126},[79,888,889],{"class":81,"line":158},[79,890,891],{"class":85},"public:\n",[79,893,894,897,899,901,903,905,907,909,911,913],{"class":81,"line":173},[79,895,896],{"class":85},"    void",[79,898,123],{"class":122},[79,900,127],{"class":126},[79,902,130],{"class":85},[79,904,133],{"class":122},[79,906,136],{"class":126},[79,908,139],{"class":122},[79,910,142],{"class":85},[79,912,146],{"class":145},[79,914,149],{"class":126},[79,916,917],{"class":81,"line":181},[79,918,218],{"class":126},[79,920,921,923,925,927],{"class":81,"line":193},[79,922,295],{"class":122},[79,924,164],{"class":126},[79,926,167],{"class":122},[79,928,170],{"class":126},[79,930,931,933],{"class":81,"line":198},[79,932,295],{"class":122},[79,934,178],{"class":126},[79,936,937,939,941],{"class":81,"line":215},[79,938,271],{"class":126},[79,940,187],{"class":85},[79,942,190],{"class":126},[79,944,945],{"class":81,"line":221},[79,946,113],{"emptyLinePlaceholder":112},[79,948,949,952,954,956,958],{"class":81,"line":240},[79,950,951],{"class":85},"        if",[79,953,204],{"class":126},[79,955,207],{"class":85},[79,957,210],{"class":89},[79,959,149],{"class":126},[79,961,962],{"class":81,"line":254},[79,963,964],{"class":126},"        {\n",[79,966,967,970],{"class":81,"line":268},[79,968,969],{"class":122},"            parse_odom",[79,971,972],{"class":126},"(iss);\n",[79,974,975],{"class":81,"line":287},[79,976,977],{"class":126},"        }\n",[79,979,980,983,985,987,989,991],{"class":81,"line":292},[79,981,982],{"class":85},"        else",[79,984,358],{"class":85},[79,986,204],{"class":126},[79,988,207],{"class":85},[79,990,365],{"class":89},[79,992,149],{"class":126},[79,994,995],{"class":81,"line":313},[79,996,964],{"class":126},[79,998,999,1002],{"class":81,"line":327},[79,1000,1001],{"class":122},"            parse_battery",[79,1003,972],{"class":126},[79,1005,1006],{"class":81,"line":346},[79,1007,977],{"class":126},[79,1009,1010],{"class":81,"line":352},[79,1011,1012],{"class":85},"        else\n",[79,1014,1015],{"class":81,"line":370},[79,1016,964],{"class":126},[79,1018,1019,1022,1024,1026,1028,1030,1032,1034,1036],{"class":81,"line":375},[79,1020,1021],{"class":122},"            std",[79,1023,298],{"class":126},[79,1025,301],{"class":85},[79,1027,589],{"class":89},[79,1029,307],{"class":85},[79,1031,594],{"class":126},[79,1033,301],{"class":85},[79,1035,133],{"class":122},[79,1037,343],{"class":126},[79,1039,1040],{"class":81,"line":389},[79,1041,977],{"class":126},[79,1043,1044],{"class":81,"line":399},[79,1045,349],{"class":126},[79,1047,1048],{"class":81,"line":404},[79,1049,113],{"emptyLinePlaceholder":112},[79,1051,1052],{"class":81,"line":431},[79,1053,1054],{"class":85},"private:\n",[79,1056,1057,1059,1062,1064,1067,1069,1072,1074,1077],{"class":81,"line":436},[79,1058,896],{"class":85},[79,1060,1061],{"class":122}," parse_odom",[79,1063,127],{"class":126},[79,1065,1066],{"class":122},"std",[79,1068,136],{"class":126},[79,1070,1071],{"class":122},"istringstream",[79,1073,142],{"class":85},[79,1075,1076],{"class":145}," iss",[79,1078,149],{"class":126},[79,1080,1081],{"class":81,"line":452},[79,1082,218],{"class":126},[79,1084,1085,1087,1089,1091,1093],{"class":81,"line":457},[79,1086,224],{"class":85},[79,1088,227],{"class":126},[79,1090,230],{"class":85},[79,1092,234],{"class":233},[79,1094,237],{"class":126},[79,1096,1097,1099,1101,1103,1105],{"class":81,"line":471},[79,1098,224],{"class":85},[79,1100,245],{"class":126},[79,1102,230],{"class":85},[79,1104,234],{"class":233},[79,1106,237],{"class":126},[79,1108,1109,1111,1113,1115,1117],{"class":81,"line":485},[79,1110,224],{"class":85},[79,1112,259],{"class":126},[79,1114,230],{"class":85},[79,1116,234],{"class":233},[79,1118,237],{"class":126},[79,1120,1121,1123,1125,1127,1129,1131,1133],{"class":81,"line":499},[79,1122,271],{"class":126},[79,1124,187],{"class":85},[79,1126,227],{"class":126},[79,1128,187],{"class":85},[79,1130,245],{"class":126},[79,1132,187],{"class":85},[79,1134,284],{"class":126},[79,1136,1137],{"class":81,"line":517},[79,1138,113],{"emptyLinePlaceholder":112},[79,1140,1141,1143,1145,1147,1150,1152],{"class":81,"line":522},[79,1142,295],{"class":122},[79,1144,298],{"class":126},[79,1146,301],{"class":85},[79,1148,1149],{"class":89}," \"RobotProtocolParser：ODOM x = \"",[79,1151,307],{"class":85},[79,1153,310],{"class":126},[79,1155,1156,1158,1160,1162],{"class":81,"line":534},[79,1157,316],{"class":85},[79,1159,319],{"class":89},[79,1161,307],{"class":85},[79,1163,324],{"class":126},[79,1165,1166,1168,1170,1172,1174,1176,1178],{"class":81,"line":564},[79,1167,316],{"class":85},[79,1169,332],{"class":89},[79,1171,307],{"class":85},[79,1173,259],{"class":126},[79,1175,301],{"class":85},[79,1177,133],{"class":122},[79,1179,343],{"class":126},[79,1181,1182],{"class":81,"line":569},[79,1183,349],{"class":126},[79,1185,1186],{"class":81,"line":575},[79,1187,113],{"emptyLinePlaceholder":112},[79,1189,1190,1192,1195,1197,1199,1201,1203,1205,1207],{"class":81,"line":580},[79,1191,896],{"class":85},[79,1193,1194],{"class":122}," parse_battery",[79,1196,127],{"class":126},[79,1198,1066],{"class":122},[79,1200,136],{"class":126},[79,1202,1071],{"class":122},[79,1204,142],{"class":85},[79,1206,1076],{"class":145},[79,1208,149],{"class":126},[79,1210,1211],{"class":81,"line":603},[79,1212,218],{"class":126},[79,1214,1215,1217,1219,1221,1223],{"class":81,"line":608},[79,1216,224],{"class":85},[79,1218,380],{"class":126},[79,1220,230],{"class":85},[79,1222,234],{"class":233},[79,1224,237],{"class":126},[79,1226,1227,1229,1231],{"class":81,"line":614},[79,1228,271],{"class":126},[79,1230,187],{"class":85},[79,1232,396],{"class":126},[79,1234,1235],{"class":81,"line":619},[79,1236,113],{"emptyLinePlaceholder":112},[79,1238,1239,1241,1243,1245],{"class":81,"line":631},[79,1240,295],{"class":122},[79,1242,298],{"class":126},[79,1244,301],{"class":85},[79,1246,1247],{"class":89}," \"RobotProtocolParser：BAT voltage = \"\n",[79,1249,1250,1252,1254,1256,1258,1260,1262],{"class":81,"line":636},[79,1251,316],{"class":85},[79,1253,380],{"class":126},[79,1255,301],{"class":85},[79,1257,422],{"class":89},[79,1259,307],{"class":85},[79,1261,133],{"class":122},[79,1263,343],{"class":126},[79,1265,1266],{"class":81,"line":643},[79,1267,349],{"class":126},[79,1269,1270],{"class":81,"line":661},[79,1271,1272],{"class":126},"};\n",[79,1274,1275],{"class":81,"line":666},[79,1276,113],{"emptyLinePlaceholder":112},[79,1278,1279,1281,1283],{"class":81,"line":680},[79,1280,622],{"class":85},[79,1282,625],{"class":122},[79,1284,628],{"class":126},[79,1286,1287],{"class":81,"line":692},[79,1288,155],{"class":126},[79,1290,1291],{"class":81,"line":704},[79,1292,640],{"class":639},[79,1294,1295],{"class":81,"line":716},[79,1296,1297],{"class":126},"    RobotProtocolParser parser;\n",[79,1299,1300],{"class":81,"line":721},[79,1301,113],{"emptyLinePlaceholder":112},[79,1303,1304,1306,1308,1310,1313,1315,1317],{"class":81,"line":739},[79,1305,161],{"class":122},[79,1307,298],{"class":126},[79,1309,301],{"class":85},[79,1311,1312],{"class":89}," \"main：开始解析\"",[79,1314,307],{"class":85},[79,1316,133],{"class":122},[79,1318,343],{"class":126},[79,1320,1321],{"class":81,"line":744},[79,1322,113],{"emptyLinePlaceholder":112},[79,1324,1325,1328,1331,1333,1336],{"class":81,"line":750},[79,1326,1327],{"class":126},"    parser.",[79,1329,1330],{"class":122},"parse_line",[79,1332,127],{"class":126},[79,1334,1335],{"class":89},"\"ODOM 0.1 0.2 0.3\"",[79,1337,677],{"class":126},[79,1339,1340,1342,1344,1346,1349],{"class":81,"line":761},[79,1341,1327],{"class":126},[79,1343,1330],{"class":122},[79,1345,127],{"class":126},[79,1347,1348],{"class":89},"\"BAT 23.8\"",[79,1350,677],{"class":126},[79,1352,1354,1356,1358,1360,1363],{"class":81,"line":1353},60,[79,1355,1327],{"class":126},[79,1357,1330],{"class":122},[79,1359,127],{"class":126},[79,1361,1362],{"class":89},"\"ERROR abc\"",[79,1364,677],{"class":126},[79,1366,1368],{"class":81,"line":1367},61,[79,1369,113],{"emptyLinePlaceholder":112},[79,1371,1373,1375,1377,1379,1381,1383,1385],{"class":81,"line":1372},62,[79,1374,161],{"class":122},[79,1376,298],{"class":126},[79,1378,301],{"class":85},[79,1380,730],{"class":89},[79,1382,307],{"class":85},[79,1384,133],{"class":122},[79,1386,343],{"class":126},[79,1388,1390],{"class":81,"line":1389},63,[79,1391,113],{"emptyLinePlaceholder":112},[79,1393,1395],{"class":81,"line":1394},64,[79,1396,747],{"class":639},[79,1398,1400,1402,1404],{"class":81,"line":1399},65,[79,1401,753],{"class":85},[79,1403,756],{"class":233},[79,1405,237],{"class":126},[79,1407,1409],{"class":81,"line":1408},66,[79,1410,611],{"class":126},[13,1412,1413,770],{},[767,1414,769],{},[49,1416,774],{"id":1417},"compile-and-run-1",[20,1419,1421],{"className":777,"code":1420,"language":779,"meta":26,"style":26},"g++ demo2_protocol_parser_class.cpp -o demo2_protocol_parser_class -std=c++17\n.\u002Fdemo2_protocol_parser_class\n",[28,1422,1423,1437],{"__ignoreMap":26},[79,1424,1425,1427,1430,1432,1435],{"class":81,"line":82},[79,1426,786],{"class":122},[79,1428,1429],{"class":89}," demo2_protocol_parser_class.cpp",[79,1431,792],{"class":233},[79,1433,1434],{"class":89}," demo2_protocol_parser_class",[79,1436,798],{"class":233},[79,1438,1439],{"class":81,"line":93},[79,1440,1441],{"class":122},".\u002Fdemo2_protocol_parser_class\n",[49,1443,807],{"id":1444},"run-output-1",[20,1446,1449],{"className":1447,"code":1448,"language":25,"meta":26},[23],"main：开始解析\nRobotProtocolParser：ODOM x = 0.1，y = 0.2，yaw = 0.3\nRobotProtocolParser：BAT voltage = 23.8 V\n未知协议行：ERROR abc\nmain：结束\n",[28,1450,1448],{"__ignoreMap":26},[49,1452,817],{"id":1453},"points-to-note-for-this-example-1",[13,1455,1456],{},"The protocol parser should not depend on Boost.Asio, nor on ROS2.",[13,1458,1459,1460,1462],{},"It’s best if it is a pure C++ class. That way, you can directly verify it with ordinary ",[28,1461,47],{}," or unit tests.",[38,1464],{},[41,1466,1468],{"id":1467},"example-3-asio-serial-port-read-protocol-parser-combination","Example 3: Asio Serial Port Read + Protocol Parser Combination",[49,1470,52],{"id":1471},"program-objective-2",[13,1473,1474],{},"Combine the previous asynchronous serial port reading and protocol parser:",[20,1476,1479],{"className":1477,"code":1478,"language":25,"meta":26},[23],"串口收到一行\nSerialRobotDriver::on_read() 被调用\n取出字符串\n交给 RobotProtocolParser 解析\n继续注册下一次串口读取\n",[28,1480,1478],{"__ignoreMap":26},[49,1482,70],{"id":1483},"full-code-2",[20,1485,1487],{"className":73,"code":1486,"language":75,"meta":26,"style":26},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n#include \u003Cfunctional>\n#include \u003Ciostream>\n#include \u003Cistream>\n#include \u003Csstream>\n#include \u003Cstring>\n\nclass RobotProtocolParser\n{\npublic:\n    void parse_line(const std::string& line)\n    {\n        std::istringstream iss(line);\n        std::string type;\n        iss >> type;\n\n        if (type == \"ODOM\")\n        {\n            double x = 0.0;\n            double y = 0.0;\n            double yaw = 0.0;\n            iss >> x >> y >> yaw;\n\n            std::cout \u003C\u003C \"解析 ODOM：x = \" \u003C\u003C x\n                      \u003C\u003C \"，y = \" \u003C\u003C y\n                      \u003C\u003C \"，yaw = \" \u003C\u003C yaw \u003C\u003C std::endl;\n        }\n        else if (type == \"BAT\")\n        {\n            double voltage = 0.0;\n            iss >> voltage;\n\n            std::cout \u003C\u003C \"解析 BAT：\" \u003C\u003C voltage \u003C\u003C \" V\" \u003C\u003C std::endl;\n        }\n        else\n        {\n            std::cout \u003C\u003C \"未知数据：\" \u003C\u003C line \u003C\u003C std::endl;\n        }\n    }\n};\n\nclass SerialRobotDriver\n{\npublic:\n    SerialRobotDriver(boost::asio::io_context& io, const std::string& port_name)\n        : serial_(io)\n    {\n        boost::system::error_code ec;\n\n        serial_.open(port_name, ec);\n        if (ec)\n        {\n            std::cout \u003C\u003C \"打开串口失败：\" \u003C\u003C ec.message() \u003C\u003C std::endl;\n            return;\n        }\n\n        serial_.set_option(boost::asio::serial_port_base::baud_rate(115200));\n\n        std::cout \u003C\u003C \"SerialRobotDriver：串口打开成功\" \u003C\u003C std::endl;\n\n        start_read();\n    }\n\nprivate:\n    void start_read()\n    {\n        boost::asio::async_read_until(serial_,\n                                      buffer_,\n                                      '\\n',\n                                      std::bind(&SerialRobotDriver::on_read,\n                                                this,\n                                                std::placeholders::_1,\n                                                std::placeholders::_2));\n    }\n\n    void on_read(const boost::system::error_code& ec, std::size_t bytes_transferred)\n    {\n        if (ec)\n        {\n            std::cout \u003C\u003C \"串口读取错误：\" \u003C\u003C ec.message() \u003C\u003C std::endl;\n            return;\n        }\n\n        std::istream is(&buffer_);\n        std::string line;\n        std::getline(is, line);\n\n        std::cout \u003C\u003C \"收到串口行，bytes = \" \u003C\u003C bytes_transferred\n                  \u003C\u003C \"，line = \" \u003C\u003C line \u003C\u003C std::endl;\n\n        parser_.parse_line(line);\n\n        start_read();\n    }\n\nprivate:\n    \u002F\u002F serial_port 表示串口设备，后续读写都通过它完成。\n    boost::asio::serial_port serial_;\n    boost::asio::streambuf buffer_;\n    RobotProtocolParser parser_;\n};\n\nint main(int argc, char* argv[])\n{\n    \u002F\u002F 程序从 main 函数开始执行，argc\u002Fargv 用来接收命令行参数。\n    std::string port_name = \"\u002Fdev\u002Fpts\u002F3\";\n\n    if (argc >= 2)\n    {\n        port_name = argv[1];\n    }\n\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io;\n    SerialRobotDriver driver(io, port_name);\n\n    std::cout \u003C\u003C \"main：开始 io.run()\" \u003C\u003C std::endl;\n\n    \u002F\u002F 启动事件循环，前面注册的异步任务会在这里被调度执行。\n    io.run();\n\n    std::cout \u003C\u003C \"main：io.run() 返回\" \u003C\u003C std::endl;\n\n    return 0;\n}\n",[28,1488,1489,1496,1503,1510,1516,1523,1529,1535,1539,1545,1549,1553,1575,1579,1589,1595,1603,1607,1619,1623,1636,1648,1660,1677,1681,1696,1707,1723,1727,1741,1745,1757,1765,1769,1794,1798,1802,1806,1827,1831,1835,1839,1843,1850,1854,1858,1901,1912,1916,1929,1933,1944,1951,1955,1983,1990,1994,1998,2031,2035,2052,2056,2064,2068,2072,2076,2085,2090,2107,2113,2128,2149,2157,2171,2183,2188,2193,2236,2241,2248,2253,2279,2286,2291,2296,2314,2322,2335,2340,2357,2375,2380,2390,2395,2402,2407,2412,2417,2423,2436,2448,2454,2459,2464,2489,2494,2500,2515,2520,2536,2541,2558,2563,2568,2574,2586,2598,2603,2621,2626,2632,2643,2648,2666,2671,2680],{"__ignoreMap":26},[79,1490,1491,1493],{"class":81,"line":82},[79,1492,86],{"class":85},[79,1494,1495],{"class":89}," \u003Cboost\u002Fasio.hpp>\n",[79,1497,1498,1500],{"class":81,"line":93},[79,1499,86],{"class":85},[79,1501,1502],{"class":89}," \u003Cboost\u002Fsystem\u002Ferror_code.hpp>\n",[79,1504,1505,1507],{"class":81,"line":101},[79,1506,86],{"class":85},[79,1508,1509],{"class":89}," \u003Cfunctional>\n",[79,1511,1512,1514],{"class":81,"line":109},[79,1513,86],{"class":85},[79,1515,90],{"class":89},[79,1517,1518,1520],{"class":81,"line":116},[79,1519,86],{"class":85},[79,1521,1522],{"class":89}," \u003Cistream>\n",[79,1524,1525,1527],{"class":81,"line":152},[79,1526,86],{"class":85},[79,1528,98],{"class":89},[79,1530,1531,1533],{"class":81,"line":158},[79,1532,86],{"class":85},[79,1534,106],{"class":89},[79,1536,1537],{"class":81,"line":173},[79,1538,113],{"emptyLinePlaceholder":112},[79,1540,1541,1543],{"class":81,"line":181},[79,1542,879],{"class":85},[79,1544,882],{"class":122},[79,1546,1547],{"class":81,"line":193},[79,1548,155],{"class":126},[79,1550,1551],{"class":81,"line":198},[79,1552,891],{"class":85},[79,1554,1555,1557,1559,1561,1563,1565,1567,1569,1571,1573],{"class":81,"line":215},[79,1556,896],{"class":85},[79,1558,123],{"class":122},[79,1560,127],{"class":126},[79,1562,130],{"class":85},[79,1564,133],{"class":122},[79,1566,136],{"class":126},[79,1568,139],{"class":122},[79,1570,142],{"class":85},[79,1572,146],{"class":145},[79,1574,149],{"class":126},[79,1576,1577],{"class":81,"line":221},[79,1578,218],{"class":126},[79,1580,1581,1583,1585,1587],{"class":81,"line":240},[79,1582,295],{"class":122},[79,1584,164],{"class":126},[79,1586,167],{"class":122},[79,1588,170],{"class":126},[79,1590,1591,1593],{"class":81,"line":254},[79,1592,295],{"class":122},[79,1594,178],{"class":126},[79,1596,1597,1599,1601],{"class":81,"line":268},[79,1598,271],{"class":126},[79,1600,187],{"class":85},[79,1602,190],{"class":126},[79,1604,1605],{"class":81,"line":287},[79,1606,113],{"emptyLinePlaceholder":112},[79,1608,1609,1611,1613,1615,1617],{"class":81,"line":292},[79,1610,951],{"class":85},[79,1612,204],{"class":126},[79,1614,207],{"class":85},[79,1616,210],{"class":89},[79,1618,149],{"class":126},[79,1620,1621],{"class":81,"line":313},[79,1622,964],{"class":126},[79,1624,1625,1628,1630,1632,1634],{"class":81,"line":327},[79,1626,1627],{"class":85},"            double",[79,1629,227],{"class":126},[79,1631,230],{"class":85},[79,1633,234],{"class":233},[79,1635,237],{"class":126},[79,1637,1638,1640,1642,1644,1646],{"class":81,"line":346},[79,1639,1627],{"class":85},[79,1641,245],{"class":126},[79,1643,230],{"class":85},[79,1645,234],{"class":233},[79,1647,237],{"class":126},[79,1649,1650,1652,1654,1656,1658],{"class":81,"line":352},[79,1651,1627],{"class":85},[79,1653,259],{"class":126},[79,1655,230],{"class":85},[79,1657,234],{"class":233},[79,1659,237],{"class":126},[79,1661,1662,1665,1667,1669,1671,1673,1675],{"class":81,"line":370},[79,1663,1664],{"class":126},"            iss ",[79,1666,187],{"class":85},[79,1668,227],{"class":126},[79,1670,187],{"class":85},[79,1672,245],{"class":126},[79,1674,187],{"class":85},[79,1676,284],{"class":126},[79,1678,1679],{"class":81,"line":375},[79,1680,113],{"emptyLinePlaceholder":112},[79,1682,1683,1685,1687,1689,1692,1694],{"class":81,"line":389},[79,1684,1021],{"class":122},[79,1686,298],{"class":126},[79,1688,301],{"class":85},[79,1690,1691],{"class":89}," \"解析 ODOM：x = \"",[79,1693,307],{"class":85},[79,1695,310],{"class":126},[79,1697,1698,1701,1703,1705],{"class":81,"line":399},[79,1699,1700],{"class":85},"                      \u003C\u003C",[79,1702,319],{"class":89},[79,1704,307],{"class":85},[79,1706,324],{"class":126},[79,1708,1709,1711,1713,1715,1717,1719,1721],{"class":81,"line":404},[79,1710,1700],{"class":85},[79,1712,332],{"class":89},[79,1714,307],{"class":85},[79,1716,259],{"class":126},[79,1718,301],{"class":85},[79,1720,133],{"class":122},[79,1722,343],{"class":126},[79,1724,1725],{"class":81,"line":431},[79,1726,977],{"class":126},[79,1728,1729,1731,1733,1735,1737,1739],{"class":81,"line":436},[79,1730,982],{"class":85},[79,1732,358],{"class":85},[79,1734,204],{"class":126},[79,1736,207],{"class":85},[79,1738,365],{"class":89},[79,1740,149],{"class":126},[79,1742,1743],{"class":81,"line":452},[79,1744,964],{"class":126},[79,1746,1747,1749,1751,1753,1755],{"class":81,"line":457},[79,1748,1627],{"class":85},[79,1750,380],{"class":126},[79,1752,230],{"class":85},[79,1754,234],{"class":233},[79,1756,237],{"class":126},[79,1758,1759,1761,1763],{"class":81,"line":471},[79,1760,1664],{"class":126},[79,1762,187],{"class":85},[79,1764,396],{"class":126},[79,1766,1767],{"class":81,"line":485},[79,1768,113],{"emptyLinePlaceholder":112},[79,1770,1771,1773,1775,1777,1780,1782,1784,1786,1788,1790,1792],{"class":81,"line":499},[79,1772,1021],{"class":122},[79,1774,298],{"class":126},[79,1776,301],{"class":85},[79,1778,1779],{"class":89}," \"解析 BAT：\"",[79,1781,307],{"class":85},[79,1783,380],{"class":126},[79,1785,301],{"class":85},[79,1787,422],{"class":89},[79,1789,307],{"class":85},[79,1791,133],{"class":122},[79,1793,343],{"class":126},[79,1795,1796],{"class":81,"line":517},[79,1797,977],{"class":126},[79,1799,1800],{"class":81,"line":522},[79,1801,1012],{"class":85},[79,1803,1804],{"class":81,"line":534},[79,1805,964],{"class":126},[79,1807,1808,1810,1812,1814,1817,1819,1821,1823,1825],{"class":81,"line":564},[79,1809,1021],{"class":122},[79,1811,298],{"class":126},[79,1813,301],{"class":85},[79,1815,1816],{"class":89}," \"未知数据：\"",[79,1818,307],{"class":85},[79,1820,594],{"class":126},[79,1822,301],{"class":85},[79,1824,133],{"class":122},[79,1826,343],{"class":126},[79,1828,1829],{"class":81,"line":569},[79,1830,977],{"class":126},[79,1832,1833],{"class":81,"line":575},[79,1834,349],{"class":126},[79,1836,1837],{"class":81,"line":580},[79,1838,1272],{"class":126},[79,1840,1841],{"class":81,"line":603},[79,1842,113],{"emptyLinePlaceholder":112},[79,1844,1845,1847],{"class":81,"line":608},[79,1846,879],{"class":85},[79,1848,1849],{"class":122}," SerialRobotDriver\n",[79,1851,1852],{"class":81,"line":614},[79,1853,155],{"class":126},[79,1855,1856],{"class":81,"line":619},[79,1857,891],{"class":85},[79,1859,1860,1863,1865,1868,1870,1873,1875,1878,1880,1883,1886,1888,1890,1892,1894,1896,1899],{"class":81,"line":631},[79,1861,1862],{"class":122},"    SerialRobotDriver",[79,1864,127],{"class":126},[79,1866,1867],{"class":122},"boost",[79,1869,136],{"class":126},[79,1871,1872],{"class":122},"asio",[79,1874,136],{"class":126},[79,1876,1877],{"class":122},"io_context",[79,1879,142],{"class":85},[79,1881,1882],{"class":145}," io",[79,1884,1885],{"class":126},", ",[79,1887,130],{"class":85},[79,1889,133],{"class":122},[79,1891,136],{"class":126},[79,1893,139],{"class":122},[79,1895,142],{"class":85},[79,1897,1898],{"class":145}," port_name",[79,1900,149],{"class":126},[79,1902,1903,1906,1909],{"class":81,"line":636},[79,1904,1905],{"class":126},"        : ",[79,1907,1908],{"class":122},"serial_",[79,1910,1911],{"class":126},"(io)\n",[79,1913,1914],{"class":81,"line":643},[79,1915,218],{"class":126},[79,1917,1918,1921,1923,1926],{"class":81,"line":661},[79,1919,1920],{"class":122},"        boost",[79,1922,136],{"class":126},[79,1924,1925],{"class":122},"system",[79,1927,1928],{"class":126},"::error_code ec;\n",[79,1930,1931],{"class":81,"line":666},[79,1932,113],{"emptyLinePlaceholder":112},[79,1934,1935,1938,1941],{"class":81,"line":680},[79,1936,1937],{"class":126},"        serial_.",[79,1939,1940],{"class":122},"open",[79,1942,1943],{"class":126},"(port_name, ec);\n",[79,1945,1946,1948],{"class":81,"line":692},[79,1947,951],{"class":85},[79,1949,1950],{"class":126}," (ec)\n",[79,1952,1953],{"class":81,"line":704},[79,1954,964],{"class":126},[79,1956,1957,1959,1961,1963,1966,1968,1971,1974,1977,1979,1981],{"class":81,"line":716},[79,1958,1021],{"class":122},[79,1960,298],{"class":126},[79,1962,301],{"class":85},[79,1964,1965],{"class":89}," \"打开串口失败：\"",[79,1967,307],{"class":85},[79,1969,1970],{"class":126}," ec.",[79,1972,1973],{"class":122},"message",[79,1975,1976],{"class":126},"() ",[79,1978,301],{"class":85},[79,1980,133],{"class":122},[79,1982,343],{"class":126},[79,1984,1985,1988],{"class":81,"line":721},[79,1986,1987],{"class":85},"            return",[79,1989,237],{"class":126},[79,1991,1992],{"class":81,"line":739},[79,1993,977],{"class":126},[79,1995,1996],{"class":81,"line":744},[79,1997,113],{"emptyLinePlaceholder":112},[79,1999,2000,2002,2005,2007,2009,2011,2013,2015,2018,2020,2023,2025,2028],{"class":81,"line":750},[79,2001,1937],{"class":126},[79,2003,2004],{"class":122},"set_option",[79,2006,127],{"class":126},[79,2008,1867],{"class":122},[79,2010,136],{"class":126},[79,2012,1872],{"class":122},[79,2014,136],{"class":126},[79,2016,2017],{"class":122},"serial_port_base",[79,2019,136],{"class":126},[79,2021,2022],{"class":122},"baud_rate",[79,2024,127],{"class":126},[79,2026,2027],{"class":233},"115200",[79,2029,2030],{"class":126},"));\n",[79,2032,2033],{"class":81,"line":761},[79,2034,113],{"emptyLinePlaceholder":112},[79,2036,2037,2039,2041,2043,2046,2048,2050],{"class":81,"line":1353},[79,2038,295],{"class":122},[79,2040,298],{"class":126},[79,2042,301],{"class":85},[79,2044,2045],{"class":89}," \"SerialRobotDriver：串口打开成功\"",[79,2047,307],{"class":85},[79,2049,133],{"class":122},[79,2051,343],{"class":126},[79,2053,2054],{"class":81,"line":1367},[79,2055,113],{"emptyLinePlaceholder":112},[79,2057,2058,2061],{"class":81,"line":1372},[79,2059,2060],{"class":122},"        start_read",[79,2062,2063],{"class":126},"();\n",[79,2065,2066],{"class":81,"line":1389},[79,2067,349],{"class":126},[79,2069,2070],{"class":81,"line":1394},[79,2071,113],{"emptyLinePlaceholder":112},[79,2073,2074],{"class":81,"line":1399},[79,2075,1054],{"class":85},[79,2077,2078,2080,2083],{"class":81,"line":1408},[79,2079,896],{"class":85},[79,2081,2082],{"class":122}," start_read",[79,2084,628],{"class":126},[79,2086,2088],{"class":81,"line":2087},67,[79,2089,218],{"class":126},[79,2091,2093,2095,2097,2099,2101,2104],{"class":81,"line":2092},68,[79,2094,1920],{"class":122},[79,2096,136],{"class":126},[79,2098,1872],{"class":122},[79,2100,136],{"class":126},[79,2102,2103],{"class":122},"async_read_until",[79,2105,2106],{"class":126},"(serial_,\n",[79,2108,2110],{"class":81,"line":2109},69,[79,2111,2112],{"class":126},"                                      buffer_,\n",[79,2114,2116,2119,2122,2125],{"class":81,"line":2115},70,[79,2117,2118],{"class":89},"                                      '",[79,2120,2121],{"class":233},"\\n",[79,2123,2124],{"class":89},"'",[79,2126,2127],{"class":126},",\n",[79,2129,2131,2134,2136,2139,2141,2143,2146],{"class":81,"line":2130},71,[79,2132,2133],{"class":122},"                                      std",[79,2135,136],{"class":126},[79,2137,2138],{"class":122},"bind",[79,2140,127],{"class":126},[79,2142,142],{"class":85},[79,2144,2145],{"class":122},"SerialRobotDriver",[79,2147,2148],{"class":126},"::on_read,\n",[79,2150,2152,2155],{"class":81,"line":2151},72,[79,2153,2154],{"class":233},"                                                this",[79,2156,2127],{"class":126},[79,2158,2160,2163,2165,2168],{"class":81,"line":2159},73,[79,2161,2162],{"class":122},"                                                std",[79,2164,136],{"class":126},[79,2166,2167],{"class":122},"placeholders",[79,2169,2170],{"class":126},"::_1,\n",[79,2172,2174,2176,2178,2180],{"class":81,"line":2173},74,[79,2175,2162],{"class":122},[79,2177,136],{"class":126},[79,2179,2167],{"class":122},[79,2181,2182],{"class":126},"::_2));\n",[79,2184,2186],{"class":81,"line":2185},75,[79,2187,349],{"class":126},[79,2189,2191],{"class":81,"line":2190},76,[79,2192,113],{"emptyLinePlaceholder":112},[79,2194,2196,2198,2201,2203,2205,2208,2210,2212,2214,2217,2219,2222,2224,2226,2228,2231,2234],{"class":81,"line":2195},77,[79,2197,896],{"class":85},[79,2199,2200],{"class":122}," on_read",[79,2202,127],{"class":126},[79,2204,130],{"class":85},[79,2206,2207],{"class":122}," boost",[79,2209,136],{"class":126},[79,2211,1925],{"class":122},[79,2213,136],{"class":126},[79,2215,2216],{"class":122},"error_code",[79,2218,142],{"class":85},[79,2220,2221],{"class":145}," ec",[79,2223,1885],{"class":126},[79,2225,1066],{"class":122},[79,2227,136],{"class":126},[79,2229,2230],{"class":85},"size_t",[79,2232,2233],{"class":145}," bytes_transferred",[79,2235,149],{"class":126},[79,2237,2239],{"class":81,"line":2238},78,[79,2240,218],{"class":126},[79,2242,2244,2246],{"class":81,"line":2243},79,[79,2245,951],{"class":85},[79,2247,1950],{"class":126},[79,2249,2251],{"class":81,"line":2250},80,[79,2252,964],{"class":126},[79,2254,2256,2258,2260,2262,2265,2267,2269,2271,2273,2275,2277],{"class":81,"line":2255},81,[79,2257,1021],{"class":122},[79,2259,298],{"class":126},[79,2261,301],{"class":85},[79,2263,2264],{"class":89}," \"串口读取错误：\"",[79,2266,307],{"class":85},[79,2268,1970],{"class":126},[79,2270,1973],{"class":122},[79,2272,1976],{"class":126},[79,2274,301],{"class":85},[79,2276,133],{"class":122},[79,2278,343],{"class":126},[79,2280,2282,2284],{"class":81,"line":2281},82,[79,2283,1987],{"class":85},[79,2285,237],{"class":126},[79,2287,2289],{"class":81,"line":2288},83,[79,2290,977],{"class":126},[79,2292,2294],{"class":81,"line":2293},84,[79,2295,113],{"emptyLinePlaceholder":112},[79,2297,2299,2301,2304,2307,2309,2311],{"class":81,"line":2298},85,[79,2300,295],{"class":122},[79,2302,2303],{"class":126},"::istream ",[79,2305,2306],{"class":122},"is",[79,2308,127],{"class":126},[79,2310,142],{"class":85},[79,2312,2313],{"class":126},"buffer_);\n",[79,2315,2317,2319],{"class":81,"line":2316},86,[79,2318,295],{"class":122},[79,2320,2321],{"class":126},"::string line;\n",[79,2323,2325,2327,2329,2332],{"class":81,"line":2324},87,[79,2326,295],{"class":122},[79,2328,136],{"class":126},[79,2330,2331],{"class":122},"getline",[79,2333,2334],{"class":126},"(is, line);\n",[79,2336,2338],{"class":81,"line":2337},88,[79,2339,113],{"emptyLinePlaceholder":112},[79,2341,2343,2345,2347,2349,2352,2354],{"class":81,"line":2342},89,[79,2344,295],{"class":122},[79,2346,298],{"class":126},[79,2348,301],{"class":85},[79,2350,2351],{"class":89}," \"收到串口行，bytes = \"",[79,2353,307],{"class":85},[79,2355,2356],{"class":126}," bytes_transferred\n",[79,2358,2360,2362,2365,2367,2369,2371,2373],{"class":81,"line":2359},90,[79,2361,316],{"class":85},[79,2363,2364],{"class":89}," \"，line = \"",[79,2366,307],{"class":85},[79,2368,594],{"class":126},[79,2370,301],{"class":85},[79,2372,133],{"class":122},[79,2374,343],{"class":126},[79,2376,2378],{"class":81,"line":2377},91,[79,2379,113],{"emptyLinePlaceholder":112},[79,2381,2383,2386,2388],{"class":81,"line":2382},92,[79,2384,2385],{"class":126},"        parser_.",[79,2387,1330],{"class":122},[79,2389,170],{"class":126},[79,2391,2393],{"class":81,"line":2392},93,[79,2394,113],{"emptyLinePlaceholder":112},[79,2396,2398,2400],{"class":81,"line":2397},94,[79,2399,2060],{"class":122},[79,2401,2063],{"class":126},[79,2403,2405],{"class":81,"line":2404},95,[79,2406,349],{"class":126},[79,2408,2410],{"class":81,"line":2409},96,[79,2411,113],{"emptyLinePlaceholder":112},[79,2413,2415],{"class":81,"line":2414},97,[79,2416,1054],{"class":85},[79,2418,2420],{"class":81,"line":2419},98,[79,2421,2422],{"class":639},"    \u002F\u002F serial_port 表示串口设备，后续读写都通过它完成。\n",[79,2424,2426,2429,2431,2433],{"class":81,"line":2425},99,[79,2427,2428],{"class":122},"    boost",[79,2430,136],{"class":126},[79,2432,1872],{"class":122},[79,2434,2435],{"class":126},"::serial_port serial_;\n",[79,2437,2439,2441,2443,2445],{"class":81,"line":2438},100,[79,2440,2428],{"class":122},[79,2442,136],{"class":126},[79,2444,1872],{"class":122},[79,2446,2447],{"class":126},"::streambuf buffer_;\n",[79,2449,2451],{"class":81,"line":2450},101,[79,2452,2453],{"class":126},"    RobotProtocolParser parser_;\n",[79,2455,2457],{"class":81,"line":2456},102,[79,2458,1272],{"class":126},[79,2460,2462],{"class":81,"line":2461},103,[79,2463,113],{"emptyLinePlaceholder":112},[79,2465,2467,2469,2471,2473,2475,2478,2480,2483,2486],{"class":81,"line":2466},104,[79,2468,622],{"class":85},[79,2470,625],{"class":122},[79,2472,127],{"class":126},[79,2474,622],{"class":85},[79,2476,2477],{"class":145}," argc",[79,2479,1885],{"class":126},[79,2481,2482],{"class":85},"char*",[79,2484,2485],{"class":145}," argv",[79,2487,2488],{"class":126},"[])\n",[79,2490,2492],{"class":81,"line":2491},105,[79,2493,155],{"class":126},[79,2495,2497],{"class":81,"line":2496},106,[79,2498,2499],{"class":639},"    \u002F\u002F 程序从 main 函数开始执行，argc\u002Fargv 用来接收命令行参数。\n",[79,2501,2503,2505,2508,2510,2513],{"class":81,"line":2502},107,[79,2504,161],{"class":122},[79,2506,2507],{"class":126},"::string port_name ",[79,2509,230],{"class":85},[79,2511,2512],{"class":89}," \"\u002Fdev\u002Fpts\u002F3\"",[79,2514,237],{"class":126},[79,2516,2518],{"class":81,"line":2517},108,[79,2519,113],{"emptyLinePlaceholder":112},[79,2521,2523,2525,2528,2531,2534],{"class":81,"line":2522},109,[79,2524,201],{"class":85},[79,2526,2527],{"class":126}," (argc ",[79,2529,2530],{"class":85},">=",[79,2532,2533],{"class":233}," 2",[79,2535,149],{"class":126},[79,2537,2539],{"class":81,"line":2538},110,[79,2540,218],{"class":126},[79,2542,2544,2547,2549,2552,2555],{"class":81,"line":2543},111,[79,2545,2546],{"class":126},"        port_name ",[79,2548,230],{"class":85},[79,2550,2551],{"class":126}," argv[",[79,2553,2554],{"class":233},"1",[79,2556,2557],{"class":126},"];\n",[79,2559,2561],{"class":81,"line":2560},112,[79,2562,349],{"class":126},[79,2564,2566],{"class":81,"line":2565},113,[79,2567,113],{"emptyLinePlaceholder":112},[79,2569,2571],{"class":81,"line":2570},114,[79,2572,2573],{"class":639},"    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n",[79,2575,2577,2579,2581,2583],{"class":81,"line":2576},115,[79,2578,2428],{"class":122},[79,2580,136],{"class":126},[79,2582,1872],{"class":122},[79,2584,2585],{"class":126},"::io_context io;\n",[79,2587,2589,2592,2595],{"class":81,"line":2588},116,[79,2590,2591],{"class":126},"    SerialRobotDriver ",[79,2593,2594],{"class":122},"driver",[79,2596,2597],{"class":126},"(io, port_name);\n",[79,2599,2601],{"class":81,"line":2600},117,[79,2602,113],{"emptyLinePlaceholder":112},[79,2604,2606,2608,2610,2612,2615,2617,2619],{"class":81,"line":2605},118,[79,2607,161],{"class":122},[79,2609,298],{"class":126},[79,2611,301],{"class":85},[79,2613,2614],{"class":89}," \"main：开始 io.run()\"",[79,2616,307],{"class":85},[79,2618,133],{"class":122},[79,2620,343],{"class":126},[79,2622,2624],{"class":81,"line":2623},119,[79,2625,113],{"emptyLinePlaceholder":112},[79,2627,2629],{"class":81,"line":2628},120,[79,2630,2631],{"class":639},"    \u002F\u002F 启动事件循环，前面注册的异步任务会在这里被调度执行。\n",[79,2633,2635,2638,2641],{"class":81,"line":2634},121,[79,2636,2637],{"class":126},"    io.",[79,2639,2640],{"class":122},"run",[79,2642,2063],{"class":126},[79,2644,2646],{"class":81,"line":2645},122,[79,2647,113],{"emptyLinePlaceholder":112},[79,2649,2651,2653,2655,2657,2660,2662,2664],{"class":81,"line":2650},123,[79,2652,161],{"class":122},[79,2654,298],{"class":126},[79,2656,301],{"class":85},[79,2658,2659],{"class":89}," \"main：io.run() 返回\"",[79,2661,307],{"class":85},[79,2663,133],{"class":122},[79,2665,343],{"class":126},[79,2667,2669],{"class":81,"line":2668},124,[79,2670,113],{"emptyLinePlaceholder":112},[79,2672,2674,2676,2678],{"class":81,"line":2673},125,[79,2675,753],{"class":85},[79,2677,756],{"class":233},[79,2679,237],{"class":126},[79,2681,2683],{"class":81,"line":2682},126,[79,2684,611],{"class":126},[13,2686,2687,770],{},[767,2688,769],{},[49,2690,774],{"id":2691},"compile-and-run-2",[13,2693,2694],{},"Terminal 1: Create virtual serial port.",[20,2696,2698],{"className":777,"code":2697,"language":779,"meta":26,"style":26},"socat -d -d pty,raw,echo=0 pty,raw,echo=0\n",[28,2699,2700],{"__ignoreMap":26},[79,2701,2702,2705,2708,2710,2713,2716,2718],{"class":81,"line":82},[79,2703,2704],{"class":122},"socat",[79,2706,2707],{"class":233}," -d",[79,2709,2707],{"class":233},[79,2711,2712],{"class":89}," pty,raw,echo=",[79,2714,2715],{"class":233},"0",[79,2717,2712],{"class":89},[79,2719,2720],{"class":233},"0\n",[13,2722,2723],{},"Terminal 2: Run the program.",[20,2725,2727],{"className":777,"code":2726,"language":779,"meta":26,"style":26},"g++ demo3_serial_robot_driver.cpp -o demo3_serial_robot_driver -std=c++17 -lboost_system -pthread\n.\u002Fdemo3_serial_robot_driver \u002Fdev\u002Fpts\u002F3\n",[28,2728,2729,2750],{"__ignoreMap":26},[79,2730,2731,2733,2736,2738,2741,2744,2747],{"class":81,"line":82},[79,2732,786],{"class":122},[79,2734,2735],{"class":89}," demo3_serial_robot_driver.cpp",[79,2737,792],{"class":233},[79,2739,2740],{"class":89}," demo3_serial_robot_driver",[79,2742,2743],{"class":233}," -std=c++17",[79,2745,2746],{"class":233}," -lboost_system",[79,2748,2749],{"class":233}," -pthread\n",[79,2751,2752,2755],{"class":81,"line":93},[79,2753,2754],{"class":122},".\u002Fdemo3_serial_robot_driver",[79,2756,2757],{"class":89}," \u002Fdev\u002Fpts\u002F3\n",[13,2759,2760],{},"Terminal 3: Send simulated lower-level device data.",[20,2762,2764],{"className":777,"code":2763,"language":779,"meta":26,"style":26},"echo \"ODOM 1.0 2.0 0.5\" > \u002Fdev\u002Fpts\u002F4\necho \"BAT 24.2\" > \u002Fdev\u002Fpts\u002F4\n",[28,2765,2766,2780],{"__ignoreMap":26},[79,2767,2768,2771,2774,2777],{"class":81,"line":82},[79,2769,2770],{"class":233},"echo",[79,2772,2773],{"class":89}," \"ODOM 1.0 2.0 0.5\"",[79,2775,2776],{"class":85}," >",[79,2778,2779],{"class":89}," \u002Fdev\u002Fpts\u002F4\n",[79,2781,2782,2784,2787,2789],{"class":81,"line":93},[79,2783,2770],{"class":233},[79,2785,2786],{"class":89}," \"BAT 24.2\"",[79,2788,2776],{"class":85},[79,2790,2779],{"class":89},[49,2792,2794],{"id":2793},"execution-output-and-chronological-order","Execution output and chronological order",[13,2796,2797],{},"After the program starts, it outputs:",[20,2799,2802],{"className":2800,"code":2801,"language":25,"meta":26},[23],"SerialRobotDriver：串口打开成功\nmain：开始 io.run()\n",[28,2803,2801],{"__ignoreMap":26},[13,2805,2806],{},"After sending the first line, output:",[20,2808,2811],{"className":2809,"code":2810,"language":25,"meta":26},[23],"收到串口行，bytes = 17，line = ODOM 1.0 2.0 0.5\n解析 ODOM：x = 1，y = 2，yaw = 0.5\n",[28,2812,2810],{"__ignoreMap":26},[13,2814,2815],{},"I understand you're giving an instruction, but it seems you might be asking me to translate a Chinese Markdown fragment. However, \"发送第二行后输出：\" is not a Markdown fragment itself. Could you please provide the actual Chinese Markdown text you'd like me to translate into natural American English? I'll then follow the guidelines you provided.",[20,2817,2820],{"className":2818,"code":2819,"language":25,"meta":26},[23],"收到串口行，bytes = 9，line = BAT 24.2\n解析 BAT：24.2 V\n",[28,2821,2819],{"__ignoreMap":26},[49,2823,817],{"id":2824},"points-to-note-for-this-example-2",[13,2826,2827],{},"This is a minimal robot serial port driver prototype.",[13,2829,2830],{},"But it hasn't been done yet:",[2832,2833,2834,2838,2841,2844,2847,2850],"ol",{},[2835,2836,2837],"li",{},"Serial port disconnect and reconnect;",[2835,2839,2840],{},"Binary frame parsing;",[2835,2842,2843],{},"CRC check;",[2835,2845,2846],{},"Convert data to ROS2 topic",[2835,2848,2849],{},"Write back cmd_vel to the electrical control;",[2835,2851,2852],{},"Thread safety.",[13,2854,2855],{},"These can be added further onto this structure.",[38,2857],{},[41,2859,2861],{"id":2860},"example-4-recommended-structure-for-using-asio-in-a-ros2-node","Example 4: Recommended structure for using Asio in a ROS2 node",[49,2863,52],{"id":2864},"program-objective-3",[13,2866,2867],{},"This example shows the recommended structure; it doesn't require you to run it fully right now.",[13,2869,2870],{},"Recommended Approach:",[20,2872,2875],{"className":2873,"code":2874,"language":25,"meta":26},[23],"ROS2 节点线程：负责 rclcpp::spin()\nAsio 线程：负责 io_context.run()\n串口回调：收到数据后更新成员变量或 post 给 ROS2 逻辑\nROS2 timer：定期发布 odom \u002F battery \u002F imu\n",[28,2876,2874],{"__ignoreMap":26},[49,2878,2880],{"id":2879},"code-skeleton","code skeleton",[20,2882,2884],{"className":73,"code":2883,"language":75,"meta":26,"style":26},"#include \u003Cboost\u002Fasio.hpp>\n#include \u003Cfunctional>\n#include \u003Ciostream>\n#include \u003Cmemory>\n#include \u003Cstring>\n#include \u003Cthread>\n\n#include \u003Crclcpp\u002Frclcpp.hpp>\n#include \u003Cstd_msgs\u002Fmsg\u002Fstring.hpp>\n\nclass RobotNode : public rclcpp::Node\n{\npublic:\n    RobotNode()\n        : Node(\"robot_node\"),\n          guard_(boost::asio::make_work_guard(io_))\n    {\n        publisher_ = this->create_publisher\u003Cstd_msgs::msg::String>(\"robot_status\", 10);\n\n        ros_timer_ = this->create_wall_timer(\n            std::chrono::seconds(1),\n            std::bind(&RobotNode::on_ros_timer, this));\n\n        asio_thread_ = std::thread(std::bind(&RobotNode::run_asio, this));\n\n        std::cout \u003C\u003C \"RobotNode：启动完成\" \u003C\u003C std::endl;\n    }\n\n    ~RobotNode()\n    {\n        guard_.reset();\n        io_.stop();\n\n        if (asio_thread_.joinable())\n        {\n            asio_thread_.join();\n        }\n    }\n\nprivate:\n    void run_asio()\n    {\n        std::cout \u003C\u003C \"Asio 线程：io.run() 开始\" \u003C\u003C std::endl;\n        \u002F\u002F 启动事件循环，前面注册的异步任务会在这里被调度执行。\n        io_.run();\n        std::cout \u003C\u003C \"Asio 线程：io.run() 返回\" \u003C\u003C std::endl;\n    }\n\n    void on_ros_timer()\n    {\n        std_msgs::msg::String msg;\n        msg.data = \"robot alive\";\n        publisher_->publish(msg);\n\n        RCLCPP_INFO(this->get_logger(), \"publish: %s\", msg.data.c_str());\n    }\n\nprivate:\n    \u002F\u002F io_context 是 Asio 的事件循环对象，异步任务需要靠它调度。\n    boost::asio::io_context io_;\n    boost::asio::executor_work_guard\u003Cboost::asio::io_context::executor_type> guard_;\n    \u002F\u002F 创建子线程，让这部分代码和 main 线程并发运行。\n    std::thread asio_thread_;\n\n    rclcpp::Publisher\u003Cstd_msgs::msg::String>::SharedPtr publisher_;\n    rclcpp::TimerBase::SharedPtr ros_timer_;\n};\n\nint main(int argc, char* argv[])\n{\n    \u002F\u002F 程序从 main 函数开始执行，argc\u002Fargv 用来接收命令行参数。\n    rclcpp::init(argc, argv);\n\n    std::shared_ptr\u003CRobotNode> node = std::make_shared\u003CRobotNode>();\n\n    rclcpp::spin(node);\n\n    rclcpp::shutdown();\n\n    return 0;\n}\n",[28,2885,2886,2892,2898,2904,2911,2917,2924,2928,2935,2942,2946,2967,2971,2975,2982,2997,3018,3022,3064,3068,3086,3106,3129,3133,3168,3172,3189,3193,3197,3204,3208,3218,3228,3232,3245,3249,3259,3263,3267,3271,3275,3284,3288,3305,3310,3318,3335,3339,3343,3352,3356,3368,3380,3391,3395,3430,3434,3438,3442,3446,3457,3488,3493,3500,3504,3530,3542,3546,3550,3570,3574,3578,3590,3594,3626,3630,3642,3646,3657,3661,3669],{"__ignoreMap":26},[79,2887,2888,2890],{"class":81,"line":82},[79,2889,86],{"class":85},[79,2891,1495],{"class":89},[79,2893,2894,2896],{"class":81,"line":93},[79,2895,86],{"class":85},[79,2897,1509],{"class":89},[79,2899,2900,2902],{"class":81,"line":101},[79,2901,86],{"class":85},[79,2903,90],{"class":89},[79,2905,2906,2908],{"class":81,"line":109},[79,2907,86],{"class":85},[79,2909,2910],{"class":89}," \u003Cmemory>\n",[79,2912,2913,2915],{"class":81,"line":116},[79,2914,86],{"class":85},[79,2916,106],{"class":89},[79,2918,2919,2921],{"class":81,"line":152},[79,2920,86],{"class":85},[79,2922,2923],{"class":89}," \u003Cthread>\n",[79,2925,2926],{"class":81,"line":158},[79,2927,113],{"emptyLinePlaceholder":112},[79,2929,2930,2932],{"class":81,"line":173},[79,2931,86],{"class":85},[79,2933,2934],{"class":89}," \u003Crclcpp\u002Frclcpp.hpp>\n",[79,2936,2937,2939],{"class":81,"line":181},[79,2938,86],{"class":85},[79,2940,2941],{"class":89}," \u003Cstd_msgs\u002Fmsg\u002Fstring.hpp>\n",[79,2943,2944],{"class":81,"line":193},[79,2945,113],{"emptyLinePlaceholder":112},[79,2947,2948,2950,2953,2956,2959,2962,2964],{"class":81,"line":198},[79,2949,879],{"class":85},[79,2951,2952],{"class":122}," RobotNode",[79,2954,2955],{"class":126}," : ",[79,2957,2958],{"class":85},"public",[79,2960,2961],{"class":122}," rclcpp",[79,2963,136],{"class":126},[79,2965,2966],{"class":122},"Node\n",[79,2968,2969],{"class":81,"line":215},[79,2970,155],{"class":126},[79,2972,2973],{"class":81,"line":221},[79,2974,891],{"class":85},[79,2976,2977,2980],{"class":81,"line":240},[79,2978,2979],{"class":122},"    RobotNode",[79,2981,628],{"class":126},[79,2983,2984,2986,2989,2991,2994],{"class":81,"line":254},[79,2985,1905],{"class":126},[79,2987,2988],{"class":122},"Node",[79,2990,127],{"class":126},[79,2992,2993],{"class":89},"\"robot_node\"",[79,2995,2996],{"class":126},"),\n",[79,2998,2999,3002,3004,3006,3008,3010,3012,3015],{"class":81,"line":268},[79,3000,3001],{"class":122},"          guard_",[79,3003,127],{"class":126},[79,3005,1867],{"class":122},[79,3007,136],{"class":126},[79,3009,1872],{"class":122},[79,3011,136],{"class":126},[79,3013,3014],{"class":122},"make_work_guard",[79,3016,3017],{"class":126},"(io_))\n",[79,3019,3020],{"class":81,"line":287},[79,3021,218],{"class":126},[79,3023,3024,3027,3029,3032,3035,3038,3041,3043,3046,3049,3052,3054,3057,3059,3062],{"class":81,"line":292},[79,3025,3026],{"class":126},"        publisher_ ",[79,3028,230],{"class":85},[79,3030,3031],{"class":233}," this",[79,3033,3034],{"class":126},"->create_publisher",[79,3036,3037],{"class":85},"\u003C",[79,3039,3040],{"class":122},"std_msgs",[79,3042,136],{"class":126},[79,3044,3045],{"class":122},"msg",[79,3047,3048],{"class":126},"::String",[79,3050,3051],{"class":85},">",[79,3053,127],{"class":126},[79,3055,3056],{"class":89},"\"robot_status\"",[79,3058,1885],{"class":126},[79,3060,3061],{"class":233},"10",[79,3063,677],{"class":126},[79,3065,3066],{"class":81,"line":313},[79,3067,113],{"emptyLinePlaceholder":112},[79,3069,3070,3073,3075,3077,3080,3083],{"class":81,"line":327},[79,3071,3072],{"class":126},"        ros_timer_ ",[79,3074,230],{"class":85},[79,3076,3031],{"class":233},[79,3078,3079],{"class":126},"->",[79,3081,3082],{"class":122},"create_wall_timer",[79,3084,3085],{"class":126},"(\n",[79,3087,3088,3090,3092,3095,3097,3100,3102,3104],{"class":81,"line":346},[79,3089,1021],{"class":122},[79,3091,136],{"class":126},[79,3093,3094],{"class":122},"chrono",[79,3096,136],{"class":126},[79,3098,3099],{"class":122},"seconds",[79,3101,127],{"class":126},[79,3103,2554],{"class":233},[79,3105,2996],{"class":126},[79,3107,3108,3110,3112,3114,3116,3118,3121,3124,3127],{"class":81,"line":352},[79,3109,1021],{"class":122},[79,3111,136],{"class":126},[79,3113,2138],{"class":122},[79,3115,127],{"class":126},[79,3117,142],{"class":85},[79,3119,3120],{"class":122},"RobotNode",[79,3122,3123],{"class":126},"::on_ros_timer, ",[79,3125,3126],{"class":233},"this",[79,3128,2030],{"class":126},[79,3130,3131],{"class":81,"line":370},[79,3132,113],{"emptyLinePlaceholder":112},[79,3134,3135,3138,3140,3142,3144,3147,3149,3151,3153,3155,3157,3159,3161,3164,3166],{"class":81,"line":375},[79,3136,3137],{"class":126},"        asio_thread_ ",[79,3139,230],{"class":85},[79,3141,133],{"class":122},[79,3143,136],{"class":126},[79,3145,3146],{"class":122},"thread",[79,3148,127],{"class":126},[79,3150,1066],{"class":122},[79,3152,136],{"class":126},[79,3154,2138],{"class":122},[79,3156,127],{"class":126},[79,3158,142],{"class":85},[79,3160,3120],{"class":122},[79,3162,3163],{"class":126},"::run_asio, ",[79,3165,3126],{"class":233},[79,3167,2030],{"class":126},[79,3169,3170],{"class":81,"line":389},[79,3171,113],{"emptyLinePlaceholder":112},[79,3173,3174,3176,3178,3180,3183,3185,3187],{"class":81,"line":399},[79,3175,295],{"class":122},[79,3177,298],{"class":126},[79,3179,301],{"class":85},[79,3181,3182],{"class":89}," \"RobotNode：启动完成\"",[79,3184,307],{"class":85},[79,3186,133],{"class":122},[79,3188,343],{"class":126},[79,3190,3191],{"class":81,"line":404},[79,3192,349],{"class":126},[79,3194,3195],{"class":81,"line":431},[79,3196,113],{"emptyLinePlaceholder":112},[79,3198,3199,3202],{"class":81,"line":436},[79,3200,3201],{"class":122},"    ~RobotNode",[79,3203,628],{"class":126},[79,3205,3206],{"class":81,"line":452},[79,3207,218],{"class":126},[79,3209,3210,3213,3216],{"class":81,"line":457},[79,3211,3212],{"class":126},"        guard_.",[79,3214,3215],{"class":122},"reset",[79,3217,2063],{"class":126},[79,3219,3220,3223,3226],{"class":81,"line":471},[79,3221,3222],{"class":126},"        io_.",[79,3224,3225],{"class":122},"stop",[79,3227,2063],{"class":126},[79,3229,3230],{"class":81,"line":485},[79,3231,113],{"emptyLinePlaceholder":112},[79,3233,3234,3236,3239,3242],{"class":81,"line":499},[79,3235,951],{"class":85},[79,3237,3238],{"class":126}," (asio_thread_.",[79,3240,3241],{"class":122},"joinable",[79,3243,3244],{"class":126},"())\n",[79,3246,3247],{"class":81,"line":517},[79,3248,964],{"class":126},[79,3250,3251,3254,3257],{"class":81,"line":522},[79,3252,3253],{"class":126},"            asio_thread_.",[79,3255,3256],{"class":122},"join",[79,3258,2063],{"class":126},[79,3260,3261],{"class":81,"line":534},[79,3262,977],{"class":126},[79,3264,3265],{"class":81,"line":564},[79,3266,349],{"class":126},[79,3268,3269],{"class":81,"line":569},[79,3270,113],{"emptyLinePlaceholder":112},[79,3272,3273],{"class":81,"line":575},[79,3274,1054],{"class":85},[79,3276,3277,3279,3282],{"class":81,"line":580},[79,3278,896],{"class":85},[79,3280,3281],{"class":122}," run_asio",[79,3283,628],{"class":126},[79,3285,3286],{"class":81,"line":603},[79,3287,218],{"class":126},[79,3289,3290,3292,3294,3296,3299,3301,3303],{"class":81,"line":608},[79,3291,295],{"class":122},[79,3293,298],{"class":126},[79,3295,301],{"class":85},[79,3297,3298],{"class":89}," \"Asio 线程：io.run() 开始\"",[79,3300,307],{"class":85},[79,3302,133],{"class":122},[79,3304,343],{"class":126},[79,3306,3307],{"class":81,"line":614},[79,3308,3309],{"class":639},"        \u002F\u002F 启动事件循环，前面注册的异步任务会在这里被调度执行。\n",[79,3311,3312,3314,3316],{"class":81,"line":619},[79,3313,3222],{"class":126},[79,3315,2640],{"class":122},[79,3317,2063],{"class":126},[79,3319,3320,3322,3324,3326,3329,3331,3333],{"class":81,"line":631},[79,3321,295],{"class":122},[79,3323,298],{"class":126},[79,3325,301],{"class":85},[79,3327,3328],{"class":89}," \"Asio 线程：io.run() 返回\"",[79,3330,307],{"class":85},[79,3332,133],{"class":122},[79,3334,343],{"class":126},[79,3336,3337],{"class":81,"line":636},[79,3338,349],{"class":126},[79,3340,3341],{"class":81,"line":643},[79,3342,113],{"emptyLinePlaceholder":112},[79,3344,3345,3347,3350],{"class":81,"line":661},[79,3346,896],{"class":85},[79,3348,3349],{"class":122}," on_ros_timer",[79,3351,628],{"class":126},[79,3353,3354],{"class":81,"line":666},[79,3355,218],{"class":126},[79,3357,3358,3361,3363,3365],{"class":81,"line":680},[79,3359,3360],{"class":122},"        std_msgs",[79,3362,136],{"class":126},[79,3364,3045],{"class":122},[79,3366,3367],{"class":126},"::String msg;\n",[79,3369,3370,3373,3375,3378],{"class":81,"line":692},[79,3371,3372],{"class":126},"        msg.data ",[79,3374,230],{"class":85},[79,3376,3377],{"class":89}," \"robot alive\"",[79,3379,237],{"class":126},[79,3381,3382,3385,3388],{"class":81,"line":704},[79,3383,3384],{"class":126},"        publisher_->",[79,3386,3387],{"class":122},"publish",[79,3389,3390],{"class":126},"(msg);\n",[79,3392,3393],{"class":81,"line":716},[79,3394,113],{"emptyLinePlaceholder":112},[79,3396,3397,3400,3402,3404,3406,3409,3412,3415,3418,3421,3424,3427],{"class":81,"line":721},[79,3398,3399],{"class":122},"        RCLCPP_INFO",[79,3401,127],{"class":126},[79,3403,3126],{"class":233},[79,3405,3079],{"class":126},[79,3407,3408],{"class":122},"get_logger",[79,3410,3411],{"class":126},"(), ",[79,3413,3414],{"class":89},"\"publish: ",[79,3416,3417],{"class":233},"%s",[79,3419,3420],{"class":89},"\"",[79,3422,3423],{"class":126},", msg.data.",[79,3425,3426],{"class":122},"c_str",[79,3428,3429],{"class":126},"());\n",[79,3431,3432],{"class":81,"line":739},[79,3433,349],{"class":126},[79,3435,3436],{"class":81,"line":744},[79,3437,113],{"emptyLinePlaceholder":112},[79,3439,3440],{"class":81,"line":750},[79,3441,1054],{"class":85},[79,3443,3444],{"class":81,"line":761},[79,3445,2573],{"class":639},[79,3447,3448,3450,3452,3454],{"class":81,"line":1353},[79,3449,2428],{"class":122},[79,3451,136],{"class":126},[79,3453,1872],{"class":122},[79,3455,3456],{"class":126},"::io_context io_;\n",[79,3458,3459,3461,3463,3465,3468,3470,3472,3474,3476,3478,3480,3483,3485],{"class":81,"line":1367},[79,3460,2428],{"class":122},[79,3462,136],{"class":126},[79,3464,1872],{"class":122},[79,3466,3467],{"class":126},"::executor_work_guard",[79,3469,3037],{"class":85},[79,3471,1867],{"class":122},[79,3473,136],{"class":126},[79,3475,1872],{"class":122},[79,3477,136],{"class":126},[79,3479,1877],{"class":122},[79,3481,3482],{"class":126},"::executor_type",[79,3484,3051],{"class":85},[79,3486,3487],{"class":126}," guard_;\n",[79,3489,3490],{"class":81,"line":1372},[79,3491,3492],{"class":639},"    \u002F\u002F 创建子线程，让这部分代码和 main 线程并发运行。\n",[79,3494,3495,3497],{"class":81,"line":1389},[79,3496,161],{"class":122},[79,3498,3499],{"class":126},"::thread asio_thread_;\n",[79,3501,3502],{"class":81,"line":1394},[79,3503,113],{"emptyLinePlaceholder":112},[79,3505,3506,3509,3511,3514,3516,3518,3520,3522,3524,3527],{"class":81,"line":1399},[79,3507,3508],{"class":122},"    rclcpp",[79,3510,136],{"class":126},[79,3512,3513],{"class":122},"Publisher",[79,3515,3037],{"class":126},[79,3517,3040],{"class":122},[79,3519,136],{"class":126},[79,3521,3045],{"class":122},[79,3523,136],{"class":126},[79,3525,3526],{"class":122},"String",[79,3528,3529],{"class":126},">::SharedPtr publisher_;\n",[79,3531,3532,3534,3536,3539],{"class":81,"line":1408},[79,3533,3508],{"class":122},[79,3535,136],{"class":126},[79,3537,3538],{"class":122},"TimerBase",[79,3540,3541],{"class":126},"::SharedPtr ros_timer_;\n",[79,3543,3544],{"class":81,"line":2087},[79,3545,1272],{"class":126},[79,3547,3548],{"class":81,"line":2092},[79,3549,113],{"emptyLinePlaceholder":112},[79,3551,3552,3554,3556,3558,3560,3562,3564,3566,3568],{"class":81,"line":2109},[79,3553,622],{"class":85},[79,3555,625],{"class":122},[79,3557,127],{"class":126},[79,3559,622],{"class":85},[79,3561,2477],{"class":145},[79,3563,1885],{"class":126},[79,3565,2482],{"class":85},[79,3567,2485],{"class":145},[79,3569,2488],{"class":126},[79,3571,3572],{"class":81,"line":2115},[79,3573,155],{"class":126},[79,3575,3576],{"class":81,"line":2130},[79,3577,2499],{"class":639},[79,3579,3580,3582,3584,3587],{"class":81,"line":2151},[79,3581,3508],{"class":122},[79,3583,136],{"class":126},[79,3585,3586],{"class":122},"init",[79,3588,3589],{"class":126},"(argc, argv);\n",[79,3591,3592],{"class":81,"line":2159},[79,3593,113],{"emptyLinePlaceholder":112},[79,3595,3596,3598,3601,3603,3605,3607,3610,3612,3614,3616,3619,3621,3623],{"class":81,"line":2173},[79,3597,161],{"class":122},[79,3599,3600],{"class":126},"::shared_ptr",[79,3602,3037],{"class":85},[79,3604,3120],{"class":126},[79,3606,3051],{"class":85},[79,3608,3609],{"class":126}," node ",[79,3611,230],{"class":85},[79,3613,133],{"class":122},[79,3615,136],{"class":126},[79,3617,3618],{"class":122},"make_shared",[79,3620,3037],{"class":126},[79,3622,3120],{"class":122},[79,3624,3625],{"class":126},">();\n",[79,3627,3628],{"class":81,"line":2185},[79,3629,113],{"emptyLinePlaceholder":112},[79,3631,3632,3634,3636,3639],{"class":81,"line":2190},[79,3633,3508],{"class":122},[79,3635,136],{"class":126},[79,3637,3638],{"class":122},"spin",[79,3640,3641],{"class":126},"(node);\n",[79,3643,3644],{"class":81,"line":2195},[79,3645,113],{"emptyLinePlaceholder":112},[79,3647,3648,3650,3652,3655],{"class":81,"line":2238},[79,3649,3508],{"class":122},[79,3651,136],{"class":126},[79,3653,3654],{"class":122},"shutdown",[79,3656,2063],{"class":126},[79,3658,3659],{"class":81,"line":2243},[79,3660,113],{"emptyLinePlaceholder":112},[79,3662,3663,3665,3667],{"class":81,"line":2250},[79,3664,753],{"class":85},[79,3666,756],{"class":233},[79,3668,237],{"class":126},[79,3670,3671],{"class":81,"line":2255},[79,3672,611],{"class":126},[49,3674,3676],{"id":3675},"typical-runtime-output-and-time-sequence","Typical Runtime Output and Time Sequence",[13,3678,3679],{},"After the node starts, output similar to:",[20,3681,3684],{"className":3682,"code":3683,"language":25,"meta":26},[23],"RobotNode：启动完成\nAsio 线程：io.run() 开始\n",[28,3685,3683],{"__ignoreMap":26},[13,3687,3688],{},"Afterwards, the ROS2 timer outputs once every second:",[20,3690,3693],{"className":3691,"code":3692,"language":25,"meta":26},[23],"[INFO] [robot_node]: publish: robot alive\n[INFO] [robot_node]: publish: robot alive\n[INFO] [robot_node]: publish: robot alive\n",[28,3694,3692],{"__ignoreMap":26},[13,3696,3697],{},"After pressing Ctrl+C to exit:",[20,3699,3702],{"className":3700,"code":3701,"language":25,"meta":26},[23],"Asio 线程：io.run() 返回\n",[28,3703,3701],{"__ignoreMap":26},[49,3705,817],{"id":3706},"points-to-note-for-this-example-3",[13,3708,3709],{},"ROS2 also has timer:",[20,3711,3713],{"className":73,"code":3712,"language":75,"meta":26,"style":26},"create_wall_timer(...)\n",[28,3714,3715],{"__ignoreMap":26},[79,3716,3717,3719],{"class":81,"line":82},[79,3718,3082],{"class":122},[79,3720,3721],{"class":126},"(...)\n",[13,3723,3724],{},"Boost.Asio also has a timer:",[20,3726,3728],{"className":73,"code":3727,"language":75,"meta":26,"style":26},"boost::asio::steady_timer\n",[28,3729,3730],{"__ignoreMap":26},[79,3731,3732,3734,3736,3738],{"class":81,"line":82},[79,3733,1867],{"class":122},[79,3735,136],{"class":126},[79,3737,1872],{"class":122},[79,3739,3740],{"class":126},"::steady_timer\n",[13,3742,3743],{},"They are not the same thing.",[13,3745,3746],{},"General Advice:",[20,3748,3751],{"className":3749,"code":3750,"language":25,"meta":26},[23],"ROS2 周期发布 topic -> 用 ROS2 timer\n串口\u002FTCP\u002FUDP 超时、重连、心跳 -> 用 Asio timer\n",[28,3752,3750],{"__ignoreMap":26},[49,3754,3756],{"id":3755},"why-you-should-not-block-reading-the-serial-port-inside-a-ros2-callback","Why you should not block reading the serial port inside a ROS2 callback",[13,3758,3759],{},"Don't be like this:",[20,3761,3764],{"className":3762,"code":3763,"language":25,"meta":26},[23],"订阅 cmd_vel 的回调里\n直接 while 循环 read 串口\n",[28,3765,3763],{"__ignoreMap":26},[13,3767,3768],{},"Because the ROS2 executor may be blocked by you, other topics, timers, and services will be affected.",[13,3770,3771],{},"A better way is:",[20,3773,3776],{"className":3774,"code":3775,"language":25,"meta":26},[23],"Asio 负责异步收发\nROS2 回调只把命令投递给 Asio 模块\n",[28,3777,3775],{"__ignoreMap":26},[38,3779],{},[41,3781,3783],{"id":3782},"example-5-submitting-tasks-to-asio-in-a-ros2-callback","Example 5: Submitting tasks to Asio in a ROS2 callback",[49,3785,52],{"id":3786},"program-objective-4",[13,3788,3789],{},"Show a common structure: after ROS2 receives a command, it does not directly write to the serial port, but instead submits the write operation to the Asio thread.",[49,3791,3793],{"id":3792},"code-snippet","code snippet",[20,3795,3797],{"className":73,"code":3796,"language":75,"meta":26,"style":26},"void on_cmd_vel(const std_msgs::msg::String::SharedPtr msg)\n{\n    std::string command = msg->data + \"\\n\";\n\n    boost::asio::post(io_,\n                      std::bind(&RobotNode::send_command_in_asio_thread,\n                                this,\n                                command));\n}\n\nvoid send_command_in_asio_thread(const std::string& command)\n{\n    std::cout \u003C\u003C \"Asio 线程中发送命令：\" \u003C\u003C command;\n\n    \u002F\u002F 这里调用 SerialWriter::async_send(command)\n    \u002F\u002F 或者调用你自己的串口驱动发送队列\n}\n",[28,3798,3799,3831,3835,3859,3863,3879,3897,3904,3909,3913,3917,3941,3945,3961,3965,3970,3975],{"__ignoreMap":26},[79,3800,3801,3803,3806,3808,3810,3813,3815,3817,3819,3821,3823,3826,3829],{"class":81,"line":82},[79,3802,119],{"class":85},[79,3804,3805],{"class":122}," on_cmd_vel",[79,3807,127],{"class":126},[79,3809,130],{"class":85},[79,3811,3812],{"class":122}," std_msgs",[79,3814,136],{"class":126},[79,3816,3045],{"class":122},[79,3818,136],{"class":126},[79,3820,3526],{"class":122},[79,3822,136],{"class":126},[79,3824,3825],{"class":122},"SharedPtr",[79,3827,3828],{"class":145}," msg",[79,3830,149],{"class":126},[79,3832,3833],{"class":81,"line":93},[79,3834,155],{"class":126},[79,3836,3837,3839,3842,3844,3847,3850,3853,3855,3857],{"class":81,"line":101},[79,3838,161],{"class":122},[79,3840,3841],{"class":126},"::string command ",[79,3843,230],{"class":85},[79,3845,3846],{"class":126}," msg->data ",[79,3848,3849],{"class":85},"+",[79,3851,3852],{"class":89}," \"",[79,3854,2121],{"class":233},[79,3856,3420],{"class":89},[79,3858,237],{"class":126},[79,3860,3861],{"class":81,"line":109},[79,3862,113],{"emptyLinePlaceholder":112},[79,3864,3865,3867,3869,3871,3873,3876],{"class":81,"line":116},[79,3866,2428],{"class":122},[79,3868,136],{"class":126},[79,3870,1872],{"class":122},[79,3872,136],{"class":126},[79,3874,3875],{"class":122},"post",[79,3877,3878],{"class":126},"(io_,\n",[79,3880,3881,3884,3886,3888,3890,3892,3894],{"class":81,"line":152},[79,3882,3883],{"class":122},"                      std",[79,3885,136],{"class":126},[79,3887,2138],{"class":122},[79,3889,127],{"class":126},[79,3891,142],{"class":85},[79,3893,3120],{"class":122},[79,3895,3896],{"class":126},"::send_command_in_asio_thread,\n",[79,3898,3899,3902],{"class":81,"line":158},[79,3900,3901],{"class":233},"                                this",[79,3903,2127],{"class":126},[79,3905,3906],{"class":81,"line":173},[79,3907,3908],{"class":126},"                                command));\n",[79,3910,3911],{"class":81,"line":181},[79,3912,611],{"class":126},[79,3914,3915],{"class":81,"line":193},[79,3916,113],{"emptyLinePlaceholder":112},[79,3918,3919,3921,3924,3926,3928,3930,3932,3934,3936,3939],{"class":81,"line":198},[79,3920,119],{"class":85},[79,3922,3923],{"class":122}," send_command_in_asio_thread",[79,3925,127],{"class":126},[79,3927,130],{"class":85},[79,3929,133],{"class":122},[79,3931,136],{"class":126},[79,3933,139],{"class":122},[79,3935,142],{"class":85},[79,3937,3938],{"class":145}," command",[79,3940,149],{"class":126},[79,3942,3943],{"class":81,"line":215},[79,3944,155],{"class":126},[79,3946,3947,3949,3951,3953,3956,3958],{"class":81,"line":221},[79,3948,161],{"class":122},[79,3950,298],{"class":126},[79,3952,301],{"class":85},[79,3954,3955],{"class":89}," \"Asio 线程中发送命令：\"",[79,3957,307],{"class":85},[79,3959,3960],{"class":126}," command;\n",[79,3962,3963],{"class":81,"line":240},[79,3964,113],{"emptyLinePlaceholder":112},[79,3966,3967],{"class":81,"line":254},[79,3968,3969],{"class":639},"    \u002F\u002F 这里调用 SerialWriter::async_send(command)\n",[79,3971,3972],{"class":81,"line":268},[79,3973,3974],{"class":639},"    \u002F\u002F 或者调用你自己的串口驱动发送队列\n",[79,3976,3977],{"class":81,"line":287},[79,3978,611],{"class":126},[49,3980,3982],{"id":3981},"typical-output-and-time-sequence","Typical Output and Time Sequence",[13,3984,3985],{},"When ROS2 receives a command:",[20,3987,3990],{"className":3988,"code":3989,"language":25,"meta":26},[23],"cmd_vel 0.2 0.0\n",[28,3991,3989],{"__ignoreMap":26},[13,3993,3994],{},"The ROS2 callback thread immediately dispatches the task. Then the Asio thread executes:",[20,3996,3999],{"className":3997,"code":3998,"language":25,"meta":26},[23],"Asio 线程中发送命令：cmd_vel 0.2 0.0\n",[28,4000,3998],{"__ignoreMap":26},[49,4002,817],{"id":4003},"points-to-note-for-this-example-4",[13,4005,4006,4009],{},[28,4007,4008],{},"boost::asio::post()"," can safely deliver tasks to the Asio event loop.",[13,4011,4012],{},"If your serial port object is only accessed within the Asio thread, then many locking issues can be reduced.",[38,4014],{},[41,4016,4018],{"id":4017},"recommended-layering-in-robot-engineering","Recommended Layering in Robot Engineering",[13,4020,4021],{},"Recommended structure:",[20,4023,4026],{"className":4024,"code":4025,"language":25,"meta":26},[23],"RobotNode                  ROS2 节点层\n├── SerialRobotDriver      串口通信层\n│   ├── async_read_until   异步读取\n│   ├── write_queue        异步写队列\n│   └── steady_timer       超时\u002F心跳\u002F重连\n├── RobotProtocolParser    协议解析层\n└── RobotState             数据缓存层\n",[28,4027,4025],{"__ignoreMap":26},[13,4029,4030],{},"Do not write as:",[20,4032,4035],{"className":4033,"code":4034,"language":25,"meta":26},[23],"一个 node.cpp 里面塞满：\n串口打开\nread\nwrite\n协议解析\nodom 发布\ncmd_vel 订阅\nPID 控制\nTF 发布\n参数读取\n",[28,4036,4034],{"__ignoreMap":26},[13,4038,4039],{},"This will be very difficult to maintain later on.",[38,4041],{},[41,4043,4045],{"id":4044},"common-pitfalls","Common Pitfalls",[49,4047,4049,4050,4053],{"id":4048},"pitfall-1-iorun-early-return","Pitfall 1: ",[28,4051,4052],{},"io.run()"," early return",[13,4055,4056,4057,36],{},"The reason is usually that there is no asynchronous task, and there is no ",[28,4058,4059],{},"work_guard",[13,4061,4062],{},"Solution:",[20,4064,4066],{"className":73,"code":4065,"language":75,"meta":26,"style":26},"auto guard = boost::asio::make_work_guard(io);\n",[28,4067,4068],{"__ignoreMap":26},[79,4069,4070,4073,4076,4078,4080,4082,4084,4086,4088],{"class":81,"line":82},[79,4071,4072],{"class":85},"auto",[79,4074,4075],{"class":126}," guard ",[79,4077,230],{"class":85},[79,4079,2207],{"class":122},[79,4081,136],{"class":126},[79,4083,1872],{"class":122},[79,4085,136],{"class":126},[79,4087,3014],{"class":122},[79,4089,4090],{"class":126},"(io);\n",[49,4092,4094],{"id":4093},"pitfall-2-callback-not-executing","Pitfall 2: Callback Not Executing",[13,4096,4097],{},"Common causes:",[2832,4099,4100,4106,4111,4114,4117],{},[2835,4101,4102,4103,4105],{},"Did not call ",[28,4104,4052],{},";",[2835,4107,4108,4110],{},[28,4109,4052],{}," has returned；",[2835,4112,4113],{},"Asynchronous object destructed prematurely;",[2835,4115,4116],{},"buffer destructed prematurely;",[2835,4118,4119,4120,4123],{},"The serial port did not receive the delimiter, for example ",[28,4121,4122],{},"async_read_until(..., '\\n')",", but the microcontroller did not send a newline.",[49,4125,4127],{"id":4126},"pitfall-3-incorrectly-writing-a-bound-member-function-in-a-class","Pitfall 3: Incorrectly writing a bound member function in a class.",[13,4129,4130],{},"Correct writing:",[20,4132,4134],{"className":73,"code":4133,"language":75,"meta":26,"style":26},"std::bind(&ClassName::callback,\n          this,\n          std::placeholders::_1,\n          std::placeholders::_2)\n",[28,4135,4136,4154,4161,4172],{"__ignoreMap":26},[79,4137,4138,4140,4142,4144,4146,4148,4151],{"class":81,"line":82},[79,4139,1066],{"class":122},[79,4141,136],{"class":126},[79,4143,2138],{"class":122},[79,4145,127],{"class":126},[79,4147,142],{"class":85},[79,4149,4150],{"class":122},"ClassName",[79,4152,4153],{"class":126},"::callback,\n",[79,4155,4156,4159],{"class":81,"line":93},[79,4157,4158],{"class":233},"          this",[79,4160,2127],{"class":126},[79,4162,4163,4166,4168,4170],{"class":81,"line":101},[79,4164,4165],{"class":122},"          std",[79,4167,136],{"class":126},[79,4169,2167],{"class":122},[79,4171,2170],{"class":126},[79,4173,4174,4176,4178,4180],{"class":81,"line":109},[79,4175,4165],{"class":122},[79,4177,136],{"class":126},[79,4179,2167],{"class":122},[79,4181,4182],{"class":126},"::_2)\n",[13,4184,4185,4186,4189],{},"If it is ",[28,4187,4188],{},"shared_ptr"," managing the lifecycle:",[20,4191,4193],{"className":73,"code":4192,"language":75,"meta":26,"style":26},"std::bind(&Session::on_read,\n          shared_from_this(),\n          std::placeholders::_1,\n          std::placeholders::_2)\n",[28,4194,4195,4212,4220,4230],{"__ignoreMap":26},[79,4196,4197,4199,4201,4203,4205,4207,4210],{"class":81,"line":82},[79,4198,1066],{"class":122},[79,4200,136],{"class":126},[79,4202,2138],{"class":122},[79,4204,127],{"class":126},[79,4206,142],{"class":85},[79,4208,4209],{"class":122},"Session",[79,4211,2148],{"class":126},[79,4213,4214,4217],{"class":81,"line":93},[79,4215,4216],{"class":122},"          shared_from_this",[79,4218,4219],{"class":126},"(),\n",[79,4221,4222,4224,4226,4228],{"class":81,"line":101},[79,4223,4165],{"class":122},[79,4225,136],{"class":126},[79,4227,2167],{"class":122},[79,4229,2170],{"class":126},[79,4231,4232,4234,4236,4238],{"class":81,"line":109},[79,4233,4165],{"class":122},[79,4235,136],{"class":126},[79,4237,2167],{"class":122},[79,4239,4182],{"class":126},[49,4241,4243],{"id":4242},"pitfall-4-buffer-is-a-local-variable-when-writing-asynchronously","Pitfall 4: Buffer is a local variable when writing asynchronously",[13,4245,4246],{},"Wrong approach:",[20,4248,4251],{"className":4249,"code":4250,"language":25,"meta":26},[23],"函数里创建 std::string\n把它交给 async_write\n函数返回后 string 销毁\n异步写还没完成\n",[28,4252,4250],{"__ignoreMap":26},[13,4254,4255],{},"Recommended:",[20,4257,4260],{"className":4258,"code":4259,"language":25,"meta":26},[23],"用类成员变量\n用 shared_ptr\n用 write_queue\n",[28,4261,4259],{"__ignoreMap":26},[49,4263,4265],{"id":4264},"pitfall-5-treating-tcp-as-packets-of-data","Pitfall 5: Treating TCP as Packets of Data",[13,4267,4268],{},"TCP is a byte stream with no message boundaries. Custom robot protocols must implement framing.",[49,4270,4272],{"id":4271},"pitfall-6-udp-believed-to-be-reliable","Pitfall 6: UDP believed to be reliable",[13,4274,4275],{},"UDP may experience packet loss, out-of-order delivery, and duplication. Do not blindly rely on a single UDP transmission for important commands.",[38,4277],{},[41,4279,4281],{"id":4280},"how-can-you-continue-to-expand-further","How can you continue to expand further?",[13,4283,4284],{},"After completing this set, you can move on to three small projects:",[2832,4286,4287,4293,4299],{},[2835,4288,4289,4292],{},[767,4290,4291],{},"Serial Peripheral Protocol Driver","\nLinux host computer reads odom sent from STM32 via Asio serial port and sends cmd_vel.",[2835,4294,4295,4298],{},[767,4296,4297],{},"TCP Debug Server","\nWrite a TCP server, where a mobile phone or computer connects over the network to send debug commands to control the car.",[2835,4300,4301,4304],{},[767,4302,4303],{},"UDP Heartbeat and Status Broadcast","\nThe car broadcasts its status every 1 second, and the debugging tool automatically discovers the device.",[13,4306,4307],{},"These three projects can all interface with ROS2, Nav2, ros2_control, and small car chassis control.",[4309,4310,4311],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":26,"searchDepth":93,"depth":93,"links":4313},[4314,4322,4329,4336,4343,4349,4350,4359],{"id":43,"depth":93,"text":4315,"children":4316},"Example 1: Simulating robot protocol parsing in a common main()",[4317,4318,4319,4320,4321],{"id":51,"depth":101,"text":52},{"id":69,"depth":101,"text":70},{"id":773,"depth":101,"text":774},{"id":806,"depth":101,"text":807},{"id":816,"depth":101,"text":817},{"id":837,"depth":93,"text":838,"children":4323},[4324,4325,4326,4327,4328],{"id":841,"depth":101,"text":52},{"id":847,"depth":101,"text":70},{"id":1417,"depth":101,"text":774},{"id":1444,"depth":101,"text":807},{"id":1453,"depth":101,"text":817},{"id":1467,"depth":93,"text":1468,"children":4330},[4331,4332,4333,4334,4335],{"id":1471,"depth":101,"text":52},{"id":1483,"depth":101,"text":70},{"id":2691,"depth":101,"text":774},{"id":2793,"depth":101,"text":2794},{"id":2824,"depth":101,"text":817},{"id":2860,"depth":93,"text":2861,"children":4337},[4338,4339,4340,4341,4342],{"id":2864,"depth":101,"text":52},{"id":2879,"depth":101,"text":2880},{"id":3675,"depth":101,"text":3676},{"id":3706,"depth":101,"text":817},{"id":3755,"depth":101,"text":3756},{"id":3782,"depth":93,"text":3783,"children":4344},[4345,4346,4347,4348],{"id":3786,"depth":101,"text":52},{"id":3792,"depth":101,"text":3793},{"id":3981,"depth":101,"text":3982},{"id":4003,"depth":101,"text":817},{"id":4017,"depth":93,"text":4018},{"id":4044,"depth":93,"text":4045,"children":4351},[4352,4354,4355,4356,4357,4358],{"id":4048,"depth":101,"text":4353},"Pitfall 1: io.run() early return",{"id":4093,"depth":101,"text":4094},{"id":4126,"depth":101,"text":4127},{"id":4242,"depth":101,"text":4243},{"id":4264,"depth":101,"text":4265},{"id":4271,"depth":101,"text":4272},{"id":4280,"depth":93,"text":4281},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng","2100-0100-0600","2023-10-05","wiki\u002F2023-10-05-cplusplus-jiao-xue","en-us:2023-10-05-cplusplus-jiao-xue","\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue","Cplusplus教学","md","wiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0600-机器人工程写法与ROS2集成",false,null,"en-US","en-us",{},{"title":5,"description":26},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0600-机器人工程写法与ROS2集成","M49rjrfMcyhnq3ptrMuPQm74or4t4G-em_7hZ1z8Ytc",[4379,4385,4390,4395,4400,4405,4410,4415,4420,4425,4430,4435,4440,4445,4450,4455,4460,4465,4470,4475,4480,4485,4490,4495,4500,4505,4510,4515,4520,4525,4530,4535,4540,4545,4550,4555,4560,4565,4569,4574,4579,4584,4589,4594,4599,4604,4609,4614,4619,4624,4628,4633,4638,4643,4648,4653,4658,4663,4668,4673,4678,4683,4688,4693,4698,4703,4708,4713,4718,4719,4724,4729,4734,4739,4744,4749,4754,4759,4764,4769,4774,4779],{"path":4380,"stem":4381,"title":4382,"date":4362,"chapterOrder":4383,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0100-c-kai-fa-huan-jing-da-jian-yu-ce-shi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0100-C++开发环境搭建与测试","C++ Development Environment Setup and Testing","0100",0,{"path":4386,"stem":4387,"title":4388,"date":4362,"chapterOrder":4389,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0200-c-ji-chu-chu-shi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0200-C++基础初识","C++ Basics","0200",{"path":4391,"stem":4392,"title":4393,"date":4362,"chapterOrder":4394,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0300-shu-ju-lei-xing-yu-shu-ju-cun-fang","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0300-数据类型与数据存放","Data Types and Data Storage","0300",{"path":4396,"stem":4397,"title":4398,"date":4362,"chapterOrder":4399,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0400-shu-ru-shu-chu","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0400-输入输出","Input and Output","0400",{"path":4401,"stem":4402,"title":4403,"date":4362,"chapterOrder":4404,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0500-yun-suan-fu","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0500-运算符","operator","0500",{"path":4406,"stem":4407,"title":4408,"date":4362,"chapterOrder":4409,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0600-cheng-xu-liu-cheng-jie-gou","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0600-程序流程结构","program flow structure","0600",{"path":4411,"stem":4412,"title":4413,"date":4362,"chapterOrder":4414,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0700-shu-zu","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0700-数组","array","0700",{"path":4416,"stem":4417,"title":4418,"date":4362,"chapterOrder":4419,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0800-han-shu-yu-tou-wen-jian","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0800-函数与头文件","Functions and Header Files","0800",{"path":4421,"stem":4422,"title":4423,"date":4362,"chapterOrder":4424,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F0900-zhi-zhen","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F0900-指针","pointer","0900",{"path":4426,"stem":4427,"title":4428,"date":4362,"chapterOrder":4429,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1000-jie-gou-ti-yu-gong-yong-ti","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1000-结构体与共用体","Structures and Unions","1000",{"path":4431,"stem":4432,"title":4433,"date":4362,"chapterOrder":4434,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1100-nei-cun-fen-qu-yu-sheng-ming-zhou-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1100-内存分区与生命周期","Memory Partitioning and Lifecycle","1100",{"path":4436,"stem":4437,"title":4438,"date":4362,"chapterOrder":4439,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1200-yin-yong","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1200-引用","reference","1200",{"path":4441,"stem":4442,"title":4443,"date":4362,"chapterOrder":4444,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1300-han-shu-ti-gao-yu-ming-ming-kong-jian","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1300-函数提高与命名空间","Advanced Functions and Namespaces","1300",{"path":4446,"stem":4447,"title":4448,"date":4362,"chapterOrder":4449,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0100-feng-zhuang","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1400-0100-封装","encapsulation","1400-0100",{"path":4451,"stem":4452,"title":4453,"date":4362,"chapterOrder":4454,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0200-dui-xiang-chu-shi-hua-he-qing-li","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1400-0200-对象初始化和清理","Object initialization and cleanup","1400-0200",{"path":4456,"stem":4457,"title":4458,"date":4362,"chapterOrder":4459,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0300-dui-xiang-mo-xing-yu-this-zhi-zhen","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1400-0300-对象模型与this指针","Object Model and the `this` Pointer","1400-0300",{"path":4461,"stem":4462,"title":4463,"date":4362,"chapterOrder":4464,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0400-you-yuan-yu-yun-suan-fu-zhong-zai","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1400-0400-友元与运算符重载","Friends and operator overloading","1400-0400",{"path":4466,"stem":4467,"title":4468,"date":4362,"chapterOrder":4469,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0500-ji-cheng","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1400-0500-继承","inheritance","1400-0500",{"path":4471,"stem":4472,"title":4473,"date":4362,"chapterOrder":4474,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-0600-duo-tai","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1400-0600-多态","polymorphism","1400-0600",{"path":4476,"stem":4477,"title":4478,"date":4362,"chapterOrder":4479,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1400-lei-he-dui-xiang","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1400-类和对象","Classes and Objects","1400",{"path":4481,"stem":4482,"title":4483,"date":4362,"chapterOrder":4484,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1500-wen-jian-cao-zuo","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1500-文件操作","File operations","1500",{"path":4486,"stem":4487,"title":4488,"date":4362,"chapterOrder":4489,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1600-yi-chang-chu-li-yu-cuo-wu-ma","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1600-异常处理与错误码","异常处理","1600",{"path":4491,"stem":4492,"title":4493,"date":4362,"chapterOrder":4494,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1700-mu-ban","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1700-模板","template","1700",{"path":4496,"stem":4497,"title":4498,"date":4362,"chapterOrder":4499,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0100-stl-chu-shi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0100-STL初识","Introduction to STL","1800-0100",{"path":4501,"stem":4502,"title":4503,"date":4362,"chapterOrder":4504,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0200-std-array","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0200-std-array","std::array","1800-0200",{"path":4506,"stem":4507,"title":4508,"date":4362,"chapterOrder":4509,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0300-string-rong-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0300-string容器","string container","1800-0300",{"path":4511,"stem":4512,"title":4513,"date":4362,"chapterOrder":4514,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0400-vector-rong-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0400-vector容器","vector 容器","1800-0400",{"path":4516,"stem":4517,"title":4518,"date":4362,"chapterOrder":4519,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0500-deque-rong-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0500-deque容器","deque 容器","1800-0500",{"path":4521,"stem":4522,"title":4523,"date":4362,"chapterOrder":4524,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0600-stack-rong-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0600-stack容器","stack 容器","1800-0600",{"path":4526,"stem":4527,"title":4528,"date":4362,"chapterOrder":4529,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0700-queue-rong-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0700-queue容器","queue container","1800-0700",{"path":4531,"stem":4532,"title":4533,"date":4362,"chapterOrder":4534,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0800-list-rong-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0800-list容器","list 容器","1800-0800",{"path":4536,"stem":4537,"title":4538,"date":4362,"chapterOrder":4539,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-0900-set-rong-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-0900-set容器","set \u002F multiset 容器","1800-0900",{"path":4541,"stem":4542,"title":4543,"date":4362,"chapterOrder":4544,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-1000-map-rong-qi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-1000-map容器","map \u002F multimap 容器","1800-1000",{"path":4546,"stem":4547,"title":4548,"date":4362,"chapterOrder":4549,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-1100-han-shu-dui-xiang-yu-wei-ci","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-1100-函数对象与谓词","Function objects and predicates","1800-1100",{"path":4551,"stem":4552,"title":4553,"date":4362,"chapterOrder":4554,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-1200-chang-yong-suan-fa","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-1200-常用算法","Common algorithms","1800-1200",{"path":4556,"stem":4557,"title":4558,"date":4362,"chapterOrder":4559,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1800-stl-ti-gao-bian-cheng","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1800-STL提高编程","Level up your programming with STL.","1800",{"path":4561,"stem":4562,"title":4563,"date":4362,"chapterOrder":4564,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F1900-c-lei-xing-zhuan-huan","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F1900-C++类型转换","C++ Type Casting","1900",{"path":4566,"stem":4567,"title":4072,"date":4362,"chapterOrder":4568,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0100-auto","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0100-auto","2000-0100",{"path":4570,"stem":4571,"title":4572,"date":4362,"chapterOrder":4573,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0200-nullptr","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0200-nullptr","nullptr","2000-0200",{"path":4575,"stem":4576,"title":4577,"date":4362,"chapterOrder":4578,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0300-using","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0300-using","using","2000-0300",{"path":4580,"stem":4581,"title":4582,"date":4362,"chapterOrder":4583,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0400-enum-class","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0400-enum-class","enum class","2000-0400",{"path":4585,"stem":4586,"title":4587,"date":4362,"chapterOrder":4588,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0500-fan-wei-for-xun-huan","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0500-范围for循环","range-based for loop","2000-0500",{"path":4590,"stem":4591,"title":4592,"date":4362,"chapterOrder":4593,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0600-jie-gou-hua-bang-ding","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0600-结构化绑定","structured binding","2000-0600",{"path":4595,"stem":4596,"title":4597,"date":4362,"chapterOrder":4598,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0700-constexpr","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0700-constexpr","constexpr","2000-0700",{"path":4600,"stem":4601,"title":4602,"date":4362,"chapterOrder":4603,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0800-raii","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0800-RAII","RAII","2000-0800",{"path":4605,"stem":4606,"title":4607,"date":4362,"chapterOrder":4608,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-0900-zhi-neng-zhi-zhen","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-0900-智能指针","Smart pointer","2000-0900",{"path":4610,"stem":4611,"title":4612,"date":4362,"chapterOrder":4613,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1000-you-zhi-yin-yong-he-yi-dong-yu-yi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1000-右值引用和移动语义","Rvalue references and move semantics","2000-1000",{"path":4615,"stem":4616,"title":4617,"date":4362,"chapterOrder":4618,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1100-lambda-biao-da-shi","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1100-Lambda表达式","Lambda expression","2000-1100",{"path":4620,"stem":4621,"title":4622,"date":4362,"chapterOrder":4623,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1200-std-function","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1200-std-function","std::function","2000-1200",{"path":4625,"stem":4626,"title":35,"date":4362,"chapterOrder":4627,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1300-std-bind","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1300-std-bind","2000-1300",{"path":4629,"stem":4630,"title":4631,"date":4362,"chapterOrder":4632,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1400-std-optional","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1400-std-optional","std::optional","2000-1400",{"path":4634,"stem":4635,"title":4636,"date":4362,"chapterOrder":4637,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1500-std-variant","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1500-std-variant","std::variant","2000-1500",{"path":4639,"stem":4640,"title":4641,"date":4362,"chapterOrder":4642,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1600-std-span","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1600-std-span","std::span","2000-1600",{"path":4644,"stem":4645,"title":4646,"date":4362,"chapterOrder":4647,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1700-std-format-print","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1700-std-format-print","std::format \u002F std::print","2000-1700",{"path":4649,"stem":4650,"title":4651,"date":4362,"chapterOrder":4652,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1800-std-chrono","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1800-std-chrono","std::chrono","2000-1800",{"path":4654,"stem":4655,"title":4656,"date":4362,"chapterOrder":4657,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-0100-std-thread","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-0100-std-thread","std::thread and join","2000-1900-0100",{"path":4659,"stem":4660,"title":4661,"date":4362,"chapterOrder":4662,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-0200-mutex-lock-guard","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-0200-mutex-lock-guard","mutex 与 lock_guard","2000-1900-0200",{"path":4664,"stem":4665,"title":4666,"date":4362,"chapterOrder":4667,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-0300-std-atomic","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-0300-std-atomic","std::atomic","2000-1900-0300",{"path":4669,"stem":4670,"title":4671,"date":4362,"chapterOrder":4672,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-0400-condition-variable","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-0400-condition-variable","condition_variable","2000-1900-0400",{"path":4674,"stem":4675,"title":4676,"date":4362,"chapterOrder":4677,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-1900-bing-fa-bian-cheng","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-1900-并发编程","Concurrent programming","2000-1900",{"path":4679,"stem":4680,"title":4681,"date":4362,"chapterOrder":4682,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-2000-std-filesystem","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-2000-std-filesystem","std::filesystem","2000-2000",{"path":4684,"stem":4685,"title":4686,"date":4362,"chapterOrder":4687,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-2100-modules-jian-jie","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-2100-modules简介","Modules Introduction","2000-2100",{"path":4689,"stem":4690,"title":4691,"date":4362,"chapterOrder":4692,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2000-xian-dai-c","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2000-现代C++","Modern C++","2000",{"path":4694,"stem":4695,"title":4696,"date":4362,"chapterOrder":4697,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0100-ding-shi-qi-yu-yi-bu-io","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0100-定时器与异步IO","Timers and Asynchronous I\u002FO","2100-0100-0100",{"path":4699,"stem":4700,"title":4701,"date":4362,"chapterOrder":4702,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0200-boost-asio-ji-chu","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0200-Boost.Asio基础","Boost.Asio Basics","2100-0100-0200",{"path":4704,"stem":4705,"title":4706,"date":4362,"chapterOrder":4707,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0300-chuan-kou-tong-xin","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0300-串口通信","serial communication","2100-0100-0300",{"path":4709,"stem":4710,"title":4711,"date":4362,"chapterOrder":4712,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0400-tcp-tong-xin","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0400-TCP通信","TCP communication","2100-0100-0400",{"path":4714,"stem":4715,"title":4716,"date":4362,"chapterOrder":4717,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0500-udp-tong-xin","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-0500-UDP通信","UDP communication","2100-0100-0500",{"path":4360,"stem":4376,"title":5,"date":4362,"chapterOrder":4361,"chapterDepth":93,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},{"path":4720,"stem":4721,"title":4722,"date":4362,"chapterOrder":4723,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-boost-asio-yi-bu-io-ku","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0100-Boost.Asio异步IO库","Boost.Asio asynchronous IO library","2100-0100",{"path":4725,"stem":4726,"title":4727,"date":4362,"chapterOrder":4728,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0200-eigen-xian-xing-dai-shu-ku","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0200-Eigen线性代数库","Eigen linear algebra library","2100-0200",{"path":4730,"stem":4731,"title":4732,"date":4362,"chapterOrder":4733,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0300-opencv-ji-suan-ji-shi-jue-ku","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0300-OpenCV计算机视觉库","OpenCV Computer Vision Library","2100-0300",{"path":4735,"stem":4736,"title":4737,"date":4362,"chapterOrder":4738,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0400-pcl-dian-yun-ku","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0400-PCL点云库","PCL Point Cloud Library","2100-0400",{"path":4740,"stem":4741,"title":4742,"date":4362,"chapterOrder":4743,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0500-sophus-li-qun-li-dai-shu-ku","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-0500-Sophus李群李代数库","Sophus Lie group and Lie algebra library","2100-0500",{"path":4745,"stem":4746,"title":4747,"date":4362,"chapterOrder":4748,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-chang-yong-ku","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2100-常用库","Learning Common Libraries","2100",{"path":4750,"stem":4751,"title":4752,"date":4362,"chapterOrder":4753,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0100-cmakepresets-yu-gou-jian-an-zhuang","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2200-0100-CMakePresets与构建安装","CMakePresets and Build Installation","2200-0100",{"path":4755,"stem":4756,"title":4757,"date":4362,"chapterOrder":4758,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0200-ding-ceng-cmake-yu-gong-gong-bian-yi-xuan-xiang","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2200-0200-顶层CMake与公共编译选项","Top-level CMake and Public Compilation Options","2200-0200",{"path":4760,"stem":4761,"title":4762,"date":4362,"chapterOrder":4763,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0300-src-yu-lib-mo-kuai-cmake-xiang-jie","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2200-0300-src与lib模块CMake详解","Detailed CMake Explanation for src and lib Modules","2200-0300",{"path":4765,"stem":4766,"title":4767,"date":4362,"chapterOrder":4768,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0400-di-san-fang-ku-yi-lai-xie-fa","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2200-0400-第三方库依赖写法","How to write third-party library dependencies","2200-0400",{"path":4770,"stem":4771,"title":4772,"date":4362,"chapterOrder":4773,"chapterDepth":82,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-0500-mu-ban-kuo-zhan-yu-chang-jian-wen-ti","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2200-0500-模板扩展与常见问题","Template Extensions and FAQ","2200-0500",{"path":4775,"stem":4776,"title":4777,"date":4362,"chapterOrder":4778,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":4369},"\u002Fen-us\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-cmake-gong-cheng-mu-ban","_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002F2200-CMake工程模板","CMake Project Template","2200",{"path":4365,"stem":4780,"title":4781,"date":4362,"chapterOrder":4370,"chapterDepth":4384,"docKey":4364,"docRoot":4365,"docTitle":4366,"isWikiDoc":112,"isWikiIndex":112},"_i18n\u002Fen-us\u002Fwiki\u002F2023-10-05-Cplusplus教学\u002Findex","C\u002FC++ tutorial",{"variants":4783},[4784,4785,4788,4791,4794],{"path":4360,"localeSlug":4372,"i18nKey":4368},{"path":4786,"localeSlug":4787,"i18nKey":4368},"\u002Fzh-hant\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng","zh-hant",{"path":4789,"localeSlug":4790,"i18nKey":4368},"\u002Fzh-hk\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng","zh-hk",{"path":4792,"localeSlug":4793,"i18nKey":4368},"\u002Fzh-tw\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng","zh-tw",{"path":4795,"localeSlug":4796,"i18nKey":4368},"\u002Fzh-cn\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2100-0100-0600-ji-qi-ren-gong-cheng-xie-fa-yu-ros2-ji-cheng","zh-cn",[4360,4375,4786,4375,4789,4375,4792,4375,4795,4375],1784646871237]