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