[{"data":1,"prerenderedAt":7844},["ShallowReactive",2],{"wiki-page-\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0500-chi-xu-ren-wu-yu-zhong-zhi":3,"wiki-doc-items-2023-12-30-ros2-tutorial":7425,"wiki:author-members":7832},{"id":4,"title":5,"authors":6,"body":8,"chapterDepth":487,"chapterOrder":7413,"date":7414,"description":98,"docKey":7415,"docRoot":7416,"docTitle":7417,"extension":7418,"isWikiDoc":624,"isWikiIndex":7419,"meta":7420,"navigation":624,"path":7421,"seo":7422,"stem":7423,"wikiDepth":299,"__hash__":7424},"wiki\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0500-持续任务与中止.md","持续任务与中止",[7],"董佳辉",{"type":9,"value":10,"toc":7385},"minimark",[11,16,49,56,72,91,101,104,107,121,218,250,266,280,285,288,318,327,333,356,379,383,386,421,442,524,585,594,598,604,685,732,745,749,760,873,893,897,919,925,947,949,952,963,966,1005,1013,1032,1038,1045,1065,1074,1080,1083,1093,2992,3008,3015,3029,3064,3079,3096,3112,3115,3121,3234,3241,3243,3246,3264,3270,3275,3308,3325,3345,3347,3350,3356,3376,3390,3396,3408,3411,3417,3432,3437,3443,3445,3449,3472,3477,3494,3561,3566,3572,3581,3584,3590,3596,3602,3604,3607,3613,3629,3739,5293,5298,5304,5309,5326,5338,5342,5345,5424,5454,5460,5465,5467,5471,5474,5486,6997,7012,7104,7120,7146,7153,7161,7166,7171,7176,7179,7200,7230,7276,7281,7289,7303,7305,7308,7315,7363,7369,7371,7374,7381],[12,13,15],"h2",{"id":14},"让导航任务跨越多次-tick","让导航任务跨越多次 tick",[17,18,19],"blockquote",{},[20,21,22,23,30,31,36,37,42,43,48],"p",{},"对应 BehaviorTree.CPP 3.8 官方文档：",[24,25,29],"a",{"href":26,"rel":27},"https:\u002F\u002Fwww.behaviortree.dev\u002Fdocs\u002F3.8\u002Ftutorial-basics\u002Ftutorial_04_sequence\u002F",[28],"nofollow","Reactive and Asynchronous behaviors","。实现细节参考 3.8.7 的 ",[24,32,35],{"href":33,"rel":34},"https:\u002F\u002Fgithub.com\u002FBehaviorTree\u002FBehaviorTree.CPP\u002Fblob\u002F3.8.7\u002Fsrc\u002Faction_node.cpp",[28],"action_node.cpp","、",[24,38,41],{"href":39,"rel":40},"https:\u002F\u002Fgithub.com\u002FBehaviorTree\u002FBehaviorTree.CPP\u002Fblob\u002F3.8.7\u002Fsrc\u002Fcontrols\u002Freactive_sequence.cpp",[28],"reactive_sequence.cpp"," 和 ",[24,44,47],{"href":45,"rel":46},"https:\u002F\u002Fgithub.com\u002FBehaviorTree\u002FBehaviorTree.CPP\u002Fblob\u002F3.8.7\u002Finclude\u002Fbehaviortree_cpp_v3\u002Fbt_factory.h",[28],"bt_factory.h","。",[20,50,51,52],{},"前两篇实践分别完成了最小行为树和节点间的数据传递。\n如果还没有运行，可以先完成它们，再进入本篇。\n本篇仍使用模拟数据，集中解决一个问题：",[53,54,55],"strong",{},"导航还没结束时，节点怎样立即返回，后面怎样继续检查，以及外部条件变化后怎样中止它。",[20,57,58,59,62,63,67,68,71],{},"先明确本篇的模拟规则：",[53,60,61],{},"程序用计数器表示导航进度，约定检查三次就算任务完成。"," 目标暂时用 ",[64,65,66],"code",{},"loading_area"," 这样的字符串表示。\n这段程序没有控制机器人移动，也没有读取机器人的实际位置；日志中的 ",[64,69,70],{},"arrived"," 表示满足了我们设定的模拟完成条件。\n先用这个简单规则看清行为树的调用过程，后面再说明真实导航应替换哪一部分。",[20,73,74,75,78,79,82,83,86,87,90],{},"本例中的 ",[64,76,77],{},"ticks=\"3\""," 表示执行三次 ",[64,80,81],{},"onRunning()","，不是三秒，也不是主程序只调用三次 ",[64,84,85],{},"tickRoot()","。\n开始任务还要单独调用一次 ",[64,88,89],{},"onStart()","，所以正常完成需要四次根 tick，后面会逐次展开。",[92,93,99],"pre",{"className":94,"code":96,"language":97,"meta":98},[95],"language-text","ReactiveSequence\n├── NavigationAllowed   每次根 tick 都重新检查是否允许导航\n└── NavigateToGoal      开始一次任务，后续 tick 检查进度\n                         ├── 未完成：RUNNING\n                         ├── 已到达：SUCCESS\n                         └── 被中止：执行 onHalted()\n","text","",[64,100,96],{"__ignoreMap":98},[102,103],"hr",{},[12,105,106],{"id":106},"用三个回调管理一个持续任务",[20,108,109,112,113,116,117,120],{},[64,110,111],{},"SyncActionNode"," 用于一次调用就能给出结果的动作，不能用它返回 ",[64,114,115],{},"RUNNING","。\n持续任务使用 ",[64,118,119],{},"StatefulActionNode","，实现下面三个回调：",[122,123,124,143],"table",{},[125,126,127],"thead",{},[128,129,130,134,137,140],"tr",{},[131,132,133],"th",{},"回调",[131,135,136],{},"调用时机",[131,138,139],{},"本例做什么",[131,141,142],{},"返回值",[144,145,146,174,197],"tbody",{},[128,147,148,153,160,163],{},[149,150,151],"td",{},[64,152,89],{},[149,154,155,156,159],{},"节点从 ",[64,157,158],{},"IDLE"," 开始执行",[149,161,162],{},"读取目标和所需次数，将计数清零",[149,164,165,36,167,170,171],{},[64,166,115],{},[64,168,169],{},"SUCCESS"," 或 ",[64,172,173],{},"FAILURE",[128,175,176,180,186,189],{},[149,177,178],{},[64,179,81],{},[149,181,182,183,185],{},"当前节点为 ",[64,184,115],{},"，再次收到 tick",[149,187,188],{},"将计数加一，判断是否达到所需次数",[149,190,191,36,193,170,195],{},[64,192,115],{},[64,194,169],{},[64,196,173],{},[128,198,199,204,210,213],{},[149,200,201],{},[64,202,203],{},"onHalted()",[149,205,206,207,209],{},"正在 ",[64,208,115],{}," 的节点被中止",[149,211,212],{},"打印中止信息，清零模拟计数",[149,214,215],{},[64,216,217],{},"void",[20,219,220,221,224,225,227,228,231,232,36,235,42,238,241,242,245,246,249],{},"三个回调都",[53,222,223],{},"没有函数参数","，由 ",[64,226,119],{}," 在对应时机调用，不需要在 ",[64,229,230],{},"main()"," 中直接调用。\n它们的声明分别是 ",[64,233,234],{},"BT::NodeStatus onStart() override",[64,236,237],{},"BT::NodeStatus onRunning() override",[64,239,240],{},"void onHalted() override","；",[64,243,244],{},"override"," 表示实现基类规定的虚函数。\n回调通过当前节点的 ",[64,247,248],{},"getInput()"," 读取输入，通过对象成员保存执行进度。",[20,251,252,254,255,257,258,260,261,263,264,48],{},[64,253,89],{}," 返回 ",[64,256,115],{}," 后，下一次 tick 才进入 ",[64,259,81],{},"；运行期间不会每次都重新调用 ",[64,262,89],{},"。\n两个有返回值的回调都不能返回 ",[64,265,158],{},[20,267,268,270,271,273,274,276,277,279],{},[64,269,119],{}," 本身不会自动创建工作线程。\n本例的回调都在主程序驱动行为树的线程里执行，所以每次回调要尽快返回。\n真实导航可以在 ",[64,272,89],{}," 中发送一次请求，在 ",[64,275,81],{}," 中检查请求结果，在 ",[64,278,203],{}," 中发起取消。",[281,282,284],"h3",{"id":283},"从主程序的一次-tick-找到回调调用者","从主程序的一次 tick 找到回调调用者",[20,286,287],{},"主程序驱动行为树时，调用的是：",[92,289,293],{"className":290,"code":291,"language":292,"meta":98,"style":98},"language-cpp shiki shiki-themes github-light github-dark","result = tree.tickRoot();\n","cpp",[64,294,295],{"__ignoreMap":98},[296,297,300,304,308,311,315],"span",{"class":298,"line":299},"line",1,[296,301,303],{"class":302},"sVt8B","result ",[296,305,307],{"class":306},"szBVR","=",[296,309,310],{"class":302}," tree.",[296,312,314],{"class":313},"sScJk","tickRoot",[296,316,317],{"class":302},"();\n",[20,319,320,322,323,326],{},[64,321,85],{}," 没有参数，返回这一次根 tick 的 ",[64,324,325],{},"BT::NodeStatus","。\n本例中，条件允许导航时，调用会沿着下面的路径传递：",[92,328,331],{"className":329,"code":330,"language":97,"meta":98},[95],"main() 调用 tree.tickRoot()\n    ↓\nReactiveSequence 从第一个子节点开始执行\n    ↓\nNavigationAllowed 检查是否允许导航\n    ↓ 返回 SUCCESS\n轮到 NavigateToGoal 节点\n    ↓\n库中 StatefulActionNode 的 tick() 检查导航节点的当前状态\n    ├── IDLE    → 调用 onStart()\n    └── RUNNING → 调用 onRunning()\n    ↓\n回调返回的状态沿父节点传回 main() 的 result\n",[64,332,330],{"__ignoreMap":98},[20,334,335,338,339,342,343,36,345,42,347,349,350,352,353,355],{},[64,336,337],{},"NavigateToGoal"," 继承 ",[64,340,341],{},"BT::StatefulActionNode","，因此直接使用了基类已经写好的这套分派规则。\n我们实现 ",[64,344,89],{},[64,346,81],{},[64,348,203],{},"，决定每个时机具体做什么。\n基类调用这些虚函数时，会执行当前 ",[64,351,337],{}," 对象提供的实现。\n声明中的 ",[64,354,244],{}," 用于让编译器检查是否正确覆盖了基类虚函数；实际调用由库的执行流程发起，不是由这个关键字发起。",[20,357,358,359,361,362,364,365,367,368,370,371,373,374,48],{},"因此，第一次执行导航节点时，节点状态为 ",[64,360,158],{},"，进入 ",[64,363,89],{},"；它返回 ",[64,366,115],{}," 后，框架保存这个状态。\n下一次根 tick 再次执行到导航节点，基类看到它仍为 ",[64,369,115],{},"，才进入 ",[64,372,81],{},"。\n这些规则对应 ",[24,375,378],{"href":376,"rel":377},"https:\u002F\u002Fgithub.com\u002FBehaviorTree\u002FBehaviorTree.CPP\u002Fblob\u002F3.8.7\u002Fsrc\u002Faction_node.cpp#L115",[28],"3.8.7 StatefulActionNode 的实现",[281,380,382],{"id":381},"onstart-准备一次任务返回后把执行权交回去","onStart 准备一次任务，返回后把执行权交回去",[20,384,385],{},"先看本篇稍后要填写的导航 XML：",[92,387,391],{"className":388,"code":389,"language":390,"meta":98,"style":98},"language-xml shiki shiki-themes github-light github-dark","\u003CNavigateToGoal goal=\"loading_area\" ticks=\"3\"\u002F>\n","xml",[64,392,393],{"__ignoreMap":98},[296,394,395,398,401,404,406,410,413,415,418],{"class":298,"line":299},[296,396,397],{"class":302},"\u003C",[296,399,337],{"class":400},"s9eBZ",[296,402,403],{"class":313}," goal",[296,405,307],{"class":302},[296,407,409],{"class":408},"sZZnC","\"loading_area\"",[296,411,412],{"class":313}," ticks",[296,414,307],{"class":302},[296,416,417],{"class":408},"\"3\"",[296,419,420],{"class":302},"\u002F>\n",[20,422,423,424,427,428,431,432,434,435,42,438,441],{},"端口 ",[64,425,426],{},"goal"," 接收目标字符串，端口 ",[64,429,430],{},"ticks"," 接收模拟完成所需的运行检查次数。\n",[64,433,89],{}," 通过 ",[64,436,437],{},"getInput\u003Cstd::string>(\"goal\")",[64,439,440],{},"getInput\u003Cint>(\"ticks\")"," 读取并检查它们，然后执行下面的关键语句。\n这里先逐段理解，后面的完整程序再统一复制到工程中：",[92,443,445],{"className":290,"code":444,"language":292,"meta":98,"style":98},"goal_ = goal.value();              \u002F\u002F 保存本次目标：loading_area\nrequired_ticks_ = ticks.value();   \u002F\u002F 保存完成条件：检查三次\ncompleted_ticks_ = 0;              \u002F\u002F 开始新任务，目前检查了零次\nreturn BT::NodeStatus::RUNNING;    \u002F\u002F 报告任务已开始，还没有完成\n",[64,446,447,467,485,503],{"__ignoreMap":98},[296,448,449,452,454,457,460,463],{"class":298,"line":299},[296,450,451],{"class":302},"goal_ ",[296,453,307],{"class":306},[296,455,456],{"class":302}," goal.",[296,458,459],{"class":313},"value",[296,461,462],{"class":302},"();",[296,464,466],{"class":465},"sJ8bj","              \u002F\u002F 保存本次目标：loading_area\n",[296,468,470,473,475,478,480,482],{"class":298,"line":469},2,[296,471,472],{"class":302},"required_ticks_ ",[296,474,307],{"class":306},[296,476,477],{"class":302}," ticks.",[296,479,459],{"class":313},[296,481,462],{"class":302},[296,483,484],{"class":465},"   \u002F\u002F 保存完成条件：检查三次\n",[296,486,488,491,493,497,500],{"class":298,"line":487},3,[296,489,490],{"class":302},"completed_ticks_ ",[296,492,307],{"class":306},[296,494,496],{"class":495},"sj4cs"," 0",[296,498,499],{"class":302},";",[296,501,502],{"class":465},"              \u002F\u002F 开始新任务，目前检查了零次\n",[296,504,506,509,512,515,518,521],{"class":298,"line":505},4,[296,507,508],{"class":306},"return",[296,510,511],{"class":313}," BT",[296,513,514],{"class":302},"::",[296,516,517],{"class":313},"NodeStatus",[296,519,520],{"class":302},"::RUNNING;",[296,522,523],{"class":465},"    \u002F\u002F 报告任务已开始，还没有完成\n",[122,525,526,539],{},[125,527,528],{},[128,529,530,533,536],{},[131,531,532],{},"成员变量",[131,534,535],{},"本次保存的值",[131,537,538],{},"含义",[144,540,541,555,570],{},[128,542,543,548,552],{},[149,544,545],{},[64,546,547],{},"goal_",[149,549,550],{},[64,551,409],{},[149,553,554],{},"本次导航目标",[128,556,557,562,567],{},[149,558,559],{},[64,560,561],{},"required_ticks_",[149,563,564],{},[64,565,566],{},"3",[149,568,569],{},"达到多少次运行检查就算完成",[128,571,572,577,582],{},[149,573,574],{},[64,575,576],{},"completed_ticks_",[149,578,579],{},[64,580,581],{},"0",[149,583,584],{},"已经执行过多少次运行检查",[20,586,587,590,591,593],{},[64,588,589],{},"return RUNNING"," 会结束这一次函数调用，并把执行权交回父节点，最终回到主程序。\n它报告的是“任务尚未完成”；函数返回后，没有一个 ",[64,592,89],{}," 还在后台继续执行。\n这几个变量是节点对象的成员，对象仍然存在，所以保存的目标和计数可以留到下一次回调使用。",[281,595,597],{"id":596},"onrunning-每次加一由节点自己判断是否成功","onRunning 每次加一，由节点自己判断是否成功",[20,599,600,601,603],{},"下面只保留 ",[64,602,81],{}," 中与计数相关的语句，便于看清完成条件：",[92,605,607],{"className":290,"code":606,"language":292,"meta":98,"style":98},"++completed_ticks_;  \u002F\u002F 每进入一次 onRunning，就把已检查次数加一\n\nif (completed_ticks_ >= required_ticks_)\n{\n    return BT::NodeStatus::SUCCESS;  \u002F\u002F 达到约定次数，报告模拟任务完成\n}\nreturn BT::NodeStatus::RUNNING;      \u002F\u002F 次数还不够，等待后续 tick 再检查\n",[64,608,609,620,626,640,645,663,669],{"__ignoreMap":98},[296,610,611,614,617],{"class":298,"line":299},[296,612,613],{"class":306},"++",[296,615,616],{"class":302},"completed_ticks_;",[296,618,619],{"class":465},"  \u002F\u002F 每进入一次 onRunning，就把已检查次数加一\n",[296,621,622],{"class":298,"line":469},[296,623,625],{"emptyLinePlaceholder":624},true,"\n",[296,627,628,631,634,637],{"class":298,"line":487},[296,629,630],{"class":306},"if",[296,632,633],{"class":302}," (completed_ticks_ ",[296,635,636],{"class":306},">=",[296,638,639],{"class":302}," required_ticks_)\n",[296,641,642],{"class":298,"line":505},[296,643,644],{"class":302},"{\n",[296,646,648,651,653,655,657,660],{"class":298,"line":647},5,[296,649,650],{"class":306},"    return",[296,652,511],{"class":313},[296,654,514],{"class":302},[296,656,517],{"class":313},[296,658,659],{"class":302},"::SUCCESS;",[296,661,662],{"class":465},"  \u002F\u002F 达到约定次数，报告模拟任务完成\n",[296,664,666],{"class":298,"line":665},6,[296,667,668],{"class":302},"}\n",[296,670,672,674,676,678,680,682],{"class":298,"line":671},7,[296,673,508],{"class":306},[296,675,511],{"class":313},[296,677,514],{"class":302},[296,679,517],{"class":313},[296,681,520],{"class":302},[296,683,684],{"class":465},"      \u002F\u002F 次数还不够，等待后续 tick 再检查\n",[20,686,687,690,691,693,694,696,697,700,701,704,705,707,708,696,710,713,714,716,717,696,719,721,722,725,726,729,730,48],{},[64,688,689],{},"++completed_ticks_"," 相当于把原来的计数加一，再保存回这个成员变量。\n第一次进入 ",[64,692,81],{}," 时，计数从 ",[64,695,581],{}," 变成 ",[64,698,699],{},"1","。接着判断 ",[64,702,703],{},"1 >= 3","，条件不成立，就跳过大括号，执行最后的 ",[64,706,589],{},"。\n第二次进入时，计数从 ",[64,709,699],{},[64,711,712],{},"2","，仍然返回 ",[64,715,115],{},"。\n第三次进入时，计数从 ",[64,718,712],{},[64,720,566],{},"，",[64,723,724],{},"3 >= 3"," 成立，执行大括号里的 ",[64,727,728],{},"return SUCCESS","，本次函数就结束了，不会再执行下面的 ",[64,731,589],{},[20,733,734,737,738,741,742,744],{},[53,735,736],{},"这里之所以返回成功，是因为我们编写节点时，把“计数达到三次”定义成了模拟任务的完成条件。","\nBehaviorTree.CPP 接收节点报告的状态，再按树的规则决定后续流程；它不会根据目标字符串自行判断机器人是否到达。\n完整程序中的 ",[64,739,740],{},"std::cout"," 只负责打印日志，打印 ",[64,743,70],{}," 本身不会产生导航行为。",[281,746,748],{"id":747},"把四次根-tick-连起来看","把四次根 tick 连起来看",[20,750,751,752,755,756,759],{},"先保持条件始终允许导航。主程序每次调用 ",[64,753,754],{},"tree.tickRoot()","，都会先检查 ",[64,757,758],{},"NavigationAllowed","，再执行导航节点：",[122,761,762,781],{},[125,763,764],{},[128,765,766,769,772,775,778],{},[131,767,768],{},"根 tick",[131,770,771],{},"导航回调",[131,773,774],{},"计数怎样变化",[131,776,777],{},"完成条件",[131,779,780],{},"本次根节点返回",[144,782,783,804,827,850],{},[128,784,785,788,792,797,800],{},[149,786,787],{},"第一次",[149,789,790],{},[64,791,89],{},[149,793,794,795],{},"初始化为 ",[64,796,581],{},[149,798,799],{},"本次只准备任务",[149,801,802],{},[64,803,115],{},[128,805,806,809,813,818,823],{},[149,807,808],{},"第二次",[149,810,811],{},[64,812,81],{},[149,814,815],{},[64,816,817],{},"0 → 1",[149,819,820,822],{},[64,821,703],{},"，不成立",[149,824,825],{},[64,826,115],{},[128,828,829,832,836,841,846],{},[149,830,831],{},"第三次",[149,833,834],{},[64,835,81],{},[149,837,838],{},[64,839,840],{},"1 → 2",[149,842,843,822],{},[64,844,845],{},"2 >= 3",[149,847,848],{},[64,849,115],{},[128,851,852,855,859,864,869],{},[149,853,854],{},"第四次",[149,856,857],{},[64,858,81],{},[149,860,861],{},[64,862,863],{},"2 → 3",[149,865,866,868],{},[64,867,724],{},"，成立",[149,870,871],{},[64,872,169],{},[20,874,875,876,878,879,881,882,885,886,888,889,892],{},"前面三次根 tick 返回 ",[64,877,115],{},"，主程序等待一下，再发起下一次 tick。\n第四次导航返回 ",[64,880,169],{},"，而前面的条件也已成功，",[64,883,884],{},"ReactiveSequence"," 因此返回 ",[64,887,169],{},"；主程序发现任务完成，退出这次循环。\n",[53,890,891],{},"一次启动，加上三次运行检查，共四次根 tick。"," 本例两次 tick 之间等待 100 毫秒，实际执行时间还受打印、调试暂停和系统调度影响，计数不代表固定时长。",[281,894,896],{"id":895},"onhalted-处理运行中的任务被中断","onHalted 处理运行中的任务被中断",[20,898,899,901,902,905,906,909,910,912,913,915,916,918],{},[64,900,203],{}," 走的是另一条分支。当父节点要求停止导航，或主程序调用 ",[64,903,904],{},"tree.haltTree()"," 时，中止沿树传到导航节点。\n基类用于处理中止的 ",[64,907,908],{},"StatefulActionNode::halt()"," 没有参数，返回 ",[64,911,217],{},"；它发现导航节点仍为 ",[64,914,115],{},"，才调用 ",[64,917,203],{},"。\n本例在回调里面打印中止信息，并把计数清零。",[92,920,923],{"className":921,"code":922,"language":97,"meta":98},[95],"正常完成：\nonStart() → onRunning() → onRunning() → onRunning()\n RUNNING      RUNNING       RUNNING       SUCCESS\n\n中途中止：\nonStart() → onRunning() → 收到中止要求 → onHalted()\n RUNNING      RUNNING\n",[64,924,922],{"__ignoreMap":98},[20,926,927,928,930,931,933,934,254,936,938,939,170,941,943,944,946],{},"正常返回 ",[64,929,169],{}," 不会因此触发 ",[64,932,203],{},"；它不是每次任务结束都执行的公共收尾函数。\n",[64,935,203],{},[64,937,217],{},"，负责取消和清理，不向父节点返回 ",[64,940,169],{},[64,942,173],{},"。后面的条件中止示例中，树的 ",[64,945,173],{}," 来自前置条件失败及控制节点的执行规则。\n如果接入真实导航，需要在这个回调里实现对应的取消或停止逻辑。",[102,948],{},[12,950,951],{"id":951},"沿用配置建立持续任务工程",[20,953,954,955,958,959,962],{},"本篇直接复制整个 ",[64,956,957],{},"bt_ports"," 文件夹，再把副本重命名为 ",[64,960,961],{},"bt_running","，保留原来的数据传递工程供后续对照。",[20,964,965],{},"在系统文件管理器中完成下面几步：",[967,968,969,979,992],"ol",{},[970,971,972,973,975,976,978],"li",{},"打开 ",[64,974,957],{}," 所在的父目录，复制并粘贴整个文件夹，将副本重命名为 ",[64,977,961],{},"，让两个工程位于同一层目录。",[970,980,981,982,984,985,42,988,991],{},"在新副本 ",[64,983,961],{}," 中，删除复制过来的 ",[64,986,987],{},"build",[64,989,990],{},"install"," 文件夹（如果存在）。其中的构建缓存和安装结果属于旧工程，新工程稍后会重新生成。",[970,993,994,995,998,999,1002,1003,48],{},"在 VSCode 中选择 ",[53,996,997],{},"文件 → 新建窗口","，再选择 ",[53,1000,1001],{},"文件 → 打开文件夹","，打开新的 ",[64,1004,961],{},[20,1006,1007,1008,1012],{},"使用的是前两篇已经准备好的 BT 练习版配置，框架来源见 ",[24,1009,1011],{"href":1010},"\u002Fwiki\u002F2023-10-05-cplusplus-jiao-xue\u002F2200-cmake-gong-cheng-mu-ban","CMake工程模板","。Ubuntu 22.04 可以继续使用 CMake 3.22.1；Ninja、支持 C++20 的编译器和 VSCode CMake Tools 的准备方式与前两篇相同。复用 Humble 安装的行为树库时，配置、运行和调试进程仍需继承 ROS 2 环境。",[20,1014,1015,36,1018,36,1021,1024,1025,42,1028,1031],{},[64,1016,1017],{},"cmake",[64,1019,1020],{},"src",[64,1022,1023],{},"trees"," 目录及其中的文件都已随工程复制过来，不需要重新建立。\n稍后直接修改顶层项目名，并用本篇内容替换已有的 ",[64,1026,1027],{},"src\u002Fmain.cpp",[64,1029,1030],{},"trees\u002Fmission.xml","。参与本篇构建的目录为：",[92,1033,1036],{"className":1034,"code":1035,"language":97,"meta":98},[95],"bt_running\u002F\n├── CMakeLists.txt\n├── CMakePresets.json\n├── cmake\u002F\n│   ├── ProjectOptions.cmake\n│   └── BehaviorTree.cmake\n├── src\u002F\n│   ├── CMakeLists.txt\n│   └── main.cpp\n└── trees\u002F\n    └── mission.xml\n",[64,1037,1035],{"__ignoreMap":98},[20,1039,1040,1041,1044],{},"顶层 ",[64,1042,1043],{},"CMakeLists.txt"," 的项目名改为：",[92,1046,1049],{"className":1047,"code":1048,"language":1017,"meta":98,"style":98},"language-cmake shiki shiki-themes github-light github-dark","project(bt_running VERSION 1.0.0 LANGUAGES C CXX)\n",[64,1050,1051],{"__ignoreMap":98},[296,1052,1053,1056,1059,1062],{"class":298,"line":299},[296,1054,1055],{"class":306},"project",[296,1057,1058],{"class":302},"(bt_running ",[296,1060,1061],{"class":313},"VERSION",[296,1063,1064],{"class":302}," 1.0.0 LANGUAGES C CXX)\n",[20,1066,1067,1068,1071,1072,48],{},"其他构建配置保持原样，",[64,1069,1070],{},"BT_XML_PATH"," 会自动指向这个工程的 ",[64,1073,1030],{},[20,1075,1076],{},[1077,1078],"img",{"alt":98,"src":1079},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792399513813-4f0f16a0.webp",[281,1081,1027],{"id":1082},"srcmaincpp",[20,1084,1085,1086,1088,1089,1092],{},"用下面的完整程序替换 ",[64,1087,1027],{}," 的原有内容，再保存。\n先保留 ",[64,1090,1091],{},"cancel_after_two_ticks = false","，运行正常完成的情况。",[92,1094,1096],{"className":290,"code":1095,"language":292,"meta":98,"style":98},"#include \"behaviortree_cpp_v3\u002Fbt_factory.h\"\n\n#include \u003Cchrono>\n#include \u003Ciostream>\n#include \u003Cstdexcept>\n#include \u003Cstring>\n\nclass NavigationAllowed : public BT::ConditionNode\n{\npublic:\n    NavigationAllowed(const std::string& name, const BT::NodeConfiguration& config)\n        : BT::ConditionNode(name, config)\n    {}\n\n    static BT::PortsList providedPorts()\n    {\n        return {BT::InputPort\u003Cbool>(\"allowed\")};\n    }\n\n    BT::NodeStatus tick() override\n    {\n        auto allowed = getInput\u003Cbool>(\"allowed\");\n        if (!allowed)\n        {\n            throw BT::RuntimeError(\"Cannot read input [allowed]: \", allowed.error());\n        }\n        std::cout \u003C\u003C \"[NavigationAllowed] allowed=\"\n                  \u003C\u003C (allowed.value() ? \"true\" : \"false\") \u003C\u003C '\\n';\n        return allowed.value() ? BT::NodeStatus::SUCCESS : BT::NodeStatus::FAILURE;\n    }\n};\n\nclass NavigateToGoal : public BT::StatefulActionNode\n{\npublic:\n    NavigateToGoal(const std::string& name, const BT::NodeConfiguration& config)\n        : BT::StatefulActionNode(name, config)\n    {}\n\n    static BT::PortsList providedPorts()\n    {\n        return {BT::InputPort\u003Cstd::string>(\"goal\"),\n                BT::InputPort\u003Cint>(\"ticks\", 3, \"完成导航所需的 onRunning 调用次数\")};\n    }\n\n    BT::NodeStatus onStart() override\n    {\n        auto goal = getInput\u003Cstd::string>(\"goal\");\n        auto ticks = getInput\u003Cint>(\"ticks\");\n        if (!goal)\n        {\n            throw BT::RuntimeError(\"Cannot read input [goal]: \", goal.error());\n        }\n        if (!ticks)\n        {\n            throw BT::RuntimeError(\"Cannot read input [ticks]: \", ticks.error());\n        }\n        if (goal.value().empty() || ticks.value() \u003C 1)\n        {\n            throw std::runtime_error(\"goal must not be empty and ticks must be positive\");\n        }\n\n        goal_ = goal.value();             \u002F\u002F 保存本次目标，供后续回调使用\n        required_ticks_ = ticks.value();  \u002F\u002F 保存模拟完成所需的检查次数，本例为 3\n        completed_ticks_ = 0;             \u002F\u002F 每次开始新任务，都从零次检查开始\n        \u002F\u002F 真实导航通常在这里发送一次请求，本例只保存模拟任务状态。\n        std::cout \u003C\u003C \"[NavigateToGoal] start goal=\" \u003C\u003C goal_ \u003C\u003C '\\n';\n        \u002F\u002F 结束本次回调并报告“尚未完成”，后续 tick 再进入 onRunning。\n        return BT::NodeStatus::RUNNING;\n    }\n\n    BT::NodeStatus onRunning() override\n    {\n        \u002F\u002F 每次进入这个回调，模拟检查次数就加一；函数返回后成员计数仍会保留。\n        ++completed_ticks_;\n        std::cout \u003C\u003C \"[NavigateToGoal] progress=\" \u003C\u003C completed_ticks_\n                  \u003C\u003C '\u002F' \u003C\u003C required_ticks_ \u003C\u003C '\\n';\n        \u002F\u002F 本例把“检查次数达到要求”当作完成条件，没有查询机器人的真实位置。\n        if (completed_ticks_ >= required_ticks_)\n        {\n            std::cout \u003C\u003C \"[NavigateToGoal] arrived goal=\" \u003C\u003C goal_ \u003C\u003C '\\n';\n            \u002F\u002F 已满足模拟完成条件，向父节点报告成功，本次函数到这里结束。\n            return BT::NodeStatus::SUCCESS;\n        }\n        \u002F\u002F 尚未达到要求，结束本次检查，等待后续 tick 再进入这个回调。\n        return BT::NodeStatus::RUNNING;\n    }\n\n    void onHalted() override\n    {\n        \u002F\u002F 运行中的任务收到中止要求时，基类才会调用这个回调。\n        \u002F\u002F 真实导航在这里取消请求、停止当前任务并清理资源。\n        std::cout \u003C\u003C \"[NavigateToGoal] halted goal=\" \u003C\u003C goal_\n                  \u003C\u003C \", progress=\" \u003C\u003C completed_ticks_ \u003C\u003C '\\n';\n        completed_ticks_ = 0;\n    }\n\nprivate:\n    std::string goal_;          \u002F\u002F 本次目标\n    int required_ticks_ = 0;    \u002F\u002F 模拟完成所需的运行检查次数，由 onStart 读取\n    int completed_ticks_ = 0;   \u002F\u002F 已完成的运行检查次数，可跨多次回调保存\n};\n\nint main()\n{\n    \u002F\u002F 先用 false 跑通；改为 true 后，在第二次根 tick 后禁止继续导航。（用于测试onHalted()触发）\n    const bool cancel_after_two_ticks = false;\n\n    try\n    {\n        BT::BehaviorTreeFactory factory;\n        factory.registerNodeType\u003CNavigationAllowed>(\"NavigationAllowed\");\n        factory.registerNodeType\u003CNavigateToGoal>(\"NavigateToGoal\");\n\n        auto blackboard = BT::Blackboard::create();\n        blackboard->set(\"navigation_allowed\", true);\n        auto tree = factory.createTreeFromFile(BT_XML_PATH, blackboard);\n\n        BT::NodeStatus result = BT::NodeStatus::RUNNING;\n        int tick_count = 0;\n        while (result == BT::NodeStatus::RUNNING)\n        {\n            std::cout \u003C\u003C \"--- tick \" \u003C\u003C ++tick_count \u003C\u003C '\\n';\n            \u002F\u002F 从根驱动一次；执行到导航节点时，由基类按当前状态选择回调。\n            result = tree.tickRoot();\n            std::cout \u003C\u003C \"Root returned: \" \u003C\u003C BT::toStr(result) \u003C\u003C '\\n';\n            if (result != BT::NodeStatus::RUNNING)\n            {\n                break;\n            }\n\n            if (cancel_after_two_ticks && tick_count == 2)\n            {\n                blackboard->set(\"navigation_allowed\", false);\n                std::cout \u003C\u003C \"[main] navigation is no longer allowed\\n\";\n            }\n            \u002F\u002F 等待放在主循环中，节点回调本身不长时间阻塞。\n            tree.sleep(std::chrono::milliseconds(100));\n        }\n\n        std::cout \u003C\u003C \"Tree result: \" \u003C\u003C BT::toStr(result) \u003C\u003C '\\n';\n        return result == BT::NodeStatus::SUCCESS ? 0 : 1;\n    }\n    catch (const std::exception& error)\n    {\n        std::cerr \u003C\u003C \"Error: \" \u003C\u003C error.what() \u003C\u003C '\\n';\n        return 2;\n    }\n}\n",[64,1097,1098,1106,1110,1117,1124,1131,1138,1142,1164,1169,1175,1222,1234,1240,1245,1264,1270,1301,1307,1312,1331,1336,1361,1376,1382,1409,1415,1430,1472,1507,1512,1518,1523,1542,1547,1552,1588,1597,1602,1607,1622,1627,1657,1688,1693,1698,1714,1719,1745,1767,1779,1784,1807,1812,1824,1829,1852,1857,1891,1896,1915,1920,1925,1942,1959,1974,1980,2008,2014,2028,2033,2038,2054,2059,2065,2074,2091,2114,2120,2131,2136,2163,2169,2184,2189,2195,2208,2213,2218,2231,2236,2242,2248,2265,2288,2299,2304,2309,2315,2327,2344,2360,2365,2370,2380,2385,2391,2410,2415,2421,2426,2435,2455,2473,2478,2502,2523,2542,2547,2565,2580,2601,2606,2636,2642,2656,2690,2709,2715,2723,2729,2734,2754,2759,2778,2798,2803,2809,2840,2845,2850,2882,2910,2915,2935,2940,2973,2982,2987],{"__ignoreMap":98},[296,1099,1100,1103],{"class":298,"line":299},[296,1101,1102],{"class":306},"#include",[296,1104,1105],{"class":408}," \"behaviortree_cpp_v3\u002Fbt_factory.h\"\n",[296,1107,1108],{"class":298,"line":469},[296,1109,625],{"emptyLinePlaceholder":624},[296,1111,1112,1114],{"class":298,"line":487},[296,1113,1102],{"class":306},[296,1115,1116],{"class":408}," \u003Cchrono>\n",[296,1118,1119,1121],{"class":298,"line":505},[296,1120,1102],{"class":306},[296,1122,1123],{"class":408}," \u003Ciostream>\n",[296,1125,1126,1128],{"class":298,"line":647},[296,1127,1102],{"class":306},[296,1129,1130],{"class":408}," \u003Cstdexcept>\n",[296,1132,1133,1135],{"class":298,"line":665},[296,1134,1102],{"class":306},[296,1136,1137],{"class":408}," \u003Cstring>\n",[296,1139,1140],{"class":298,"line":671},[296,1141,625],{"emptyLinePlaceholder":624},[296,1143,1145,1148,1151,1154,1157,1159,1161],{"class":298,"line":1144},8,[296,1146,1147],{"class":306},"class",[296,1149,1150],{"class":313}," NavigationAllowed",[296,1152,1153],{"class":302}," : ",[296,1155,1156],{"class":306},"public",[296,1158,511],{"class":313},[296,1160,514],{"class":302},[296,1162,1163],{"class":313},"ConditionNode\n",[296,1165,1167],{"class":298,"line":1166},9,[296,1168,644],{"class":302},[296,1170,1172],{"class":298,"line":1171},10,[296,1173,1174],{"class":306},"public:\n",[296,1176,1178,1181,1184,1187,1190,1192,1195,1198,1202,1205,1207,1209,1211,1214,1216,1219],{"class":298,"line":1177},11,[296,1179,1180],{"class":313},"    NavigationAllowed",[296,1182,1183],{"class":302},"(",[296,1185,1186],{"class":306},"const",[296,1188,1189],{"class":313}," std",[296,1191,514],{"class":302},[296,1193,1194],{"class":313},"string",[296,1196,1197],{"class":306},"&",[296,1199,1201],{"class":1200},"s4XuR"," name",[296,1203,1204],{"class":302},", ",[296,1206,1186],{"class":306},[296,1208,511],{"class":313},[296,1210,514],{"class":302},[296,1212,1213],{"class":313},"NodeConfiguration",[296,1215,1197],{"class":306},[296,1217,1218],{"class":1200}," config",[296,1220,1221],{"class":302},")\n",[296,1223,1225,1228,1231],{"class":298,"line":1224},12,[296,1226,1227],{"class":302},"        : BT::",[296,1229,1230],{"class":313},"ConditionNode",[296,1232,1233],{"class":302},"(name, config)\n",[296,1235,1237],{"class":298,"line":1236},13,[296,1238,1239],{"class":302},"    {}\n",[296,1241,1243],{"class":298,"line":1242},14,[296,1244,625],{"emptyLinePlaceholder":624},[296,1246,1248,1251,1253,1255,1258,1261],{"class":298,"line":1247},15,[296,1249,1250],{"class":306},"    static",[296,1252,511],{"class":313},[296,1254,514],{"class":302},[296,1256,1257],{"class":313},"PortsList",[296,1259,1260],{"class":313}," providedPorts",[296,1262,1263],{"class":302},"()\n",[296,1265,1267],{"class":298,"line":1266},16,[296,1268,1269],{"class":302},"    {\n",[296,1271,1273,1276,1279,1282,1284,1287,1289,1292,1295,1298],{"class":298,"line":1272},17,[296,1274,1275],{"class":306},"        return",[296,1277,1278],{"class":302}," {",[296,1280,1281],{"class":313},"BT",[296,1283,514],{"class":302},[296,1285,1286],{"class":313},"InputPort",[296,1288,397],{"class":302},[296,1290,1291],{"class":306},"bool",[296,1293,1294],{"class":302},">(",[296,1296,1297],{"class":408},"\"allowed\"",[296,1299,1300],{"class":302},")};\n",[296,1302,1304],{"class":298,"line":1303},18,[296,1305,1306],{"class":302},"    }\n",[296,1308,1310],{"class":298,"line":1309},19,[296,1311,625],{"emptyLinePlaceholder":624},[296,1313,1315,1318,1320,1322,1325,1328],{"class":298,"line":1314},20,[296,1316,1317],{"class":313},"    BT",[296,1319,514],{"class":302},[296,1321,517],{"class":313},[296,1323,1324],{"class":313}," tick",[296,1326,1327],{"class":302},"() ",[296,1329,1330],{"class":306},"override\n",[296,1332,1334],{"class":298,"line":1333},21,[296,1335,1269],{"class":302},[296,1337,1339,1342,1345,1347,1350,1352,1354,1356,1358],{"class":298,"line":1338},22,[296,1340,1341],{"class":306},"        auto",[296,1343,1344],{"class":302}," allowed ",[296,1346,307],{"class":306},[296,1348,1349],{"class":313}," getInput",[296,1351,397],{"class":302},[296,1353,1291],{"class":306},[296,1355,1294],{"class":302},[296,1357,1297],{"class":408},[296,1359,1360],{"class":302},");\n",[296,1362,1364,1367,1370,1373],{"class":298,"line":1363},23,[296,1365,1366],{"class":306},"        if",[296,1368,1369],{"class":302}," (",[296,1371,1372],{"class":306},"!",[296,1374,1375],{"class":302},"allowed)\n",[296,1377,1379],{"class":298,"line":1378},24,[296,1380,1381],{"class":302},"        {\n",[296,1383,1385,1388,1390,1392,1395,1397,1400,1403,1406],{"class":298,"line":1384},25,[296,1386,1387],{"class":306},"            throw",[296,1389,511],{"class":313},[296,1391,514],{"class":302},[296,1393,1394],{"class":313},"RuntimeError",[296,1396,1183],{"class":302},[296,1398,1399],{"class":408},"\"Cannot read input [allowed]: \"",[296,1401,1402],{"class":302},", allowed.",[296,1404,1405],{"class":313},"error",[296,1407,1408],{"class":302},"());\n",[296,1410,1412],{"class":298,"line":1411},26,[296,1413,1414],{"class":302},"        }\n",[296,1416,1418,1421,1424,1427],{"class":298,"line":1417},27,[296,1419,1420],{"class":313},"        std",[296,1422,1423],{"class":302},"::cout ",[296,1425,1426],{"class":306},"\u003C\u003C",[296,1428,1429],{"class":408}," \"[NavigationAllowed] allowed=\"\n",[296,1431,1433,1436,1439,1441,1443,1446,1449,1452,1455,1458,1460,1463,1466,1469],{"class":298,"line":1432},28,[296,1434,1435],{"class":306},"                  \u003C\u003C",[296,1437,1438],{"class":302}," (allowed.",[296,1440,459],{"class":313},[296,1442,1327],{"class":302},[296,1444,1445],{"class":306},"?",[296,1447,1448],{"class":408}," \"true\"",[296,1450,1451],{"class":306}," :",[296,1453,1454],{"class":408}," \"false\"",[296,1456,1457],{"class":302},") ",[296,1459,1426],{"class":306},[296,1461,1462],{"class":408}," '",[296,1464,1465],{"class":495},"\\n",[296,1467,1468],{"class":408},"'",[296,1470,1471],{"class":302},";\n",[296,1473,1475,1477,1480,1482,1484,1486,1488,1490,1492,1495,1498,1500,1502,1504],{"class":298,"line":1474},29,[296,1476,1275],{"class":306},[296,1478,1479],{"class":302}," allowed.",[296,1481,459],{"class":313},[296,1483,1327],{"class":302},[296,1485,1445],{"class":306},[296,1487,511],{"class":313},[296,1489,514],{"class":302},[296,1491,517],{"class":313},[296,1493,1494],{"class":302},"::SUCCESS ",[296,1496,1497],{"class":306},":",[296,1499,511],{"class":313},[296,1501,514],{"class":302},[296,1503,517],{"class":313},[296,1505,1506],{"class":302},"::FAILURE;\n",[296,1508,1510],{"class":298,"line":1509},30,[296,1511,1306],{"class":302},[296,1513,1515],{"class":298,"line":1514},31,[296,1516,1517],{"class":302},"};\n",[296,1519,1521],{"class":298,"line":1520},32,[296,1522,625],{"emptyLinePlaceholder":624},[296,1524,1526,1528,1531,1533,1535,1537,1539],{"class":298,"line":1525},33,[296,1527,1147],{"class":306},[296,1529,1530],{"class":313}," NavigateToGoal",[296,1532,1153],{"class":302},[296,1534,1156],{"class":306},[296,1536,511],{"class":313},[296,1538,514],{"class":302},[296,1540,1541],{"class":313},"StatefulActionNode\n",[296,1543,1545],{"class":298,"line":1544},34,[296,1546,644],{"class":302},[296,1548,1550],{"class":298,"line":1549},35,[296,1551,1174],{"class":306},[296,1553,1555,1558,1560,1562,1564,1566,1568,1570,1572,1574,1576,1578,1580,1582,1584,1586],{"class":298,"line":1554},36,[296,1556,1557],{"class":313},"    NavigateToGoal",[296,1559,1183],{"class":302},[296,1561,1186],{"class":306},[296,1563,1189],{"class":313},[296,1565,514],{"class":302},[296,1567,1194],{"class":313},[296,1569,1197],{"class":306},[296,1571,1201],{"class":1200},[296,1573,1204],{"class":302},[296,1575,1186],{"class":306},[296,1577,511],{"class":313},[296,1579,514],{"class":302},[296,1581,1213],{"class":313},[296,1583,1197],{"class":306},[296,1585,1218],{"class":1200},[296,1587,1221],{"class":302},[296,1589,1591,1593,1595],{"class":298,"line":1590},37,[296,1592,1227],{"class":302},[296,1594,119],{"class":313},[296,1596,1233],{"class":302},[296,1598,1600],{"class":298,"line":1599},38,[296,1601,1239],{"class":302},[296,1603,1605],{"class":298,"line":1604},39,[296,1606,625],{"emptyLinePlaceholder":624},[296,1608,1610,1612,1614,1616,1618,1620],{"class":298,"line":1609},40,[296,1611,1250],{"class":306},[296,1613,511],{"class":313},[296,1615,514],{"class":302},[296,1617,1257],{"class":313},[296,1619,1260],{"class":313},[296,1621,1263],{"class":302},[296,1623,1625],{"class":298,"line":1624},41,[296,1626,1269],{"class":302},[296,1628,1630,1632,1634,1636,1638,1640,1642,1645,1647,1649,1651,1654],{"class":298,"line":1629},42,[296,1631,1275],{"class":306},[296,1633,1278],{"class":302},[296,1635,1281],{"class":313},[296,1637,514],{"class":302},[296,1639,1286],{"class":313},[296,1641,397],{"class":302},[296,1643,1644],{"class":313},"std",[296,1646,514],{"class":302},[296,1648,1194],{"class":313},[296,1650,1294],{"class":302},[296,1652,1653],{"class":408},"\"goal\"",[296,1655,1656],{"class":302},"),\n",[296,1658,1660,1663,1665,1667,1669,1672,1674,1677,1679,1681,1683,1686],{"class":298,"line":1659},43,[296,1661,1662],{"class":313},"                BT",[296,1664,514],{"class":302},[296,1666,1286],{"class":313},[296,1668,397],{"class":302},[296,1670,1671],{"class":306},"int",[296,1673,1294],{"class":302},[296,1675,1676],{"class":408},"\"ticks\"",[296,1678,1204],{"class":302},[296,1680,566],{"class":495},[296,1682,1204],{"class":302},[296,1684,1685],{"class":408},"\"完成导航所需的 onRunning 调用次数\"",[296,1687,1300],{"class":302},[296,1689,1691],{"class":298,"line":1690},44,[296,1692,1306],{"class":302},[296,1694,1696],{"class":298,"line":1695},45,[296,1697,625],{"emptyLinePlaceholder":624},[296,1699,1701,1703,1705,1707,1710,1712],{"class":298,"line":1700},46,[296,1702,1317],{"class":313},[296,1704,514],{"class":302},[296,1706,517],{"class":313},[296,1708,1709],{"class":313}," onStart",[296,1711,1327],{"class":302},[296,1713,1330],{"class":306},[296,1715,1717],{"class":298,"line":1716},47,[296,1718,1269],{"class":302},[296,1720,1722,1724,1727,1729,1731,1733,1735,1737,1739,1741,1743],{"class":298,"line":1721},48,[296,1723,1341],{"class":306},[296,1725,1726],{"class":302}," goal ",[296,1728,307],{"class":306},[296,1730,1349],{"class":313},[296,1732,397],{"class":302},[296,1734,1644],{"class":313},[296,1736,514],{"class":302},[296,1738,1194],{"class":313},[296,1740,1294],{"class":302},[296,1742,1653],{"class":408},[296,1744,1360],{"class":302},[296,1746,1748,1750,1753,1755,1757,1759,1761,1763,1765],{"class":298,"line":1747},49,[296,1749,1341],{"class":306},[296,1751,1752],{"class":302}," ticks ",[296,1754,307],{"class":306},[296,1756,1349],{"class":313},[296,1758,397],{"class":302},[296,1760,1671],{"class":306},[296,1762,1294],{"class":302},[296,1764,1676],{"class":408},[296,1766,1360],{"class":302},[296,1768,1770,1772,1774,1776],{"class":298,"line":1769},50,[296,1771,1366],{"class":306},[296,1773,1369],{"class":302},[296,1775,1372],{"class":306},[296,1777,1778],{"class":302},"goal)\n",[296,1780,1782],{"class":298,"line":1781},51,[296,1783,1381],{"class":302},[296,1785,1787,1789,1791,1793,1795,1797,1800,1803,1805],{"class":298,"line":1786},52,[296,1788,1387],{"class":306},[296,1790,511],{"class":313},[296,1792,514],{"class":302},[296,1794,1394],{"class":313},[296,1796,1183],{"class":302},[296,1798,1799],{"class":408},"\"Cannot read input [goal]: \"",[296,1801,1802],{"class":302},", goal.",[296,1804,1405],{"class":313},[296,1806,1408],{"class":302},[296,1808,1810],{"class":298,"line":1809},53,[296,1811,1414],{"class":302},[296,1813,1815,1817,1819,1821],{"class":298,"line":1814},54,[296,1816,1366],{"class":306},[296,1818,1369],{"class":302},[296,1820,1372],{"class":306},[296,1822,1823],{"class":302},"ticks)\n",[296,1825,1827],{"class":298,"line":1826},55,[296,1828,1381],{"class":302},[296,1830,1832,1834,1836,1838,1840,1842,1845,1848,1850],{"class":298,"line":1831},56,[296,1833,1387],{"class":306},[296,1835,511],{"class":313},[296,1837,514],{"class":302},[296,1839,1394],{"class":313},[296,1841,1183],{"class":302},[296,1843,1844],{"class":408},"\"Cannot read input [ticks]: \"",[296,1846,1847],{"class":302},", ticks.",[296,1849,1405],{"class":313},[296,1851,1408],{"class":302},[296,1853,1855],{"class":298,"line":1854},57,[296,1856,1414],{"class":302},[296,1858,1860,1862,1865,1867,1870,1873,1875,1878,1880,1882,1884,1886,1889],{"class":298,"line":1859},58,[296,1861,1366],{"class":306},[296,1863,1864],{"class":302}," (goal.",[296,1866,459],{"class":313},[296,1868,1869],{"class":302},"().",[296,1871,1872],{"class":313},"empty",[296,1874,1327],{"class":302},[296,1876,1877],{"class":306},"||",[296,1879,477],{"class":302},[296,1881,459],{"class":313},[296,1883,1327],{"class":302},[296,1885,397],{"class":306},[296,1887,1888],{"class":495}," 1",[296,1890,1221],{"class":302},[296,1892,1894],{"class":298,"line":1893},59,[296,1895,1381],{"class":302},[296,1897,1899,1901,1903,1905,1908,1910,1913],{"class":298,"line":1898},60,[296,1900,1387],{"class":306},[296,1902,1189],{"class":313},[296,1904,514],{"class":302},[296,1906,1907],{"class":313},"runtime_error",[296,1909,1183],{"class":302},[296,1911,1912],{"class":408},"\"goal must not be empty and ticks must be positive\"",[296,1914,1360],{"class":302},[296,1916,1918],{"class":298,"line":1917},61,[296,1919,1414],{"class":302},[296,1921,1923],{"class":298,"line":1922},62,[296,1924,625],{"emptyLinePlaceholder":624},[296,1926,1928,1931,1933,1935,1937,1939],{"class":298,"line":1927},63,[296,1929,1930],{"class":302},"        goal_ ",[296,1932,307],{"class":306},[296,1934,456],{"class":302},[296,1936,459],{"class":313},[296,1938,462],{"class":302},[296,1940,1941],{"class":465},"             \u002F\u002F 保存本次目标，供后续回调使用\n",[296,1943,1945,1948,1950,1952,1954,1956],{"class":298,"line":1944},64,[296,1946,1947],{"class":302},"        required_ticks_ ",[296,1949,307],{"class":306},[296,1951,477],{"class":302},[296,1953,459],{"class":313},[296,1955,462],{"class":302},[296,1957,1958],{"class":465},"  \u002F\u002F 保存模拟完成所需的检查次数，本例为 3\n",[296,1960,1962,1965,1967,1969,1971],{"class":298,"line":1961},65,[296,1963,1964],{"class":302},"        completed_ticks_ ",[296,1966,307],{"class":306},[296,1968,496],{"class":495},[296,1970,499],{"class":302},[296,1972,1973],{"class":465},"             \u002F\u002F 每次开始新任务，都从零次检查开始\n",[296,1975,1977],{"class":298,"line":1976},66,[296,1978,1979],{"class":465},"        \u002F\u002F 真实导航通常在这里发送一次请求，本例只保存模拟任务状态。\n",[296,1981,1983,1985,1987,1989,1992,1995,1998,2000,2002,2004,2006],{"class":298,"line":1982},67,[296,1984,1420],{"class":313},[296,1986,1423],{"class":302},[296,1988,1426],{"class":306},[296,1990,1991],{"class":408}," \"[NavigateToGoal] start goal=\"",[296,1993,1994],{"class":306}," \u003C\u003C",[296,1996,1997],{"class":302}," goal_ ",[296,1999,1426],{"class":306},[296,2001,1462],{"class":408},[296,2003,1465],{"class":495},[296,2005,1468],{"class":408},[296,2007,1471],{"class":302},[296,2009,2011],{"class":298,"line":2010},68,[296,2012,2013],{"class":465},"        \u002F\u002F 结束本次回调并报告“尚未完成”，后续 tick 再进入 onRunning。\n",[296,2015,2017,2019,2021,2023,2025],{"class":298,"line":2016},69,[296,2018,1275],{"class":306},[296,2020,511],{"class":313},[296,2022,514],{"class":302},[296,2024,517],{"class":313},[296,2026,2027],{"class":302},"::RUNNING;\n",[296,2029,2031],{"class":298,"line":2030},70,[296,2032,1306],{"class":302},[296,2034,2036],{"class":298,"line":2035},71,[296,2037,625],{"emptyLinePlaceholder":624},[296,2039,2041,2043,2045,2047,2050,2052],{"class":298,"line":2040},72,[296,2042,1317],{"class":313},[296,2044,514],{"class":302},[296,2046,517],{"class":313},[296,2048,2049],{"class":313}," onRunning",[296,2051,1327],{"class":302},[296,2053,1330],{"class":306},[296,2055,2057],{"class":298,"line":2056},73,[296,2058,1269],{"class":302},[296,2060,2062],{"class":298,"line":2061},74,[296,2063,2064],{"class":465},"        \u002F\u002F 每次进入这个回调，模拟检查次数就加一；函数返回后成员计数仍会保留。\n",[296,2066,2068,2071],{"class":298,"line":2067},75,[296,2069,2070],{"class":306},"        ++",[296,2072,2073],{"class":302},"completed_ticks_;\n",[296,2075,2077,2079,2081,2083,2086,2088],{"class":298,"line":2076},76,[296,2078,1420],{"class":313},[296,2080,1423],{"class":302},[296,2082,1426],{"class":306},[296,2084,2085],{"class":408}," \"[NavigateToGoal] progress=\"",[296,2087,1994],{"class":306},[296,2089,2090],{"class":302}," completed_ticks_\n",[296,2092,2094,2096,2099,2101,2104,2106,2108,2110,2112],{"class":298,"line":2093},77,[296,2095,1435],{"class":306},[296,2097,2098],{"class":408}," '\u002F'",[296,2100,1994],{"class":306},[296,2102,2103],{"class":302}," required_ticks_ ",[296,2105,1426],{"class":306},[296,2107,1462],{"class":408},[296,2109,1465],{"class":495},[296,2111,1468],{"class":408},[296,2113,1471],{"class":302},[296,2115,2117],{"class":298,"line":2116},78,[296,2118,2119],{"class":465},"        \u002F\u002F 本例把“检查次数达到要求”当作完成条件，没有查询机器人的真实位置。\n",[296,2121,2123,2125,2127,2129],{"class":298,"line":2122},79,[296,2124,1366],{"class":306},[296,2126,633],{"class":302},[296,2128,636],{"class":306},[296,2130,639],{"class":302},[296,2132,2134],{"class":298,"line":2133},80,[296,2135,1381],{"class":302},[296,2137,2139,2142,2144,2146,2149,2151,2153,2155,2157,2159,2161],{"class":298,"line":2138},81,[296,2140,2141],{"class":313},"            std",[296,2143,1423],{"class":302},[296,2145,1426],{"class":306},[296,2147,2148],{"class":408}," \"[NavigateToGoal] arrived goal=\"",[296,2150,1994],{"class":306},[296,2152,1997],{"class":302},[296,2154,1426],{"class":306},[296,2156,1462],{"class":408},[296,2158,1465],{"class":495},[296,2160,1468],{"class":408},[296,2162,1471],{"class":302},[296,2164,2166],{"class":298,"line":2165},82,[296,2167,2168],{"class":465},"            \u002F\u002F 已满足模拟完成条件，向父节点报告成功，本次函数到这里结束。\n",[296,2170,2172,2175,2177,2179,2181],{"class":298,"line":2171},83,[296,2173,2174],{"class":306},"            return",[296,2176,511],{"class":313},[296,2178,514],{"class":302},[296,2180,517],{"class":313},[296,2182,2183],{"class":302},"::SUCCESS;\n",[296,2185,2187],{"class":298,"line":2186},84,[296,2188,1414],{"class":302},[296,2190,2192],{"class":298,"line":2191},85,[296,2193,2194],{"class":465},"        \u002F\u002F 尚未达到要求，结束本次检查，等待后续 tick 再进入这个回调。\n",[296,2196,2198,2200,2202,2204,2206],{"class":298,"line":2197},86,[296,2199,1275],{"class":306},[296,2201,511],{"class":313},[296,2203,514],{"class":302},[296,2205,517],{"class":313},[296,2207,2027],{"class":302},[296,2209,2211],{"class":298,"line":2210},87,[296,2212,1306],{"class":302},[296,2214,2216],{"class":298,"line":2215},88,[296,2217,625],{"emptyLinePlaceholder":624},[296,2219,2221,2224,2227,2229],{"class":298,"line":2220},89,[296,2222,2223],{"class":306},"    void",[296,2225,2226],{"class":313}," onHalted",[296,2228,1327],{"class":302},[296,2230,1330],{"class":306},[296,2232,2234],{"class":298,"line":2233},90,[296,2235,1269],{"class":302},[296,2237,2239],{"class":298,"line":2238},91,[296,2240,2241],{"class":465},"        \u002F\u002F 运行中的任务收到中止要求时，基类才会调用这个回调。\n",[296,2243,2245],{"class":298,"line":2244},92,[296,2246,2247],{"class":465},"        \u002F\u002F 真实导航在这里取消请求、停止当前任务并清理资源。\n",[296,2249,2251,2253,2255,2257,2260,2262],{"class":298,"line":2250},93,[296,2252,1420],{"class":313},[296,2254,1423],{"class":302},[296,2256,1426],{"class":306},[296,2258,2259],{"class":408}," \"[NavigateToGoal] halted goal=\"",[296,2261,1994],{"class":306},[296,2263,2264],{"class":302}," goal_\n",[296,2266,2268,2270,2273,2275,2278,2280,2282,2284,2286],{"class":298,"line":2267},94,[296,2269,1435],{"class":306},[296,2271,2272],{"class":408}," \", progress=\"",[296,2274,1994],{"class":306},[296,2276,2277],{"class":302}," completed_ticks_ ",[296,2279,1426],{"class":306},[296,2281,1462],{"class":408},[296,2283,1465],{"class":495},[296,2285,1468],{"class":408},[296,2287,1471],{"class":302},[296,2289,2291,2293,2295,2297],{"class":298,"line":2290},95,[296,2292,1964],{"class":302},[296,2294,307],{"class":306},[296,2296,496],{"class":495},[296,2298,1471],{"class":302},[296,2300,2302],{"class":298,"line":2301},96,[296,2303,1306],{"class":302},[296,2305,2307],{"class":298,"line":2306},97,[296,2308,625],{"emptyLinePlaceholder":624},[296,2310,2312],{"class":298,"line":2311},98,[296,2313,2314],{"class":306},"private:\n",[296,2316,2318,2321,2324],{"class":298,"line":2317},99,[296,2319,2320],{"class":313},"    std",[296,2322,2323],{"class":302},"::string goal_;",[296,2325,2326],{"class":465},"          \u002F\u002F 本次目标\n",[296,2328,2330,2333,2335,2337,2339,2341],{"class":298,"line":2329},100,[296,2331,2332],{"class":306},"    int",[296,2334,2103],{"class":302},[296,2336,307],{"class":306},[296,2338,496],{"class":495},[296,2340,499],{"class":302},[296,2342,2343],{"class":465},"    \u002F\u002F 模拟完成所需的运行检查次数，由 onStart 读取\n",[296,2345,2347,2349,2351,2353,2355,2357],{"class":298,"line":2346},101,[296,2348,2332],{"class":306},[296,2350,2277],{"class":302},[296,2352,307],{"class":306},[296,2354,496],{"class":495},[296,2356,499],{"class":302},[296,2358,2359],{"class":465},"   \u002F\u002F 已完成的运行检查次数，可跨多次回调保存\n",[296,2361,2363],{"class":298,"line":2362},102,[296,2364,1517],{"class":302},[296,2366,2368],{"class":298,"line":2367},103,[296,2369,625],{"emptyLinePlaceholder":624},[296,2371,2373,2375,2378],{"class":298,"line":2372},104,[296,2374,1671],{"class":306},[296,2376,2377],{"class":313}," main",[296,2379,1263],{"class":302},[296,2381,2383],{"class":298,"line":2382},105,[296,2384,644],{"class":302},[296,2386,2388],{"class":298,"line":2387},106,[296,2389,2390],{"class":465},"    \u002F\u002F 先用 false 跑通；改为 true 后，在第二次根 tick 后禁止继续导航。（用于测试onHalted()触发）\n",[296,2392,2394,2397,2400,2403,2405,2408],{"class":298,"line":2393},107,[296,2395,2396],{"class":306},"    const",[296,2398,2399],{"class":306}," bool",[296,2401,2402],{"class":302}," cancel_after_two_ticks ",[296,2404,307],{"class":306},[296,2406,2407],{"class":495}," false",[296,2409,1471],{"class":302},[296,2411,2413],{"class":298,"line":2412},108,[296,2414,625],{"emptyLinePlaceholder":624},[296,2416,2418],{"class":298,"line":2417},109,[296,2419,2420],{"class":306},"    try\n",[296,2422,2424],{"class":298,"line":2423},110,[296,2425,1269],{"class":302},[296,2427,2429,2432],{"class":298,"line":2428},111,[296,2430,2431],{"class":313},"        BT",[296,2433,2434],{"class":302},"::BehaviorTreeFactory factory;\n",[296,2436,2438,2441,2443,2445,2448,2450,2453],{"class":298,"line":2437},112,[296,2439,2440],{"class":302},"        factory.registerNodeType",[296,2442,397],{"class":306},[296,2444,758],{"class":302},[296,2446,2447],{"class":306},">",[296,2449,1183],{"class":302},[296,2451,2452],{"class":408},"\"NavigationAllowed\"",[296,2454,1360],{"class":302},[296,2456,2458,2460,2462,2464,2466,2468,2471],{"class":298,"line":2457},113,[296,2459,2440],{"class":302},[296,2461,397],{"class":306},[296,2463,337],{"class":302},[296,2465,2447],{"class":306},[296,2467,1183],{"class":302},[296,2469,2470],{"class":408},"\"NavigateToGoal\"",[296,2472,1360],{"class":302},[296,2474,2476],{"class":298,"line":2475},114,[296,2477,625],{"emptyLinePlaceholder":624},[296,2479,2481,2483,2486,2488,2490,2492,2495,2497,2500],{"class":298,"line":2480},115,[296,2482,1341],{"class":306},[296,2484,2485],{"class":302}," blackboard ",[296,2487,307],{"class":306},[296,2489,511],{"class":313},[296,2491,514],{"class":302},[296,2493,2494],{"class":313},"Blackboard",[296,2496,514],{"class":302},[296,2498,2499],{"class":313},"create",[296,2501,317],{"class":302},[296,2503,2505,2508,2511,2513,2516,2518,2521],{"class":298,"line":2504},116,[296,2506,2507],{"class":302},"        blackboard->",[296,2509,2510],{"class":313},"set",[296,2512,1183],{"class":302},[296,2514,2515],{"class":408},"\"navigation_allowed\"",[296,2517,1204],{"class":302},[296,2519,2520],{"class":495},"true",[296,2522,1360],{"class":302},[296,2524,2526,2528,2531,2533,2536,2539],{"class":298,"line":2525},117,[296,2527,1341],{"class":306},[296,2529,2530],{"class":302}," tree ",[296,2532,307],{"class":306},[296,2534,2535],{"class":302}," factory.",[296,2537,2538],{"class":313},"createTreeFromFile",[296,2540,2541],{"class":302},"(BT_XML_PATH, blackboard);\n",[296,2543,2545],{"class":298,"line":2544},118,[296,2546,625],{"emptyLinePlaceholder":624},[296,2548,2550,2552,2555,2557,2559,2561,2563],{"class":298,"line":2549},119,[296,2551,2431],{"class":313},[296,2553,2554],{"class":302},"::NodeStatus result ",[296,2556,307],{"class":306},[296,2558,511],{"class":313},[296,2560,514],{"class":302},[296,2562,517],{"class":313},[296,2564,2027],{"class":302},[296,2566,2568,2571,2574,2576,2578],{"class":298,"line":2567},120,[296,2569,2570],{"class":306},"        int",[296,2572,2573],{"class":302}," tick_count ",[296,2575,307],{"class":306},[296,2577,496],{"class":495},[296,2579,1471],{"class":302},[296,2581,2583,2586,2589,2592,2594,2596,2598],{"class":298,"line":2582},121,[296,2584,2585],{"class":306},"        while",[296,2587,2588],{"class":302}," (result ",[296,2590,2591],{"class":306},"==",[296,2593,511],{"class":313},[296,2595,514],{"class":302},[296,2597,517],{"class":313},[296,2599,2600],{"class":302},"::RUNNING)\n",[296,2602,2604],{"class":298,"line":2603},122,[296,2605,1381],{"class":302},[296,2607,2609,2611,2613,2615,2618,2620,2623,2626,2628,2630,2632,2634],{"class":298,"line":2608},123,[296,2610,2141],{"class":313},[296,2612,1423],{"class":302},[296,2614,1426],{"class":306},[296,2616,2617],{"class":408}," \"--- tick \"",[296,2619,1994],{"class":306},[296,2621,2622],{"class":306}," ++",[296,2624,2625],{"class":302},"tick_count ",[296,2627,1426],{"class":306},[296,2629,1462],{"class":408},[296,2631,1465],{"class":495},[296,2633,1468],{"class":408},[296,2635,1471],{"class":302},[296,2637,2639],{"class":298,"line":2638},124,[296,2640,2641],{"class":465},"            \u002F\u002F 从根驱动一次；执行到导航节点时，由基类按当前状态选择回调。\n",[296,2643,2645,2648,2650,2652,2654],{"class":298,"line":2644},125,[296,2646,2647],{"class":302},"            result ",[296,2649,307],{"class":306},[296,2651,310],{"class":302},[296,2653,314],{"class":313},[296,2655,317],{"class":302},[296,2657,2659,2661,2663,2665,2668,2670,2672,2674,2677,2680,2682,2684,2686,2688],{"class":298,"line":2658},126,[296,2660,2141],{"class":313},[296,2662,1423],{"class":302},[296,2664,1426],{"class":306},[296,2666,2667],{"class":408}," \"Root returned: \"",[296,2669,1994],{"class":306},[296,2671,511],{"class":313},[296,2673,514],{"class":302},[296,2675,2676],{"class":313},"toStr",[296,2678,2679],{"class":302},"(result) ",[296,2681,1426],{"class":306},[296,2683,1462],{"class":408},[296,2685,1465],{"class":495},[296,2687,1468],{"class":408},[296,2689,1471],{"class":302},[296,2691,2693,2696,2698,2701,2703,2705,2707],{"class":298,"line":2692},127,[296,2694,2695],{"class":306},"            if",[296,2697,2588],{"class":302},[296,2699,2700],{"class":306},"!=",[296,2702,511],{"class":313},[296,2704,514],{"class":302},[296,2706,517],{"class":313},[296,2708,2600],{"class":302},[296,2710,2712],{"class":298,"line":2711},128,[296,2713,2714],{"class":302},"            {\n",[296,2716,2718,2721],{"class":298,"line":2717},129,[296,2719,2720],{"class":306},"                break",[296,2722,1471],{"class":302},[296,2724,2726],{"class":298,"line":2725},130,[296,2727,2728],{"class":302},"            }\n",[296,2730,2732],{"class":298,"line":2731},131,[296,2733,625],{"emptyLinePlaceholder":624},[296,2735,2737,2739,2742,2745,2747,2749,2752],{"class":298,"line":2736},132,[296,2738,2695],{"class":306},[296,2740,2741],{"class":302}," (cancel_after_two_ticks ",[296,2743,2744],{"class":306},"&&",[296,2746,2573],{"class":302},[296,2748,2591],{"class":306},[296,2750,2751],{"class":495}," 2",[296,2753,1221],{"class":302},[296,2755,2757],{"class":298,"line":2756},133,[296,2758,2714],{"class":302},[296,2760,2762,2765,2767,2769,2771,2773,2776],{"class":298,"line":2761},134,[296,2763,2764],{"class":302},"                blackboard->",[296,2766,2510],{"class":313},[296,2768,1183],{"class":302},[296,2770,2515],{"class":408},[296,2772,1204],{"class":302},[296,2774,2775],{"class":495},"false",[296,2777,1360],{"class":302},[296,2779,2781,2784,2786,2788,2791,2793,2796],{"class":298,"line":2780},135,[296,2782,2783],{"class":313},"                std",[296,2785,1423],{"class":302},[296,2787,1426],{"class":306},[296,2789,2790],{"class":408}," \"[main] navigation is no longer allowed",[296,2792,1465],{"class":495},[296,2794,2795],{"class":408},"\"",[296,2797,1471],{"class":302},[296,2799,2801],{"class":298,"line":2800},136,[296,2802,2728],{"class":302},[296,2804,2806],{"class":298,"line":2805},137,[296,2807,2808],{"class":465},"            \u002F\u002F 等待放在主循环中，节点回调本身不长时间阻塞。\n",[296,2810,2812,2815,2818,2820,2822,2824,2827,2829,2832,2834,2837],{"class":298,"line":2811},138,[296,2813,2814],{"class":302},"            tree.",[296,2816,2817],{"class":313},"sleep",[296,2819,1183],{"class":302},[296,2821,1644],{"class":313},[296,2823,514],{"class":302},[296,2825,2826],{"class":313},"chrono",[296,2828,514],{"class":302},[296,2830,2831],{"class":313},"milliseconds",[296,2833,1183],{"class":302},[296,2835,2836],{"class":495},"100",[296,2838,2839],{"class":302},"));\n",[296,2841,2843],{"class":298,"line":2842},139,[296,2844,1414],{"class":302},[296,2846,2848],{"class":298,"line":2847},140,[296,2849,625],{"emptyLinePlaceholder":624},[296,2851,2853,2855,2857,2859,2862,2864,2866,2868,2870,2872,2874,2876,2878,2880],{"class":298,"line":2852},141,[296,2854,1420],{"class":313},[296,2856,1423],{"class":302},[296,2858,1426],{"class":306},[296,2860,2861],{"class":408}," \"Tree result: \"",[296,2863,1994],{"class":306},[296,2865,511],{"class":313},[296,2867,514],{"class":302},[296,2869,2676],{"class":313},[296,2871,2679],{"class":302},[296,2873,1426],{"class":306},[296,2875,1462],{"class":408},[296,2877,1465],{"class":495},[296,2879,1468],{"class":408},[296,2881,1471],{"class":302},[296,2883,2885,2887,2890,2892,2894,2896,2898,2900,2902,2904,2906,2908],{"class":298,"line":2884},142,[296,2886,1275],{"class":306},[296,2888,2889],{"class":302}," result ",[296,2891,2591],{"class":306},[296,2893,511],{"class":313},[296,2895,514],{"class":302},[296,2897,517],{"class":313},[296,2899,1494],{"class":302},[296,2901,1445],{"class":306},[296,2903,496],{"class":495},[296,2905,1451],{"class":306},[296,2907,1888],{"class":495},[296,2909,1471],{"class":302},[296,2911,2913],{"class":298,"line":2912},143,[296,2914,1306],{"class":302},[296,2916,2918,2921,2923,2925,2927,2930,2932],{"class":298,"line":2917},144,[296,2919,2920],{"class":306},"    catch",[296,2922,1369],{"class":302},[296,2924,1186],{"class":306},[296,2926,1189],{"class":313},[296,2928,2929],{"class":302},"::exception",[296,2931,1197],{"class":306},[296,2933,2934],{"class":302}," error)\n",[296,2936,2938],{"class":298,"line":2937},145,[296,2939,1269],{"class":302},[296,2941,2943,2945,2948,2950,2953,2955,2958,2961,2963,2965,2967,2969,2971],{"class":298,"line":2942},146,[296,2944,1420],{"class":313},[296,2946,2947],{"class":302},"::cerr ",[296,2949,1426],{"class":306},[296,2951,2952],{"class":408}," \"Error: \"",[296,2954,1994],{"class":306},[296,2956,2957],{"class":302}," error.",[296,2959,2960],{"class":313},"what",[296,2962,1327],{"class":302},[296,2964,1426],{"class":306},[296,2966,1462],{"class":408},[296,2968,1465],{"class":495},[296,2970,1468],{"class":408},[296,2972,1471],{"class":302},[296,2974,2976,2978,2980],{"class":298,"line":2975},147,[296,2977,1275],{"class":306},[296,2979,2751],{"class":495},[296,2981,1471],{"class":302},[296,2983,2985],{"class":298,"line":2984},148,[296,2986,1306],{"class":302},[296,2988,2990],{"class":298,"line":2989},149,[296,2991,668],{"class":302},[20,2993,2994,36,2996,36,2998,3000,3001,3003,3004,3007],{},[64,2995,547],{},[64,2997,561],{},[64,2999,576],{}," 是节点对象的成员，能够跨越多次回调保存当前任务的数据。\n",[64,3002,230],{}," 中的 ",[64,3005,3006],{},"tick_count"," 则统计根节点执行次数，两者含义不同。",[281,3009,3011,3014],{"id":3010},"treesleep-的参数与作用",[64,3012,3013],{},"tree.sleep()"," 的参数与作用",[20,3016,3017,3018,3021,3022,3024,3025,3028],{},"前一篇的 ",[64,3019,3020],{},"tickRootWhileRunning()"," 在库内部等待并重复 tick。\n本篇需要在两次 tick 之间模拟条件变化，因此把循环写在 ",[64,3023,230],{}," 中，并直接使用 ",[64,3026,3027],{},"BT::Tree"," 的等待接口：",[92,3030,3032],{"className":290,"code":3031,"language":292,"meta":98,"style":98},"void sleep(std::chrono::system_clock::duration timeout);\n",[64,3033,3034],{"__ignoreMap":98},[296,3035,3036,3038,3041,3043,3045,3047,3049,3051,3054,3056,3059,3062],{"class":298,"line":299},[296,3037,217],{"class":306},[296,3039,3040],{"class":313}," sleep",[296,3042,1183],{"class":302},[296,3044,1644],{"class":313},[296,3046,514],{"class":302},[296,3048,2826],{"class":313},[296,3050,514],{"class":302},[296,3052,3053],{"class":313},"system_clock",[296,3055,514],{"class":302},[296,3057,3058],{"class":313},"duration",[296,3060,3061],{"class":1200}," timeout",[296,3063,1360],{"class":302},[20,3065,3066,3067,3070,3071,3074,3075,3078],{},"作用：让驱动树的当前线程等待一段时间，为下一次 tick 留出间隔。唯一的参数 ",[64,3068,3069],{},"timeout"," 是最长等待时长；",[64,3072,3073],{},"std::chrono::milliseconds(100)"," 构造一个表示 ",[53,3076,3077],{},"100 毫秒"," 的时长对象，可以传给这个参数。这个等待也可以被库的唤醒通知提前结束。",[20,3080,3081,3082,48,3084,3086,3087,3089,3090,3092,3093,3095],{},"返回值：",[64,3083,217],{},[64,3085,3013],{}," 本身不会执行节点，也不会创建导航线程；等待结束后，主程序仍需调用 ",[64,3088,754],{},"。后者没有参数，返回这一次根 tick 的 ",[64,3091,325],{},"。本例在结果为 ",[64,3094,115],{}," 时继续循环，在成功或失败时退出。",[20,3097,3098,3099,3102,3103,3105,3106,241,3108,3111],{},"其余注册、端口和 Blackboard 接口沿用前两篇的含义。例如 ",[64,3100,3101],{},"blackboard->set(\"navigation_allowed\", true)"," 中，第一个参数是键名，第二个参数是布尔值，模板类型由 ",[64,3104,2520],{}," 推导为 ",[64,3107,1291],{},[64,3109,3110],{},"InputPort\u003Cint>(\"ticks\", 3, \"...\")"," 的三个参数依次是端口名、默认值和说明。",[281,3113,1030],{"id":3114},"treesmissionxml",[20,3116,3117,3118,3120],{},"用下面的 XML 替换 ",[64,3119,1030],{}," 的原有内容，再保存。",[92,3122,3124],{"className":388,"code":3123,"language":390,"meta":98,"style":98},"\u003Croot main_tree_to_execute=\"MainTree\">\n    \u003CBehaviorTree ID=\"MainTree\">\n        \u003CReactiveSequence>\n            \u003CNavigationAllowed allowed=\"{navigation_allowed}\"\u002F>\n            \u003CNavigateToGoal goal=\"loading_area\" ticks=\"3\"\u002F>\n        \u003C\u002FReactiveSequence>\n    \u003C\u002FBehaviorTree>\n\u003C\u002Froot>\n",[64,3125,3126,3144,3161,3170,3187,3207,3216,3225],{"__ignoreMap":98},[296,3127,3128,3130,3133,3136,3138,3141],{"class":298,"line":299},[296,3129,397],{"class":302},[296,3131,3132],{"class":400},"root",[296,3134,3135],{"class":313}," main_tree_to_execute",[296,3137,307],{"class":302},[296,3139,3140],{"class":408},"\"MainTree\"",[296,3142,3143],{"class":302},">\n",[296,3145,3146,3149,3152,3155,3157,3159],{"class":298,"line":469},[296,3147,3148],{"class":302},"    \u003C",[296,3150,3151],{"class":400},"BehaviorTree",[296,3153,3154],{"class":313}," ID",[296,3156,307],{"class":302},[296,3158,3140],{"class":408},[296,3160,3143],{"class":302},[296,3162,3163,3166,3168],{"class":298,"line":487},[296,3164,3165],{"class":302},"        \u003C",[296,3167,884],{"class":400},[296,3169,3143],{"class":302},[296,3171,3172,3175,3177,3180,3182,3185],{"class":298,"line":505},[296,3173,3174],{"class":302},"            \u003C",[296,3176,758],{"class":400},[296,3178,3179],{"class":313}," allowed",[296,3181,307],{"class":302},[296,3183,3184],{"class":408},"\"{navigation_allowed}\"",[296,3186,420],{"class":302},[296,3188,3189,3191,3193,3195,3197,3199,3201,3203,3205],{"class":298,"line":647},[296,3190,3174],{"class":302},[296,3192,337],{"class":400},[296,3194,403],{"class":313},[296,3196,307],{"class":302},[296,3198,409],{"class":408},[296,3200,412],{"class":313},[296,3202,307],{"class":302},[296,3204,417],{"class":408},[296,3206,420],{"class":302},[296,3208,3209,3212,3214],{"class":298,"line":665},[296,3210,3211],{"class":302},"        \u003C\u002F",[296,3213,884],{"class":400},[296,3215,3143],{"class":302},[296,3217,3218,3221,3223],{"class":298,"line":671},[296,3219,3220],{"class":302},"    \u003C\u002F",[296,3222,3151],{"class":400},[296,3224,3143],{"class":302},[296,3226,3227,3230,3232],{"class":298,"line":1144},[296,3228,3229],{"class":302},"\u003C\u002F",[296,3231,3132],{"class":400},[296,3233,3143],{"class":302},[20,3235,3236,3237,3240],{},"普通节点端口仍然使用前一篇的写法：条件节点从父程序写入的 ",[64,3238,3239],{},"{navigation_allowed}"," 读取布尔值，导航节点从固定文本读取目标和次数。",[102,3242],{},[12,3244,3245],{"id":3245},"先观察一次完整的导航",[20,3247,3248,3249,3252,3253,3256,3257,3259,3260,3263],{},"保存全部文件，在 CMake Tools 中选择 ",[53,3250,3251],{},"Linux Debug","，执行 ",[53,3254,3255],{},"Configure → Build","，将运行目标设为 ",[53,3258,961],{},"，再点击 ",[53,3261,3262],{},"Launch","。本例的完整输出为：",[92,3265,3268],{"className":3266,"code":3267,"language":97,"meta":98},[95],"--- tick 1\n[NavigationAllowed] allowed=true\n[NavigateToGoal] start goal=loading_area\nRoot returned: RUNNING\n--- tick 2\n[NavigationAllowed] allowed=true\n[NavigateToGoal] progress=1\u002F3\nRoot returned: RUNNING\n--- tick 3\n[NavigationAllowed] allowed=true\n[NavigateToGoal] progress=2\u002F3\nRoot returned: RUNNING\n--- tick 4\n[NavigationAllowed] allowed=true\n[NavigateToGoal] progress=3\u002F3\n[NavigateToGoal] arrived goal=loading_area\nRoot returned: SUCCESS\nTree result: SUCCESS\n",[64,3269,3267],{"__ignoreMap":98},[20,3271,3272],{},[1077,3273],{"alt":98,"src":3274},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792412689286-c47ae6ea.webp",[20,3276,3277,3278,3281,3282,3284,3285,3288,3289,3291,3292,3295,3296,3298,3299,3301,3302,3305,3306,48],{},"这组输出对应前面的四次根 tick 表：第一次只有 ",[64,3279,3280],{},"start","，表示进入 ",[64,3283,89],{},"；后面三次出现 ",[64,3286,3287],{},"progress","，分别表示进入三次 ",[64,3290,81],{},"。\n最后一次先打印 ",[64,3293,3294],{},"progress=3\u002F3","，随后因为计数达到要求，打印 ",[64,3297,70],{}," 并返回 ",[64,3300,169],{},"，所以主程序最后显示 ",[64,3303,3304],{},"Tree result: SUCCESS","。\n这次完成的是我们约定的模拟任务，整个过程中不会调用 ",[64,3307,203],{},[20,3309,3310,3311,3313,3314,170,3316,3318,3319,3321,3322,3324],{},"主程序在 ",[64,3312,115],{}," 时继续 tick，在 ",[64,3315,169],{},[64,3317,173],{}," 时结束本次任务，并用 ",[64,3320,3013],{}," 留出等待间隔。等待放在主循环里，节点检查本身保持简短；把几秒钟的等待直接塞进 ",[64,3323,81],{},"，会同时拖慢整棵树对条件变化的响应。",[20,3326,3327,3328,3330,3331,3333,3334,3337,3338,3340,3341,170,3343,48],{},"3.8.7 的 ",[64,3329,85],{}," 在返回终态时还会重置根节点状态，因此应保存它的",[53,3332,142],{},"作为本次任务结果。稍后查看 ",[64,3335,3336],{},"rootNode()->status()"," 时可能已经是 ",[64,3339,158],{},"，不能据此否定刚刚返回的 ",[64,3342,169],{},[64,3344,173],{},[102,3346],{},[12,3348,3349],{"id":3349},"条件改变后中止正在运行的导航",[20,3351,3352,3353,3355],{},"在 ",[64,3354,230],{}," 中将已有的设置改为：",[92,3357,3359],{"className":290,"code":3358,"language":292,"meta":98,"style":98},"const bool cancel_after_two_ticks = true;\n",[64,3360,3361],{"__ignoreMap":98},[296,3362,3363,3365,3367,3369,3371,3374],{"class":298,"line":299},[296,3364,1186],{"class":306},[296,3366,2399],{"class":306},[296,3368,2402],{"class":302},[296,3370,307],{"class":306},[296,3372,3373],{"class":495}," true",[296,3375,1471],{"class":302},[20,3377,3378,3379,3382,3383,3386,3387,3389],{},"保存后 ",[53,3380,3381],{},"Build → Launch","。主程序会在第二次根 tick 结束后，将 ",[64,3384,3385],{},"navigation_allowed"," 改成 ",[64,3388,2775],{},"，模拟外部系统不再允许继续导航。输出为：",[92,3391,3394],{"className":3392,"code":3393,"language":97,"meta":98},[95],"--- tick 1\n[NavigationAllowed] allowed=true\n[NavigateToGoal] start goal=loading_area\nRoot returned: RUNNING\n--- tick 2\n[NavigationAllowed] allowed=true\n[NavigateToGoal] progress=1\u002F3\nRoot returned: RUNNING\n[main] navigation is no longer allowed\n--- tick 3\n[NavigationAllowed] allowed=false\n[NavigateToGoal] halted goal=loading_area, progress=1\nRoot returned: FAILURE\nTree result: FAILURE\n",[64,3395,3393],{"__ignoreMap":98},[20,3397,3398,3399,3401,3402,3404,3405,3407],{},"第三次根 tick 先检查 ",[64,3400,758],{},"。条件失败后，",[64,3403,884],{}," 中止还在运行的导航，触发 ",[64,3406,203],{},"，并将失败结果返回给主程序。此时导航不会再收到第三次根 tick 对应的运行检查，所以打印的进度仍是 1。",[20,3409,3410],{},"这次中止的先后关系为：",[92,3412,3415],{"className":3413,"code":3414,"language":97,"meta":98},[95],"第二次根 tick 结束：导航仍为 RUNNING，已检查一次\n    ↓\nmain() 将 Blackboard 中的 navigation_allowed 改为 false\n    ↓ 此时只是更新数据\n第三次根 tick：NavigationAllowed 读取新值，返回 FAILURE\n    ↓\nReactiveSequence 中止正在运行的导航\n    ↓\nStatefulActionNode::halt() 调用 NavigateToGoal::onHalted()\n    ↓\nReactiveSequence 返回 FAILURE，传回 main()\n",[64,3416,3414],{"__ignoreMap":98},[20,3418,3419,3420,3422,3423,3425,3426,3428,3429,3431],{},"因此，写入 ",[64,3421,2775],{}," 本身没有直接调用 ",[64,3424,203],{},"；本例要等下一次根 tick 重新检查条件，才会触发中止。\n",[64,3427,203],{}," 中的日志报告被中断时的进度，随后清零计数；它没有返回 ",[64,3430,173],{},"，失败结果由前置条件和父控制节点决定。",[20,3433,3434],{},[1077,3435],{"alt":98,"src":3436},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792412748786-0b96ae6c.webp",[20,3438,3439,3440,3442],{},"本例的取消只是清理模拟计数。对真实机器人，",[64,3441,203],{}," 中还需要实现对应的取消请求或停止逻辑，行为树本身不会替你完成设备控制。",[102,3444],{},[12,3446,3448],{"id":3447},"对照-sequence-怎样处理同一个变化","对照 Sequence 怎样处理同一个变化",[20,3450,3451,3452,3454,3455,42,3458,3461,3462,42,3465,3468,3469,3471],{},"保持取消设置为 ",[64,3453,2520],{},"，将 XML 中的 ",[64,3456,3457],{},"\u003CReactiveSequence>",[64,3459,3460],{},"\u003C\u002FReactiveSequence>"," 分别改为 ",[64,3463,3464],{},"\u003CSequence>",[64,3466,3467],{},"\u003C\u002FSequence>","。\n保存 XML 后直接 ",[53,3470,3262],{},"，无需手动重新编译 C++。",[20,3473,3474],{},[1077,3475],{"alt":98,"src":3476},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792412888008-8d20e1ee.webp",[20,3478,3479,3480,3483,3484],{},"这次虽然主程序仍会打印 ",[64,3481,3482],{},"navigation is no longer allowed","，导航却继续执行到成功。\n",[53,3485,3486,3487,3489,3490,3493],{},"在本次任务的 ",[64,3488,115],{}," 期间，普通 ",[64,3491,3492],{},"Sequence"," 从正在运行的导航继续，不会每次都重新检查已经成功的前置条件。",[122,3495,3496,3511],{},[125,3497,3498],{},[128,3499,3500,3503,3507],{},[131,3501,3502],{},"本例中的行为",[131,3504,3505],{},[64,3506,3492],{},[131,3508,3509],{},[64,3510,884],{},[144,3512,3513,3524,3535,3548],{},[128,3514,3515,3518,3521],{},[149,3516,3517],{},"正常导航期间检查条件",[149,3519,3520],{},"开始时一次",[149,3522,3523],{},"每次根 tick",[128,3525,3526,3529,3532],{},[149,3527,3528],{},"第二次根 tick 后将条件改成 false",[149,3530,3531],{},"导航继续完成",[149,3533,3534],{},"下一次根 tick 中止导航",[128,3536,3537,3542,3545],{},[149,3538,3539,3540],{},"是否调用导航的 ",[64,3541,203],{},[149,3543,3544],{},"否",[149,3546,3547],{},"是",[128,3549,3550,3553,3557],{},[149,3551,3552],{},"这次任务的结果",[149,3554,3555],{},[64,3556,169],{},[149,3558,3559],{},[64,3560,173],{},[20,3562,3563],{},[1077,3564],{"alt":98,"src":3565},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792412924057-0e277e45.webp",[20,3567,3568,3569,3571],{},"这个差别发生在一次尚未结束的任务内。\n普通 ",[64,3570,3492],{}," 结束并重置后，下一次任务仍会从前面的条件重新开始。",[3573,3574,3575,3578],"ul",{},[970,3576,3577],{},"Sequence：直接继续导航，跳过前面已经成功的条件。",[970,3579,3580],{},"ReactiveSequence：从第一个子节点重新执行，再检查条件；如果条件变成 FAILURE，就中止正在运行的导航。",[20,3582,3583],{},"ReactiveSequence它每次都从第一个子节点开始执行，前一个成功了，才继续下一个。\n比如前面放的不是条件检查，而是一个打印日志的动作：",[92,3585,3588],{"className":3586,"code":3587,"language":97,"meta":98},[95],"ReactiveSequence\n├── PrintMessage     打印“准备导航”，然后返回 SUCCESS\n└── NavigateToGoal   执行导航，未完成时返回 RUNNING\n",[64,3589,3587],{"__ignoreMap":98},[92,3591,3594],{"className":3592,"code":3593,"language":97,"meta":98},[95],"第一次 tick：打印“准备导航” → 启动导航\n第二次 tick：又打印“准备导航” → 检查导航进度\n第三次 tick：又打印“准备导航” → 检查导航进度\n……\n",[64,3595,3593],{"__ignoreMap":98},[20,3597,3598,3599,3601],{},"完成对照后，将 XML 恢复为 ",[64,3600,884],{},"，再进行后面的观察。",[102,3603],{},[12,3605,3606],{"id":3606},"主程序主动退出时先停止树",[20,3608,3609,3610,3612],{},"前面的中止由条件失败触发。\n主程序也可以主动决定停止当前任务，并调用 ",[64,3611,904],{},"，让中止沿树传播。",[20,3614,3615,3616,3619,3620,3622,3623,3625,3626,3628],{},"保持 ",[64,3617,3618],{},"cancel_after_two_ticks = true","，将 ",[64,3621,230],{}," 中修改 ",[64,3624,3385],{}," 的整个 ",[64,3627,630],{}," 代码块替换为：",[92,3630,3632],{"className":290,"code":3631,"language":292,"meta":98,"style":98},"            if (cancel_after_two_ticks && tick_count == 2)\n            {\n                std::cout \u003C\u003C \"[main] stop requested\\n\";\n                tree.haltTree();\n                std::cout \u003C\u003C \"Tree halted: \" \u003C\u003C BT::toStr(tree.rootNode()->status()) \u003C\u003C '\\n';\n                return 3;\n            }\n",[64,3633,3634,3650,3654,3671,3681,3725,3735],{"__ignoreMap":98},[296,3635,3636,3638,3640,3642,3644,3646,3648],{"class":298,"line":299},[296,3637,2695],{"class":306},[296,3639,2741],{"class":302},[296,3641,2744],{"class":306},[296,3643,2573],{"class":302},[296,3645,2591],{"class":306},[296,3647,2751],{"class":495},[296,3649,1221],{"class":302},[296,3651,3652],{"class":298,"line":469},[296,3653,2714],{"class":302},[296,3655,3656,3658,3660,3662,3665,3667,3669],{"class":298,"line":487},[296,3657,2783],{"class":313},[296,3659,1423],{"class":302},[296,3661,1426],{"class":306},[296,3663,3664],{"class":408}," \"[main] stop requested",[296,3666,1465],{"class":495},[296,3668,2795],{"class":408},[296,3670,1471],{"class":302},[296,3672,3673,3676,3679],{"class":298,"line":505},[296,3674,3675],{"class":302},"                tree.",[296,3677,3678],{"class":313},"haltTree",[296,3680,317],{"class":302},[296,3682,3683,3685,3687,3689,3692,3694,3696,3698,3700,3703,3706,3709,3712,3715,3717,3719,3721,3723],{"class":298,"line":647},[296,3684,2783],{"class":313},[296,3686,1423],{"class":302},[296,3688,1426],{"class":306},[296,3690,3691],{"class":408}," \"Tree halted: \"",[296,3693,1994],{"class":306},[296,3695,511],{"class":313},[296,3697,514],{"class":302},[296,3699,2676],{"class":313},[296,3701,3702],{"class":302},"(tree.",[296,3704,3705],{"class":313},"rootNode",[296,3707,3708],{"class":302},"()->",[296,3710,3711],{"class":313},"status",[296,3713,3714],{"class":302},"()) ",[296,3716,1426],{"class":306},[296,3718,1462],{"class":408},[296,3720,1465],{"class":495},[296,3722,1468],{"class":408},[296,3724,1471],{"class":302},[296,3726,3727,3730,3733],{"class":298,"line":665},[296,3728,3729],{"class":306},"                return",[296,3731,3732],{"class":495}," 3",[296,3734,1471],{"class":302},[296,3736,3737],{"class":298,"line":671},[296,3738,2728],{"class":302},[92,3740,3742],{"className":290,"code":3741,"language":292,"meta":98,"style":98},"#include \"behaviortree_cpp_v3\u002Fbt_factory.h\"\n\n#include \u003Cchrono>\n#include \u003Ciostream>\n#include \u003Cstdexcept>\n#include \u003Cstring>\n\nclass NavigationAllowed : public BT::ConditionNode\n{\npublic:\n    NavigationAllowed(const std::string& name, const BT::NodeConfiguration& config)\n        : BT::ConditionNode(name, config)\n    {}\n\n    static BT::PortsList providedPorts()\n    {\n        return {BT::InputPort\u003Cbool>(\"allowed\")};\n    }\n\n    BT::NodeStatus tick() override\n    {\n        auto allowed = getInput\u003Cbool>(\"allowed\");\n        if (!allowed)\n        {\n            throw BT::RuntimeError(\"Cannot read input [allowed]: \", allowed.error());\n        }\n        std::cout \u003C\u003C \"[NavigationAllowed] allowed=\"\n                  \u003C\u003C (allowed.value() ? \"true\" : \"false\") \u003C\u003C '\\n';\n        return allowed.value() ? BT::NodeStatus::SUCCESS : BT::NodeStatus::FAILURE;\n    }\n};\n\nclass NavigateToGoal : public BT::StatefulActionNode\n{\npublic:\n    NavigateToGoal(const std::string& name, const BT::NodeConfiguration& config)\n        : BT::StatefulActionNode(name, config)\n    {}\n\n    static BT::PortsList providedPorts()\n    {\n        return {BT::InputPort\u003Cstd::string>(\"goal\"),\n                BT::InputPort\u003Cint>(\"ticks\", 3, \"完成导航所需的 onRunning 调用次数\")};\n    }\n\n    BT::NodeStatus onStart() override\n    {\n        auto goal = getInput\u003Cstd::string>(\"goal\");\n        auto ticks = getInput\u003Cint>(\"ticks\");\n        if (!goal)\n        {\n            throw BT::RuntimeError(\"Cannot read input [goal]: \", goal.error());\n        }\n        if (!ticks)\n        {\n            throw BT::RuntimeError(\"Cannot read input [ticks]: \", ticks.error());\n        }\n        if (goal.value().empty() || ticks.value() \u003C 1)\n        {\n            throw std::runtime_error(\"goal must not be empty and ticks must be positive\");\n        }\n\n        goal_ = goal.value();\n        required_ticks_ = ticks.value();\n        completed_ticks_ = 0;\n        \u002F\u002F 真实导航通常在这里发送一次请求，本例只保存模拟任务状态。\n        std::cout \u003C\u003C \"[NavigateToGoal] start goal=\" \u003C\u003C goal_ \u003C\u003C '\\n';\n        return BT::NodeStatus::RUNNING;\n    }\n\n    BT::NodeStatus onRunning() override\n    {\n        \u002F\u002F 每次只检查一步，立即把执行权交回行为树。\n        ++completed_ticks_;\n        std::cout \u003C\u003C \"[NavigateToGoal] progress=\" \u003C\u003C completed_ticks_\n                  \u003C\u003C '\u002F' \u003C\u003C required_ticks_ \u003C\u003C '\\n';\n        if (completed_ticks_ >= required_ticks_)\n        {\n            std::cout \u003C\u003C \"[NavigateToGoal] arrived goal=\" \u003C\u003C goal_ \u003C\u003C '\\n';\n            return BT::NodeStatus::SUCCESS;\n        }\n        return BT::NodeStatus::RUNNING;\n    }\n\n    void onHalted() override\n    {\n        \u002F\u002F 真实导航在这里取消请求、停止当前任务并清理资源。\n        std::cout \u003C\u003C \"[NavigateToGoal] halted goal=\" \u003C\u003C goal_\n                  \u003C\u003C \", progress=\" \u003C\u003C completed_ticks_ \u003C\u003C '\\n';\n        completed_ticks_ = 0;\n    }\n\nprivate:\n    std::string goal_;\n    int required_ticks_ = 0;\n    int completed_ticks_ = 0;\n};\n\nint main()\n{\n    \u002F\u002F 先用 false 跑通；改为 true 后，在第二次根 tick 后禁止继续导航。\n    const bool cancel_after_two_ticks = true;\n\n    try\n    {\n        BT::BehaviorTreeFactory factory;\n        factory.registerNodeType\u003CNavigationAllowed>(\"NavigationAllowed\");\n        factory.registerNodeType\u003CNavigateToGoal>(\"NavigateToGoal\");\n\n        auto blackboard = BT::Blackboard::create();\n        blackboard->set(\"navigation_allowed\", true);\n        auto tree = factory.createTreeFromFile(BT_XML_PATH, blackboard);\n\n        BT::NodeStatus result = BT::NodeStatus::RUNNING;\n        int tick_count = 0;\n        while (result == BT::NodeStatus::RUNNING)\n        {\n            std::cout \u003C\u003C \"--- tick \" \u003C\u003C ++tick_count \u003C\u003C '\\n';\n            result = tree.tickRoot();\n            std::cout \u003C\u003C \"Root returned: \" \u003C\u003C BT::toStr(result) \u003C\u003C '\\n';\n            if (result != BT::NodeStatus::RUNNING)\n            {\n                break;\n            }\n\n            if (cancel_after_two_ticks && tick_count == 2)\n            {\n                \u002F\u002F blackboard->set(\"navigation_allowed\", false);\n                \u002F\u002F std::cout \u003C\u003C \"[main] navigation is no longer allowed\\n\";\n                std::cout \u003C\u003C \"[main] stop requested\\n\";\n                tree.haltTree();\n                std::cout \u003C\u003C \"Tree halted: \" \u003C\u003C BT::toStr(tree.rootNode()->status()) \u003C\u003C '\\n';\n                return 3;\n            }\n            \u002F\u002F 等待放在主循环中，节点回调本身不长时间阻塞。\n            tree.sleep(std::chrono::milliseconds(100));\n        }\n\n        std::cout \u003C\u003C \"Tree result: \" \u003C\u003C BT::toStr(result) \u003C\u003C '\\n';\n        return result == BT::NodeStatus::SUCCESS ? 0 : 1;\n    }\n    catch (const std::exception& error)\n    {\n        std::cerr \u003C\u003C \"Error: \" \u003C\u003C error.what() \u003C\u003C '\\n';\n        return 2;\n    }\n}\n",[64,3743,3744,3750,3754,3760,3766,3772,3778,3782,3798,3802,3806,3840,3848,3852,3856,3870,3874,3896,3900,3904,3918,3922,3942,3952,3956,3976,3980,3990,4020,4050,4054,4058,4062,4078,4082,4086,4120,4128,4132,4136,4150,4154,4180,4206,4210,4214,4228,4232,4256,4276,4286,4290,4310,4314,4324,4328,4348,4352,4380,4384,4400,4404,4408,4420,4432,4442,4446,4470,4482,4486,4490,4504,4508,4513,4519,4533,4553,4563,4567,4591,4603,4607,4619,4623,4627,4637,4641,4645,4659,4679,4689,4693,4697,4701,4708,4720,4732,4736,4740,4748,4752,4757,4771,4775,4779,4783,4789,4805,4821,4825,4845,4861,4875,4879,4895,4907,4923,4927,4953,4965,4995,5011,5015,5021,5025,5029,5045,5049,5054,5059,5075,5083,5121,5129,5133,5137,5161,5165,5169,5199,5225,5229,5245,5249,5277,5285,5289],{"__ignoreMap":98},[296,3745,3746,3748],{"class":298,"line":299},[296,3747,1102],{"class":306},[296,3749,1105],{"class":408},[296,3751,3752],{"class":298,"line":469},[296,3753,625],{"emptyLinePlaceholder":624},[296,3755,3756,3758],{"class":298,"line":487},[296,3757,1102],{"class":306},[296,3759,1116],{"class":408},[296,3761,3762,3764],{"class":298,"line":505},[296,3763,1102],{"class":306},[296,3765,1123],{"class":408},[296,3767,3768,3770],{"class":298,"line":647},[296,3769,1102],{"class":306},[296,3771,1130],{"class":408},[296,3773,3774,3776],{"class":298,"line":665},[296,3775,1102],{"class":306},[296,3777,1137],{"class":408},[296,3779,3780],{"class":298,"line":671},[296,3781,625],{"emptyLinePlaceholder":624},[296,3783,3784,3786,3788,3790,3792,3794,3796],{"class":298,"line":1144},[296,3785,1147],{"class":306},[296,3787,1150],{"class":313},[296,3789,1153],{"class":302},[296,3791,1156],{"class":306},[296,3793,511],{"class":313},[296,3795,514],{"class":302},[296,3797,1163],{"class":313},[296,3799,3800],{"class":298,"line":1166},[296,3801,644],{"class":302},[296,3803,3804],{"class":298,"line":1171},[296,3805,1174],{"class":306},[296,3807,3808,3810,3812,3814,3816,3818,3820,3822,3824,3826,3828,3830,3832,3834,3836,3838],{"class":298,"line":1177},[296,3809,1180],{"class":313},[296,3811,1183],{"class":302},[296,3813,1186],{"class":306},[296,3815,1189],{"class":313},[296,3817,514],{"class":302},[296,3819,1194],{"class":313},[296,3821,1197],{"class":306},[296,3823,1201],{"class":1200},[296,3825,1204],{"class":302},[296,3827,1186],{"class":306},[296,3829,511],{"class":313},[296,3831,514],{"class":302},[296,3833,1213],{"class":313},[296,3835,1197],{"class":306},[296,3837,1218],{"class":1200},[296,3839,1221],{"class":302},[296,3841,3842,3844,3846],{"class":298,"line":1224},[296,3843,1227],{"class":302},[296,3845,1230],{"class":313},[296,3847,1233],{"class":302},[296,3849,3850],{"class":298,"line":1236},[296,3851,1239],{"class":302},[296,3853,3854],{"class":298,"line":1242},[296,3855,625],{"emptyLinePlaceholder":624},[296,3857,3858,3860,3862,3864,3866,3868],{"class":298,"line":1247},[296,3859,1250],{"class":306},[296,3861,511],{"class":313},[296,3863,514],{"class":302},[296,3865,1257],{"class":313},[296,3867,1260],{"class":313},[296,3869,1263],{"class":302},[296,3871,3872],{"class":298,"line":1266},[296,3873,1269],{"class":302},[296,3875,3876,3878,3880,3882,3884,3886,3888,3890,3892,3894],{"class":298,"line":1272},[296,3877,1275],{"class":306},[296,3879,1278],{"class":302},[296,3881,1281],{"class":313},[296,3883,514],{"class":302},[296,3885,1286],{"class":313},[296,3887,397],{"class":302},[296,3889,1291],{"class":306},[296,3891,1294],{"class":302},[296,3893,1297],{"class":408},[296,3895,1300],{"class":302},[296,3897,3898],{"class":298,"line":1303},[296,3899,1306],{"class":302},[296,3901,3902],{"class":298,"line":1309},[296,3903,625],{"emptyLinePlaceholder":624},[296,3905,3906,3908,3910,3912,3914,3916],{"class":298,"line":1314},[296,3907,1317],{"class":313},[296,3909,514],{"class":302},[296,3911,517],{"class":313},[296,3913,1324],{"class":313},[296,3915,1327],{"class":302},[296,3917,1330],{"class":306},[296,3919,3920],{"class":298,"line":1333},[296,3921,1269],{"class":302},[296,3923,3924,3926,3928,3930,3932,3934,3936,3938,3940],{"class":298,"line":1338},[296,3925,1341],{"class":306},[296,3927,1344],{"class":302},[296,3929,307],{"class":306},[296,3931,1349],{"class":313},[296,3933,397],{"class":302},[296,3935,1291],{"class":306},[296,3937,1294],{"class":302},[296,3939,1297],{"class":408},[296,3941,1360],{"class":302},[296,3943,3944,3946,3948,3950],{"class":298,"line":1363},[296,3945,1366],{"class":306},[296,3947,1369],{"class":302},[296,3949,1372],{"class":306},[296,3951,1375],{"class":302},[296,3953,3954],{"class":298,"line":1378},[296,3955,1381],{"class":302},[296,3957,3958,3960,3962,3964,3966,3968,3970,3972,3974],{"class":298,"line":1384},[296,3959,1387],{"class":306},[296,3961,511],{"class":313},[296,3963,514],{"class":302},[296,3965,1394],{"class":313},[296,3967,1183],{"class":302},[296,3969,1399],{"class":408},[296,3971,1402],{"class":302},[296,3973,1405],{"class":313},[296,3975,1408],{"class":302},[296,3977,3978],{"class":298,"line":1411},[296,3979,1414],{"class":302},[296,3981,3982,3984,3986,3988],{"class":298,"line":1417},[296,3983,1420],{"class":313},[296,3985,1423],{"class":302},[296,3987,1426],{"class":306},[296,3989,1429],{"class":408},[296,3991,3992,3994,3996,3998,4000,4002,4004,4006,4008,4010,4012,4014,4016,4018],{"class":298,"line":1432},[296,3993,1435],{"class":306},[296,3995,1438],{"class":302},[296,3997,459],{"class":313},[296,3999,1327],{"class":302},[296,4001,1445],{"class":306},[296,4003,1448],{"class":408},[296,4005,1451],{"class":306},[296,4007,1454],{"class":408},[296,4009,1457],{"class":302},[296,4011,1426],{"class":306},[296,4013,1462],{"class":408},[296,4015,1465],{"class":495},[296,4017,1468],{"class":408},[296,4019,1471],{"class":302},[296,4021,4022,4024,4026,4028,4030,4032,4034,4036,4038,4040,4042,4044,4046,4048],{"class":298,"line":1474},[296,4023,1275],{"class":306},[296,4025,1479],{"class":302},[296,4027,459],{"class":313},[296,4029,1327],{"class":302},[296,4031,1445],{"class":306},[296,4033,511],{"class":313},[296,4035,514],{"class":302},[296,4037,517],{"class":313},[296,4039,1494],{"class":302},[296,4041,1497],{"class":306},[296,4043,511],{"class":313},[296,4045,514],{"class":302},[296,4047,517],{"class":313},[296,4049,1506],{"class":302},[296,4051,4052],{"class":298,"line":1509},[296,4053,1306],{"class":302},[296,4055,4056],{"class":298,"line":1514},[296,4057,1517],{"class":302},[296,4059,4060],{"class":298,"line":1520},[296,4061,625],{"emptyLinePlaceholder":624},[296,4063,4064,4066,4068,4070,4072,4074,4076],{"class":298,"line":1525},[296,4065,1147],{"class":306},[296,4067,1530],{"class":313},[296,4069,1153],{"class":302},[296,4071,1156],{"class":306},[296,4073,511],{"class":313},[296,4075,514],{"class":302},[296,4077,1541],{"class":313},[296,4079,4080],{"class":298,"line":1544},[296,4081,644],{"class":302},[296,4083,4084],{"class":298,"line":1549},[296,4085,1174],{"class":306},[296,4087,4088,4090,4092,4094,4096,4098,4100,4102,4104,4106,4108,4110,4112,4114,4116,4118],{"class":298,"line":1554},[296,4089,1557],{"class":313},[296,4091,1183],{"class":302},[296,4093,1186],{"class":306},[296,4095,1189],{"class":313},[296,4097,514],{"class":302},[296,4099,1194],{"class":313},[296,4101,1197],{"class":306},[296,4103,1201],{"class":1200},[296,4105,1204],{"class":302},[296,4107,1186],{"class":306},[296,4109,511],{"class":313},[296,4111,514],{"class":302},[296,4113,1213],{"class":313},[296,4115,1197],{"class":306},[296,4117,1218],{"class":1200},[296,4119,1221],{"class":302},[296,4121,4122,4124,4126],{"class":298,"line":1590},[296,4123,1227],{"class":302},[296,4125,119],{"class":313},[296,4127,1233],{"class":302},[296,4129,4130],{"class":298,"line":1599},[296,4131,1239],{"class":302},[296,4133,4134],{"class":298,"line":1604},[296,4135,625],{"emptyLinePlaceholder":624},[296,4137,4138,4140,4142,4144,4146,4148],{"class":298,"line":1609},[296,4139,1250],{"class":306},[296,4141,511],{"class":313},[296,4143,514],{"class":302},[296,4145,1257],{"class":313},[296,4147,1260],{"class":313},[296,4149,1263],{"class":302},[296,4151,4152],{"class":298,"line":1624},[296,4153,1269],{"class":302},[296,4155,4156,4158,4160,4162,4164,4166,4168,4170,4172,4174,4176,4178],{"class":298,"line":1629},[296,4157,1275],{"class":306},[296,4159,1278],{"class":302},[296,4161,1281],{"class":313},[296,4163,514],{"class":302},[296,4165,1286],{"class":313},[296,4167,397],{"class":302},[296,4169,1644],{"class":313},[296,4171,514],{"class":302},[296,4173,1194],{"class":313},[296,4175,1294],{"class":302},[296,4177,1653],{"class":408},[296,4179,1656],{"class":302},[296,4181,4182,4184,4186,4188,4190,4192,4194,4196,4198,4200,4202,4204],{"class":298,"line":1659},[296,4183,1662],{"class":313},[296,4185,514],{"class":302},[296,4187,1286],{"class":313},[296,4189,397],{"class":302},[296,4191,1671],{"class":306},[296,4193,1294],{"class":302},[296,4195,1676],{"class":408},[296,4197,1204],{"class":302},[296,4199,566],{"class":495},[296,4201,1204],{"class":302},[296,4203,1685],{"class":408},[296,4205,1300],{"class":302},[296,4207,4208],{"class":298,"line":1690},[296,4209,1306],{"class":302},[296,4211,4212],{"class":298,"line":1695},[296,4213,625],{"emptyLinePlaceholder":624},[296,4215,4216,4218,4220,4222,4224,4226],{"class":298,"line":1700},[296,4217,1317],{"class":313},[296,4219,514],{"class":302},[296,4221,517],{"class":313},[296,4223,1709],{"class":313},[296,4225,1327],{"class":302},[296,4227,1330],{"class":306},[296,4229,4230],{"class":298,"line":1716},[296,4231,1269],{"class":302},[296,4233,4234,4236,4238,4240,4242,4244,4246,4248,4250,4252,4254],{"class":298,"line":1721},[296,4235,1341],{"class":306},[296,4237,1726],{"class":302},[296,4239,307],{"class":306},[296,4241,1349],{"class":313},[296,4243,397],{"class":302},[296,4245,1644],{"class":313},[296,4247,514],{"class":302},[296,4249,1194],{"class":313},[296,4251,1294],{"class":302},[296,4253,1653],{"class":408},[296,4255,1360],{"class":302},[296,4257,4258,4260,4262,4264,4266,4268,4270,4272,4274],{"class":298,"line":1747},[296,4259,1341],{"class":306},[296,4261,1752],{"class":302},[296,4263,307],{"class":306},[296,4265,1349],{"class":313},[296,4267,397],{"class":302},[296,4269,1671],{"class":306},[296,4271,1294],{"class":302},[296,4273,1676],{"class":408},[296,4275,1360],{"class":302},[296,4277,4278,4280,4282,4284],{"class":298,"line":1769},[296,4279,1366],{"class":306},[296,4281,1369],{"class":302},[296,4283,1372],{"class":306},[296,4285,1778],{"class":302},[296,4287,4288],{"class":298,"line":1781},[296,4289,1381],{"class":302},[296,4291,4292,4294,4296,4298,4300,4302,4304,4306,4308],{"class":298,"line":1786},[296,4293,1387],{"class":306},[296,4295,511],{"class":313},[296,4297,514],{"class":302},[296,4299,1394],{"class":313},[296,4301,1183],{"class":302},[296,4303,1799],{"class":408},[296,4305,1802],{"class":302},[296,4307,1405],{"class":313},[296,4309,1408],{"class":302},[296,4311,4312],{"class":298,"line":1809},[296,4313,1414],{"class":302},[296,4315,4316,4318,4320,4322],{"class":298,"line":1814},[296,4317,1366],{"class":306},[296,4319,1369],{"class":302},[296,4321,1372],{"class":306},[296,4323,1823],{"class":302},[296,4325,4326],{"class":298,"line":1826},[296,4327,1381],{"class":302},[296,4329,4330,4332,4334,4336,4338,4340,4342,4344,4346],{"class":298,"line":1831},[296,4331,1387],{"class":306},[296,4333,511],{"class":313},[296,4335,514],{"class":302},[296,4337,1394],{"class":313},[296,4339,1183],{"class":302},[296,4341,1844],{"class":408},[296,4343,1847],{"class":302},[296,4345,1405],{"class":313},[296,4347,1408],{"class":302},[296,4349,4350],{"class":298,"line":1854},[296,4351,1414],{"class":302},[296,4353,4354,4356,4358,4360,4362,4364,4366,4368,4370,4372,4374,4376,4378],{"class":298,"line":1859},[296,4355,1366],{"class":306},[296,4357,1864],{"class":302},[296,4359,459],{"class":313},[296,4361,1869],{"class":302},[296,4363,1872],{"class":313},[296,4365,1327],{"class":302},[296,4367,1877],{"class":306},[296,4369,477],{"class":302},[296,4371,459],{"class":313},[296,4373,1327],{"class":302},[296,4375,397],{"class":306},[296,4377,1888],{"class":495},[296,4379,1221],{"class":302},[296,4381,4382],{"class":298,"line":1893},[296,4383,1381],{"class":302},[296,4385,4386,4388,4390,4392,4394,4396,4398],{"class":298,"line":1898},[296,4387,1387],{"class":306},[296,4389,1189],{"class":313},[296,4391,514],{"class":302},[296,4393,1907],{"class":313},[296,4395,1183],{"class":302},[296,4397,1912],{"class":408},[296,4399,1360],{"class":302},[296,4401,4402],{"class":298,"line":1917},[296,4403,1414],{"class":302},[296,4405,4406],{"class":298,"line":1922},[296,4407,625],{"emptyLinePlaceholder":624},[296,4409,4410,4412,4414,4416,4418],{"class":298,"line":1927},[296,4411,1930],{"class":302},[296,4413,307],{"class":306},[296,4415,456],{"class":302},[296,4417,459],{"class":313},[296,4419,317],{"class":302},[296,4421,4422,4424,4426,4428,4430],{"class":298,"line":1944},[296,4423,1947],{"class":302},[296,4425,307],{"class":306},[296,4427,477],{"class":302},[296,4429,459],{"class":313},[296,4431,317],{"class":302},[296,4433,4434,4436,4438,4440],{"class":298,"line":1961},[296,4435,1964],{"class":302},[296,4437,307],{"class":306},[296,4439,496],{"class":495},[296,4441,1471],{"class":302},[296,4443,4444],{"class":298,"line":1976},[296,4445,1979],{"class":465},[296,4447,4448,4450,4452,4454,4456,4458,4460,4462,4464,4466,4468],{"class":298,"line":1982},[296,4449,1420],{"class":313},[296,4451,1423],{"class":302},[296,4453,1426],{"class":306},[296,4455,1991],{"class":408},[296,4457,1994],{"class":306},[296,4459,1997],{"class":302},[296,4461,1426],{"class":306},[296,4463,1462],{"class":408},[296,4465,1465],{"class":495},[296,4467,1468],{"class":408},[296,4469,1471],{"class":302},[296,4471,4472,4474,4476,4478,4480],{"class":298,"line":2010},[296,4473,1275],{"class":306},[296,4475,511],{"class":313},[296,4477,514],{"class":302},[296,4479,517],{"class":313},[296,4481,2027],{"class":302},[296,4483,4484],{"class":298,"line":2016},[296,4485,1306],{"class":302},[296,4487,4488],{"class":298,"line":2030},[296,4489,625],{"emptyLinePlaceholder":624},[296,4491,4492,4494,4496,4498,4500,4502],{"class":298,"line":2035},[296,4493,1317],{"class":313},[296,4495,514],{"class":302},[296,4497,517],{"class":313},[296,4499,2049],{"class":313},[296,4501,1327],{"class":302},[296,4503,1330],{"class":306},[296,4505,4506],{"class":298,"line":2040},[296,4507,1269],{"class":302},[296,4509,4510],{"class":298,"line":2056},[296,4511,4512],{"class":465},"        \u002F\u002F 每次只检查一步，立即把执行权交回行为树。\n",[296,4514,4515,4517],{"class":298,"line":2061},[296,4516,2070],{"class":306},[296,4518,2073],{"class":302},[296,4520,4521,4523,4525,4527,4529,4531],{"class":298,"line":2067},[296,4522,1420],{"class":313},[296,4524,1423],{"class":302},[296,4526,1426],{"class":306},[296,4528,2085],{"class":408},[296,4530,1994],{"class":306},[296,4532,2090],{"class":302},[296,4534,4535,4537,4539,4541,4543,4545,4547,4549,4551],{"class":298,"line":2076},[296,4536,1435],{"class":306},[296,4538,2098],{"class":408},[296,4540,1994],{"class":306},[296,4542,2103],{"class":302},[296,4544,1426],{"class":306},[296,4546,1462],{"class":408},[296,4548,1465],{"class":495},[296,4550,1468],{"class":408},[296,4552,1471],{"class":302},[296,4554,4555,4557,4559,4561],{"class":298,"line":2093},[296,4556,1366],{"class":306},[296,4558,633],{"class":302},[296,4560,636],{"class":306},[296,4562,639],{"class":302},[296,4564,4565],{"class":298,"line":2116},[296,4566,1381],{"class":302},[296,4568,4569,4571,4573,4575,4577,4579,4581,4583,4585,4587,4589],{"class":298,"line":2122},[296,4570,2141],{"class":313},[296,4572,1423],{"class":302},[296,4574,1426],{"class":306},[296,4576,2148],{"class":408},[296,4578,1994],{"class":306},[296,4580,1997],{"class":302},[296,4582,1426],{"class":306},[296,4584,1462],{"class":408},[296,4586,1465],{"class":495},[296,4588,1468],{"class":408},[296,4590,1471],{"class":302},[296,4592,4593,4595,4597,4599,4601],{"class":298,"line":2133},[296,4594,2174],{"class":306},[296,4596,511],{"class":313},[296,4598,514],{"class":302},[296,4600,517],{"class":313},[296,4602,2183],{"class":302},[296,4604,4605],{"class":298,"line":2138},[296,4606,1414],{"class":302},[296,4608,4609,4611,4613,4615,4617],{"class":298,"line":2165},[296,4610,1275],{"class":306},[296,4612,511],{"class":313},[296,4614,514],{"class":302},[296,4616,517],{"class":313},[296,4618,2027],{"class":302},[296,4620,4621],{"class":298,"line":2171},[296,4622,1306],{"class":302},[296,4624,4625],{"class":298,"line":2186},[296,4626,625],{"emptyLinePlaceholder":624},[296,4628,4629,4631,4633,4635],{"class":298,"line":2191},[296,4630,2223],{"class":306},[296,4632,2226],{"class":313},[296,4634,1327],{"class":302},[296,4636,1330],{"class":306},[296,4638,4639],{"class":298,"line":2197},[296,4640,1269],{"class":302},[296,4642,4643],{"class":298,"line":2210},[296,4644,2247],{"class":465},[296,4646,4647,4649,4651,4653,4655,4657],{"class":298,"line":2215},[296,4648,1420],{"class":313},[296,4650,1423],{"class":302},[296,4652,1426],{"class":306},[296,4654,2259],{"class":408},[296,4656,1994],{"class":306},[296,4658,2264],{"class":302},[296,4660,4661,4663,4665,4667,4669,4671,4673,4675,4677],{"class":298,"line":2220},[296,4662,1435],{"class":306},[296,4664,2272],{"class":408},[296,4666,1994],{"class":306},[296,4668,2277],{"class":302},[296,4670,1426],{"class":306},[296,4672,1462],{"class":408},[296,4674,1465],{"class":495},[296,4676,1468],{"class":408},[296,4678,1471],{"class":302},[296,4680,4681,4683,4685,4687],{"class":298,"line":2233},[296,4682,1964],{"class":302},[296,4684,307],{"class":306},[296,4686,496],{"class":495},[296,4688,1471],{"class":302},[296,4690,4691],{"class":298,"line":2238},[296,4692,1306],{"class":302},[296,4694,4695],{"class":298,"line":2244},[296,4696,625],{"emptyLinePlaceholder":624},[296,4698,4699],{"class":298,"line":2250},[296,4700,2314],{"class":306},[296,4702,4703,4705],{"class":298,"line":2267},[296,4704,2320],{"class":313},[296,4706,4707],{"class":302},"::string goal_;\n",[296,4709,4710,4712,4714,4716,4718],{"class":298,"line":2290},[296,4711,2332],{"class":306},[296,4713,2103],{"class":302},[296,4715,307],{"class":306},[296,4717,496],{"class":495},[296,4719,1471],{"class":302},[296,4721,4722,4724,4726,4728,4730],{"class":298,"line":2301},[296,4723,2332],{"class":306},[296,4725,2277],{"class":302},[296,4727,307],{"class":306},[296,4729,496],{"class":495},[296,4731,1471],{"class":302},[296,4733,4734],{"class":298,"line":2306},[296,4735,1517],{"class":302},[296,4737,4738],{"class":298,"line":2311},[296,4739,625],{"emptyLinePlaceholder":624},[296,4741,4742,4744,4746],{"class":298,"line":2317},[296,4743,1671],{"class":306},[296,4745,2377],{"class":313},[296,4747,1263],{"class":302},[296,4749,4750],{"class":298,"line":2329},[296,4751,644],{"class":302},[296,4753,4754],{"class":298,"line":2346},[296,4755,4756],{"class":465},"    \u002F\u002F 先用 false 跑通；改为 true 后，在第二次根 tick 后禁止继续导航。\n",[296,4758,4759,4761,4763,4765,4767,4769],{"class":298,"line":2362},[296,4760,2396],{"class":306},[296,4762,2399],{"class":306},[296,4764,2402],{"class":302},[296,4766,307],{"class":306},[296,4768,3373],{"class":495},[296,4770,1471],{"class":302},[296,4772,4773],{"class":298,"line":2367},[296,4774,625],{"emptyLinePlaceholder":624},[296,4776,4777],{"class":298,"line":2372},[296,4778,2420],{"class":306},[296,4780,4781],{"class":298,"line":2382},[296,4782,1269],{"class":302},[296,4784,4785,4787],{"class":298,"line":2387},[296,4786,2431],{"class":313},[296,4788,2434],{"class":302},[296,4790,4791,4793,4795,4797,4799,4801,4803],{"class":298,"line":2393},[296,4792,2440],{"class":302},[296,4794,397],{"class":306},[296,4796,758],{"class":302},[296,4798,2447],{"class":306},[296,4800,1183],{"class":302},[296,4802,2452],{"class":408},[296,4804,1360],{"class":302},[296,4806,4807,4809,4811,4813,4815,4817,4819],{"class":298,"line":2412},[296,4808,2440],{"class":302},[296,4810,397],{"class":306},[296,4812,337],{"class":302},[296,4814,2447],{"class":306},[296,4816,1183],{"class":302},[296,4818,2470],{"class":408},[296,4820,1360],{"class":302},[296,4822,4823],{"class":298,"line":2417},[296,4824,625],{"emptyLinePlaceholder":624},[296,4826,4827,4829,4831,4833,4835,4837,4839,4841,4843],{"class":298,"line":2423},[296,4828,1341],{"class":306},[296,4830,2485],{"class":302},[296,4832,307],{"class":306},[296,4834,511],{"class":313},[296,4836,514],{"class":302},[296,4838,2494],{"class":313},[296,4840,514],{"class":302},[296,4842,2499],{"class":313},[296,4844,317],{"class":302},[296,4846,4847,4849,4851,4853,4855,4857,4859],{"class":298,"line":2428},[296,4848,2507],{"class":302},[296,4850,2510],{"class":313},[296,4852,1183],{"class":302},[296,4854,2515],{"class":408},[296,4856,1204],{"class":302},[296,4858,2520],{"class":495},[296,4860,1360],{"class":302},[296,4862,4863,4865,4867,4869,4871,4873],{"class":298,"line":2437},[296,4864,1341],{"class":306},[296,4866,2530],{"class":302},[296,4868,307],{"class":306},[296,4870,2535],{"class":302},[296,4872,2538],{"class":313},[296,4874,2541],{"class":302},[296,4876,4877],{"class":298,"line":2457},[296,4878,625],{"emptyLinePlaceholder":624},[296,4880,4881,4883,4885,4887,4889,4891,4893],{"class":298,"line":2475},[296,4882,2431],{"class":313},[296,4884,2554],{"class":302},[296,4886,307],{"class":306},[296,4888,511],{"class":313},[296,4890,514],{"class":302},[296,4892,517],{"class":313},[296,4894,2027],{"class":302},[296,4896,4897,4899,4901,4903,4905],{"class":298,"line":2480},[296,4898,2570],{"class":306},[296,4900,2573],{"class":302},[296,4902,307],{"class":306},[296,4904,496],{"class":495},[296,4906,1471],{"class":302},[296,4908,4909,4911,4913,4915,4917,4919,4921],{"class":298,"line":2504},[296,4910,2585],{"class":306},[296,4912,2588],{"class":302},[296,4914,2591],{"class":306},[296,4916,511],{"class":313},[296,4918,514],{"class":302},[296,4920,517],{"class":313},[296,4922,2600],{"class":302},[296,4924,4925],{"class":298,"line":2525},[296,4926,1381],{"class":302},[296,4928,4929,4931,4933,4935,4937,4939,4941,4943,4945,4947,4949,4951],{"class":298,"line":2544},[296,4930,2141],{"class":313},[296,4932,1423],{"class":302},[296,4934,1426],{"class":306},[296,4936,2617],{"class":408},[296,4938,1994],{"class":306},[296,4940,2622],{"class":306},[296,4942,2625],{"class":302},[296,4944,1426],{"class":306},[296,4946,1462],{"class":408},[296,4948,1465],{"class":495},[296,4950,1468],{"class":408},[296,4952,1471],{"class":302},[296,4954,4955,4957,4959,4961,4963],{"class":298,"line":2549},[296,4956,2647],{"class":302},[296,4958,307],{"class":306},[296,4960,310],{"class":302},[296,4962,314],{"class":313},[296,4964,317],{"class":302},[296,4966,4967,4969,4971,4973,4975,4977,4979,4981,4983,4985,4987,4989,4991,4993],{"class":298,"line":2567},[296,4968,2141],{"class":313},[296,4970,1423],{"class":302},[296,4972,1426],{"class":306},[296,4974,2667],{"class":408},[296,4976,1994],{"class":306},[296,4978,511],{"class":313},[296,4980,514],{"class":302},[296,4982,2676],{"class":313},[296,4984,2679],{"class":302},[296,4986,1426],{"class":306},[296,4988,1462],{"class":408},[296,4990,1465],{"class":495},[296,4992,1468],{"class":408},[296,4994,1471],{"class":302},[296,4996,4997,4999,5001,5003,5005,5007,5009],{"class":298,"line":2582},[296,4998,2695],{"class":306},[296,5000,2588],{"class":302},[296,5002,2700],{"class":306},[296,5004,511],{"class":313},[296,5006,514],{"class":302},[296,5008,517],{"class":313},[296,5010,2600],{"class":302},[296,5012,5013],{"class":298,"line":2603},[296,5014,2714],{"class":302},[296,5016,5017,5019],{"class":298,"line":2608},[296,5018,2720],{"class":306},[296,5020,1471],{"class":302},[296,5022,5023],{"class":298,"line":2638},[296,5024,2728],{"class":302},[296,5026,5027],{"class":298,"line":2644},[296,5028,625],{"emptyLinePlaceholder":624},[296,5030,5031,5033,5035,5037,5039,5041,5043],{"class":298,"line":2658},[296,5032,2695],{"class":306},[296,5034,2741],{"class":302},[296,5036,2744],{"class":306},[296,5038,2573],{"class":302},[296,5040,2591],{"class":306},[296,5042,2751],{"class":495},[296,5044,1221],{"class":302},[296,5046,5047],{"class":298,"line":2692},[296,5048,2714],{"class":302},[296,5050,5051],{"class":298,"line":2711},[296,5052,5053],{"class":465},"                \u002F\u002F blackboard->set(\"navigation_allowed\", false);\n",[296,5055,5056],{"class":298,"line":2717},[296,5057,5058],{"class":465},"                \u002F\u002F std::cout \u003C\u003C \"[main] navigation is no longer allowed\\n\";\n",[296,5060,5061,5063,5065,5067,5069,5071,5073],{"class":298,"line":2725},[296,5062,2783],{"class":313},[296,5064,1423],{"class":302},[296,5066,1426],{"class":306},[296,5068,3664],{"class":408},[296,5070,1465],{"class":495},[296,5072,2795],{"class":408},[296,5074,1471],{"class":302},[296,5076,5077,5079,5081],{"class":298,"line":2731},[296,5078,3675],{"class":302},[296,5080,3678],{"class":313},[296,5082,317],{"class":302},[296,5084,5085,5087,5089,5091,5093,5095,5097,5099,5101,5103,5105,5107,5109,5111,5113,5115,5117,5119],{"class":298,"line":2736},[296,5086,2783],{"class":313},[296,5088,1423],{"class":302},[296,5090,1426],{"class":306},[296,5092,3691],{"class":408},[296,5094,1994],{"class":306},[296,5096,511],{"class":313},[296,5098,514],{"class":302},[296,5100,2676],{"class":313},[296,5102,3702],{"class":302},[296,5104,3705],{"class":313},[296,5106,3708],{"class":302},[296,5108,3711],{"class":313},[296,5110,3714],{"class":302},[296,5112,1426],{"class":306},[296,5114,1462],{"class":408},[296,5116,1465],{"class":495},[296,5118,1468],{"class":408},[296,5120,1471],{"class":302},[296,5122,5123,5125,5127],{"class":298,"line":2756},[296,5124,3729],{"class":306},[296,5126,3732],{"class":495},[296,5128,1471],{"class":302},[296,5130,5131],{"class":298,"line":2761},[296,5132,2728],{"class":302},[296,5134,5135],{"class":298,"line":2780},[296,5136,2808],{"class":465},[296,5138,5139,5141,5143,5145,5147,5149,5151,5153,5155,5157,5159],{"class":298,"line":2800},[296,5140,2814],{"class":302},[296,5142,2817],{"class":313},[296,5144,1183],{"class":302},[296,5146,1644],{"class":313},[296,5148,514],{"class":302},[296,5150,2826],{"class":313},[296,5152,514],{"class":302},[296,5154,2831],{"class":313},[296,5156,1183],{"class":302},[296,5158,2836],{"class":495},[296,5160,2839],{"class":302},[296,5162,5163],{"class":298,"line":2805},[296,5164,1414],{"class":302},[296,5166,5167],{"class":298,"line":2811},[296,5168,625],{"emptyLinePlaceholder":624},[296,5170,5171,5173,5175,5177,5179,5181,5183,5185,5187,5189,5191,5193,5195,5197],{"class":298,"line":2842},[296,5172,1420],{"class":313},[296,5174,1423],{"class":302},[296,5176,1426],{"class":306},[296,5178,2861],{"class":408},[296,5180,1994],{"class":306},[296,5182,511],{"class":313},[296,5184,514],{"class":302},[296,5186,2676],{"class":313},[296,5188,2679],{"class":302},[296,5190,1426],{"class":306},[296,5192,1462],{"class":408},[296,5194,1465],{"class":495},[296,5196,1468],{"class":408},[296,5198,1471],{"class":302},[296,5200,5201,5203,5205,5207,5209,5211,5213,5215,5217,5219,5221,5223],{"class":298,"line":2847},[296,5202,1275],{"class":306},[296,5204,2889],{"class":302},[296,5206,2591],{"class":306},[296,5208,511],{"class":313},[296,5210,514],{"class":302},[296,5212,517],{"class":313},[296,5214,1494],{"class":302},[296,5216,1445],{"class":306},[296,5218,496],{"class":495},[296,5220,1451],{"class":306},[296,5222,1888],{"class":495},[296,5224,1471],{"class":302},[296,5226,5227],{"class":298,"line":2852},[296,5228,1306],{"class":302},[296,5230,5231,5233,5235,5237,5239,5241,5243],{"class":298,"line":2884},[296,5232,2920],{"class":306},[296,5234,1369],{"class":302},[296,5236,1186],{"class":306},[296,5238,1189],{"class":313},[296,5240,2929],{"class":302},[296,5242,1197],{"class":306},[296,5244,2934],{"class":302},[296,5246,5247],{"class":298,"line":2912},[296,5248,1269],{"class":302},[296,5250,5251,5253,5255,5257,5259,5261,5263,5265,5267,5269,5271,5273,5275],{"class":298,"line":2917},[296,5252,1420],{"class":313},[296,5254,2947],{"class":302},[296,5256,1426],{"class":306},[296,5258,2952],{"class":408},[296,5260,1994],{"class":306},[296,5262,2957],{"class":302},[296,5264,2960],{"class":313},[296,5266,1327],{"class":302},[296,5268,1426],{"class":306},[296,5270,1462],{"class":408},[296,5272,1465],{"class":495},[296,5274,1468],{"class":408},[296,5276,1471],{"class":302},[296,5278,5279,5281,5283],{"class":298,"line":2937},[296,5280,1275],{"class":306},[296,5282,2751],{"class":495},[296,5284,1471],{"class":302},[296,5286,5287],{"class":298,"line":2942},[296,5288,1306],{"class":302},[296,5290,5291],{"class":298,"line":2975},[296,5292,668],{"class":302},[20,5294,3378,5295,5297],{},[53,5296,3381],{},"。程序会在第二次根 tick 后直接停止树，输出末尾为：",[92,5299,5302],{"className":5300,"code":5301,"language":97,"meta":98},[95],"[main] stop requested\n[NavigateToGoal] halted goal=loading_area, progress=1\nTree halted: IDLE\n",[64,5303,5301],{"__ignoreMap":98},[20,5305,5306],{},[1077,5307],{"alt":98,"src":5308},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792414927854-607a508e.webp",[20,5310,5311,5312,5314,5315,5317,5318,5320,5321,5323,5324,48],{},"这次没有再执行第三次根 tick，也没有让条件返回失败。主程序主动停止任务，并打印停止后的根状态 ",[64,5313,158],{},"。示例用退出码 ",[64,5316,566],{}," 表示主动停止；正常成功为 ",[64,5319,581],{},"，任务失败为 ",[64,5322,699],{},"，异常报告为 ",[64,5325,712],{},[20,5327,5328,5331,5332,5334,5335,5337],{},[64,5329,5330],{},"haltTree()"," 会重置节点状态，但不会自动清空 Blackboard，也不会替你重置所有 C++ 成员。\n本例在 ",[64,5333,89],{}," 初始化本次进度，在 ",[64,5336,203],{}," 清理中断时的进度，分别明确处理下一次任务的起点。",[281,5339,5341],{"id":5340},"停止树与查看状态的-api","停止树与查看状态的 API",[20,5343,5344],{},"上面的停止代码使用了三个无参数成员函数：",[122,5346,5347,5360],{},[125,5348,5349],{},[128,5350,5351,5354,5357],{},[131,5352,5353],{},"接口",[131,5355,5356],{},"所属对象",[131,5358,5359],{},"返回值与作用",[144,5361,5362,5386,5407],{},[128,5363,5364,5368,5372],{},[149,5365,5366],{},[64,5367,5330],{},[149,5369,5370],{},[64,5371,3027],{},[149,5373,5374,5375,5377,5378,5380,5381,5383,5384],{},"返回 ",[64,5376,217],{},"，停止当前树并将节点状态重置为 ",[64,5379,158],{},"；运行中的 ",[64,5382,119],{}," 会进入 ",[64,5385,203],{},[128,5387,5388,5393,5397],{},[149,5389,5390],{},[64,5391,5392],{},"rootNode()",[149,5394,5395],{},[64,5396,3027],{},[149,5398,5374,5399,5402,5403,5406],{},[64,5400,5401],{},"BT::TreeNode*","，指向根节点；空树会返回 ",[64,5404,5405],{},"nullptr","，本例已经成功创建树，因此可以访问根节点",[128,5408,5409,5414,5419],{},[149,5410,5411],{},[64,5412,5413],{},"status()",[149,5415,5416],{},[64,5417,5418],{},"BT::TreeNode",[149,5420,5374,5421,5423],{},[64,5422,325],{},"，读取节点当前保存的状态，不执行 tick",[20,5425,5426,5429,5430,5433,5434,5436,5437,5439,5440,5442,5443,170,5445,5447,5448,5450,5451,5453],{},[64,5427,5428],{},"tree.rootNode()->status()"," 先取得根节点指针，再读取状态，最后由 ",[64,5431,5432],{},"BT::toStr(...)"," 转成字符串用于打印。这里在 ",[64,5435,5330],{}," 后读取，所以得到 ",[64,5438,158],{},"。注意，3.8.7 的 ",[64,5441,85],{}," 在返回 ",[64,5444,169],{},[64,5446,173],{}," 时也会把根节点保存的状态重置为 ",[64,5449,158],{},"；判断一次 tick 的执行结果，应使用 ",[64,5452,85],{}," 的返回值。",[92,5455,5458],{"className":5456,"code":5457,"language":97,"meta":98},[95],"ReactiveSequence          ← 根节点，rootNode() 指向它\n├── NavigationAllowed     ← 它的第一个子节点\n└── NavigateToGoal        ← 它的第二个子节点\n",[64,5459,5457],{"__ignoreMap":98},[20,5461,5462],{},[1077,5463],{"alt":98,"src":5464},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792415264807-9ca5e775.webp",[102,5466],{},[12,5468,5470],{"id":5469},"在-vscode-中观察三个回调","在 VSCode 中观察三个回调",[281,5472,5473],{"id":5473},"先观察正常完成时怎样从启动进入运行检查",[20,5475,5476,5477,5480,5481,5483,5484,48],{},"恢复完整程序中原来的条件更新代码块，将 ",[64,5478,5479],{},"cancel_after_two_ticks"," 改为 ",[64,5482,2775],{},"，\nXML 使用 ",[64,5485,884],{},[92,5487,5489],{"className":290,"code":5488,"language":292,"meta":98,"style":98},"#include \"behaviortree_cpp_v3\u002Fbt_factory.h\"\n\n#include \u003Cchrono>\n#include \u003Ciostream>\n#include \u003Cstdexcept>\n#include \u003Cstring>\n\nclass NavigationAllowed : public BT::ConditionNode\n{\npublic:\n    NavigationAllowed(const std::string& name, const BT::NodeConfiguration& config)\n        : BT::ConditionNode(name, config)\n    {}\n\n    static BT::PortsList providedPorts()\n    {\n        return {BT::InputPort\u003Cbool>(\"allowed\")};\n    }\n\n    BT::NodeStatus tick() override\n    {\n        auto allowed = getInput\u003Cbool>(\"allowed\");\n        if (!allowed)\n        {\n            throw BT::RuntimeError(\"Cannot read input [allowed]: \", allowed.error());\n        }\n        std::cout \u003C\u003C \"[NavigationAllowed] allowed=\"\n                  \u003C\u003C (allowed.value() ? \"true\" : \"false\") \u003C\u003C '\\n';\n        return allowed.value() ? BT::NodeStatus::SUCCESS : BT::NodeStatus::FAILURE;\n    }\n};\n\nclass NavigateToGoal : public BT::StatefulActionNode\n{\npublic:\n    NavigateToGoal(const std::string& name, const BT::NodeConfiguration& config)\n        : BT::StatefulActionNode(name, config)\n    {}\n\n    static BT::PortsList providedPorts()\n    {\n        return {BT::InputPort\u003Cstd::string>(\"goal\"),\n                BT::InputPort\u003Cint>(\"ticks\", 3, \"完成导航所需的 onRunning 调用次数\")};\n    }\n\n    BT::NodeStatus onStart() override\n    {\n        auto goal = getInput\u003Cstd::string>(\"goal\");\n        auto ticks = getInput\u003Cint>(\"ticks\");\n        if (!goal)\n        {\n            throw BT::RuntimeError(\"Cannot read input [goal]: \", goal.error());\n        }\n        if (!ticks)\n        {\n            throw BT::RuntimeError(\"Cannot read input [ticks]: \", ticks.error());\n        }\n        if (goal.value().empty() || ticks.value() \u003C 1)\n        {\n            throw std::runtime_error(\"goal must not be empty and ticks must be positive\");\n        }\n\n        goal_ = goal.value();\n        required_ticks_ = ticks.value();\n        completed_ticks_ = 0;\n        \u002F\u002F 真实导航通常在这里发送一次请求，本例只保存模拟任务状态。\n        std::cout \u003C\u003C \"[NavigateToGoal] start goal=\" \u003C\u003C goal_ \u003C\u003C '\\n';\n        return BT::NodeStatus::RUNNING;\n    }\n\n    BT::NodeStatus onRunning() override\n    {\n        \u002F\u002F 每次只检查一步，立即把执行权交回行为树。\n        ++completed_ticks_;\n        std::cout \u003C\u003C \"[NavigateToGoal] progress=\" \u003C\u003C completed_ticks_\n                  \u003C\u003C '\u002F' \u003C\u003C required_ticks_ \u003C\u003C '\\n';\n        if (completed_ticks_ >= required_ticks_)\n        {\n            std::cout \u003C\u003C \"[NavigateToGoal] arrived goal=\" \u003C\u003C goal_ \u003C\u003C '\\n';\n            return BT::NodeStatus::SUCCESS;\n        }\n        return BT::NodeStatus::RUNNING;\n    }\n\n    void onHalted() override\n    {\n        \u002F\u002F 真实导航在这里取消请求、停止当前任务并清理资源。\n        std::cout \u003C\u003C \"[NavigateToGoal] halted goal=\" \u003C\u003C goal_\n                  \u003C\u003C \", progress=\" \u003C\u003C completed_ticks_ \u003C\u003C '\\n';\n        completed_ticks_ = 0;\n    }\n\nprivate:\n    std::string goal_;\n    int required_ticks_ = 0;\n    int completed_ticks_ = 0;\n};\n\nint main()\n{\n    \u002F\u002F 先用 false 跑通；改为 true 后，在第二次根 tick 后禁止继续导航。\n    const bool cancel_after_two_ticks = false;\n\n    try\n    {\n        BT::BehaviorTreeFactory factory;\n        factory.registerNodeType\u003CNavigationAllowed>(\"NavigationAllowed\");\n        factory.registerNodeType\u003CNavigateToGoal>(\"NavigateToGoal\");\n\n        auto blackboard = BT::Blackboard::create();\n        blackboard->set(\"navigation_allowed\", true);\n        auto tree = factory.createTreeFromFile(BT_XML_PATH, blackboard);\n\n        BT::NodeStatus result = BT::NodeStatus::RUNNING;\n        int tick_count = 0;\n        while (result == BT::NodeStatus::RUNNING)\n        {\n            std::cout \u003C\u003C \"--- tick \" \u003C\u003C ++tick_count \u003C\u003C '\\n';\n            result = tree.tickRoot();\n            std::cout \u003C\u003C \"Root returned: \" \u003C\u003C BT::toStr(result) \u003C\u003C '\\n';\n            if (result != BT::NodeStatus::RUNNING)\n            {\n                break;\n            }\n\n            if (cancel_after_two_ticks && tick_count == 2)\n            {\n                blackboard->set(\"navigation_allowed\", false);\n                std::cout \u003C\u003C \"[main] navigation is no longer allowed\\n\";\n                return 3;\n            }\n            \u002F\u002F 等待放在主循环中，节点回调本身不长时间阻塞。\n            tree.sleep(std::chrono::milliseconds(100));\n        }\n\n        std::cout \u003C\u003C \"Tree result: \" \u003C\u003C BT::toStr(result) \u003C\u003C '\\n';\n        return result == BT::NodeStatus::SUCCESS ? 0 : 1;\n    }\n    catch (const std::exception& error)\n    {\n        std::cerr \u003C\u003C \"Error: \" \u003C\u003C error.what() \u003C\u003C '\\n';\n        return 2;\n    }\n}\n",[64,5490,5491,5497,5501,5507,5513,5519,5525,5529,5545,5549,5553,5587,5595,5599,5603,5617,5621,5643,5647,5651,5665,5669,5689,5699,5703,5723,5727,5737,5767,5797,5801,5805,5809,5825,5829,5833,5867,5875,5879,5883,5897,5901,5927,5953,5957,5961,5975,5979,6003,6023,6033,6037,6057,6061,6071,6075,6095,6099,6127,6131,6147,6151,6155,6167,6179,6189,6193,6217,6229,6233,6237,6251,6255,6259,6265,6279,6299,6309,6313,6337,6349,6353,6365,6369,6373,6383,6387,6391,6405,6425,6435,6439,6443,6447,6453,6465,6477,6481,6485,6493,6497,6501,6515,6519,6523,6527,6533,6549,6565,6569,6589,6605,6619,6623,6639,6651,6667,6671,6697,6709,6739,6755,6759,6765,6769,6773,6789,6793,6809,6825,6833,6837,6841,6865,6869,6873,6903,6929,6933,6949,6953,6981,6989,6993],{"__ignoreMap":98},[296,5492,5493,5495],{"class":298,"line":299},[296,5494,1102],{"class":306},[296,5496,1105],{"class":408},[296,5498,5499],{"class":298,"line":469},[296,5500,625],{"emptyLinePlaceholder":624},[296,5502,5503,5505],{"class":298,"line":487},[296,5504,1102],{"class":306},[296,5506,1116],{"class":408},[296,5508,5509,5511],{"class":298,"line":505},[296,5510,1102],{"class":306},[296,5512,1123],{"class":408},[296,5514,5515,5517],{"class":298,"line":647},[296,5516,1102],{"class":306},[296,5518,1130],{"class":408},[296,5520,5521,5523],{"class":298,"line":665},[296,5522,1102],{"class":306},[296,5524,1137],{"class":408},[296,5526,5527],{"class":298,"line":671},[296,5528,625],{"emptyLinePlaceholder":624},[296,5530,5531,5533,5535,5537,5539,5541,5543],{"class":298,"line":1144},[296,5532,1147],{"class":306},[296,5534,1150],{"class":313},[296,5536,1153],{"class":302},[296,5538,1156],{"class":306},[296,5540,511],{"class":313},[296,5542,514],{"class":302},[296,5544,1163],{"class":313},[296,5546,5547],{"class":298,"line":1166},[296,5548,644],{"class":302},[296,5550,5551],{"class":298,"line":1171},[296,5552,1174],{"class":306},[296,5554,5555,5557,5559,5561,5563,5565,5567,5569,5571,5573,5575,5577,5579,5581,5583,5585],{"class":298,"line":1177},[296,5556,1180],{"class":313},[296,5558,1183],{"class":302},[296,5560,1186],{"class":306},[296,5562,1189],{"class":313},[296,5564,514],{"class":302},[296,5566,1194],{"class":313},[296,5568,1197],{"class":306},[296,5570,1201],{"class":1200},[296,5572,1204],{"class":302},[296,5574,1186],{"class":306},[296,5576,511],{"class":313},[296,5578,514],{"class":302},[296,5580,1213],{"class":313},[296,5582,1197],{"class":306},[296,5584,1218],{"class":1200},[296,5586,1221],{"class":302},[296,5588,5589,5591,5593],{"class":298,"line":1224},[296,5590,1227],{"class":302},[296,5592,1230],{"class":313},[296,5594,1233],{"class":302},[296,5596,5597],{"class":298,"line":1236},[296,5598,1239],{"class":302},[296,5600,5601],{"class":298,"line":1242},[296,5602,625],{"emptyLinePlaceholder":624},[296,5604,5605,5607,5609,5611,5613,5615],{"class":298,"line":1247},[296,5606,1250],{"class":306},[296,5608,511],{"class":313},[296,5610,514],{"class":302},[296,5612,1257],{"class":313},[296,5614,1260],{"class":313},[296,5616,1263],{"class":302},[296,5618,5619],{"class":298,"line":1266},[296,5620,1269],{"class":302},[296,5622,5623,5625,5627,5629,5631,5633,5635,5637,5639,5641],{"class":298,"line":1272},[296,5624,1275],{"class":306},[296,5626,1278],{"class":302},[296,5628,1281],{"class":313},[296,5630,514],{"class":302},[296,5632,1286],{"class":313},[296,5634,397],{"class":302},[296,5636,1291],{"class":306},[296,5638,1294],{"class":302},[296,5640,1297],{"class":408},[296,5642,1300],{"class":302},[296,5644,5645],{"class":298,"line":1303},[296,5646,1306],{"class":302},[296,5648,5649],{"class":298,"line":1309},[296,5650,625],{"emptyLinePlaceholder":624},[296,5652,5653,5655,5657,5659,5661,5663],{"class":298,"line":1314},[296,5654,1317],{"class":313},[296,5656,514],{"class":302},[296,5658,517],{"class":313},[296,5660,1324],{"class":313},[296,5662,1327],{"class":302},[296,5664,1330],{"class":306},[296,5666,5667],{"class":298,"line":1333},[296,5668,1269],{"class":302},[296,5670,5671,5673,5675,5677,5679,5681,5683,5685,5687],{"class":298,"line":1338},[296,5672,1341],{"class":306},[296,5674,1344],{"class":302},[296,5676,307],{"class":306},[296,5678,1349],{"class":313},[296,5680,397],{"class":302},[296,5682,1291],{"class":306},[296,5684,1294],{"class":302},[296,5686,1297],{"class":408},[296,5688,1360],{"class":302},[296,5690,5691,5693,5695,5697],{"class":298,"line":1363},[296,5692,1366],{"class":306},[296,5694,1369],{"class":302},[296,5696,1372],{"class":306},[296,5698,1375],{"class":302},[296,5700,5701],{"class":298,"line":1378},[296,5702,1381],{"class":302},[296,5704,5705,5707,5709,5711,5713,5715,5717,5719,5721],{"class":298,"line":1384},[296,5706,1387],{"class":306},[296,5708,511],{"class":313},[296,5710,514],{"class":302},[296,5712,1394],{"class":313},[296,5714,1183],{"class":302},[296,5716,1399],{"class":408},[296,5718,1402],{"class":302},[296,5720,1405],{"class":313},[296,5722,1408],{"class":302},[296,5724,5725],{"class":298,"line":1411},[296,5726,1414],{"class":302},[296,5728,5729,5731,5733,5735],{"class":298,"line":1417},[296,5730,1420],{"class":313},[296,5732,1423],{"class":302},[296,5734,1426],{"class":306},[296,5736,1429],{"class":408},[296,5738,5739,5741,5743,5745,5747,5749,5751,5753,5755,5757,5759,5761,5763,5765],{"class":298,"line":1432},[296,5740,1435],{"class":306},[296,5742,1438],{"class":302},[296,5744,459],{"class":313},[296,5746,1327],{"class":302},[296,5748,1445],{"class":306},[296,5750,1448],{"class":408},[296,5752,1451],{"class":306},[296,5754,1454],{"class":408},[296,5756,1457],{"class":302},[296,5758,1426],{"class":306},[296,5760,1462],{"class":408},[296,5762,1465],{"class":495},[296,5764,1468],{"class":408},[296,5766,1471],{"class":302},[296,5768,5769,5771,5773,5775,5777,5779,5781,5783,5785,5787,5789,5791,5793,5795],{"class":298,"line":1474},[296,5770,1275],{"class":306},[296,5772,1479],{"class":302},[296,5774,459],{"class":313},[296,5776,1327],{"class":302},[296,5778,1445],{"class":306},[296,5780,511],{"class":313},[296,5782,514],{"class":302},[296,5784,517],{"class":313},[296,5786,1494],{"class":302},[296,5788,1497],{"class":306},[296,5790,511],{"class":313},[296,5792,514],{"class":302},[296,5794,517],{"class":313},[296,5796,1506],{"class":302},[296,5798,5799],{"class":298,"line":1509},[296,5800,1306],{"class":302},[296,5802,5803],{"class":298,"line":1514},[296,5804,1517],{"class":302},[296,5806,5807],{"class":298,"line":1520},[296,5808,625],{"emptyLinePlaceholder":624},[296,5810,5811,5813,5815,5817,5819,5821,5823],{"class":298,"line":1525},[296,5812,1147],{"class":306},[296,5814,1530],{"class":313},[296,5816,1153],{"class":302},[296,5818,1156],{"class":306},[296,5820,511],{"class":313},[296,5822,514],{"class":302},[296,5824,1541],{"class":313},[296,5826,5827],{"class":298,"line":1544},[296,5828,644],{"class":302},[296,5830,5831],{"class":298,"line":1549},[296,5832,1174],{"class":306},[296,5834,5835,5837,5839,5841,5843,5845,5847,5849,5851,5853,5855,5857,5859,5861,5863,5865],{"class":298,"line":1554},[296,5836,1557],{"class":313},[296,5838,1183],{"class":302},[296,5840,1186],{"class":306},[296,5842,1189],{"class":313},[296,5844,514],{"class":302},[296,5846,1194],{"class":313},[296,5848,1197],{"class":306},[296,5850,1201],{"class":1200},[296,5852,1204],{"class":302},[296,5854,1186],{"class":306},[296,5856,511],{"class":313},[296,5858,514],{"class":302},[296,5860,1213],{"class":313},[296,5862,1197],{"class":306},[296,5864,1218],{"class":1200},[296,5866,1221],{"class":302},[296,5868,5869,5871,5873],{"class":298,"line":1590},[296,5870,1227],{"class":302},[296,5872,119],{"class":313},[296,5874,1233],{"class":302},[296,5876,5877],{"class":298,"line":1599},[296,5878,1239],{"class":302},[296,5880,5881],{"class":298,"line":1604},[296,5882,625],{"emptyLinePlaceholder":624},[296,5884,5885,5887,5889,5891,5893,5895],{"class":298,"line":1609},[296,5886,1250],{"class":306},[296,5888,511],{"class":313},[296,5890,514],{"class":302},[296,5892,1257],{"class":313},[296,5894,1260],{"class":313},[296,5896,1263],{"class":302},[296,5898,5899],{"class":298,"line":1624},[296,5900,1269],{"class":302},[296,5902,5903,5905,5907,5909,5911,5913,5915,5917,5919,5921,5923,5925],{"class":298,"line":1629},[296,5904,1275],{"class":306},[296,5906,1278],{"class":302},[296,5908,1281],{"class":313},[296,5910,514],{"class":302},[296,5912,1286],{"class":313},[296,5914,397],{"class":302},[296,5916,1644],{"class":313},[296,5918,514],{"class":302},[296,5920,1194],{"class":313},[296,5922,1294],{"class":302},[296,5924,1653],{"class":408},[296,5926,1656],{"class":302},[296,5928,5929,5931,5933,5935,5937,5939,5941,5943,5945,5947,5949,5951],{"class":298,"line":1659},[296,5930,1662],{"class":313},[296,5932,514],{"class":302},[296,5934,1286],{"class":313},[296,5936,397],{"class":302},[296,5938,1671],{"class":306},[296,5940,1294],{"class":302},[296,5942,1676],{"class":408},[296,5944,1204],{"class":302},[296,5946,566],{"class":495},[296,5948,1204],{"class":302},[296,5950,1685],{"class":408},[296,5952,1300],{"class":302},[296,5954,5955],{"class":298,"line":1690},[296,5956,1306],{"class":302},[296,5958,5959],{"class":298,"line":1695},[296,5960,625],{"emptyLinePlaceholder":624},[296,5962,5963,5965,5967,5969,5971,5973],{"class":298,"line":1700},[296,5964,1317],{"class":313},[296,5966,514],{"class":302},[296,5968,517],{"class":313},[296,5970,1709],{"class":313},[296,5972,1327],{"class":302},[296,5974,1330],{"class":306},[296,5976,5977],{"class":298,"line":1716},[296,5978,1269],{"class":302},[296,5980,5981,5983,5985,5987,5989,5991,5993,5995,5997,5999,6001],{"class":298,"line":1721},[296,5982,1341],{"class":306},[296,5984,1726],{"class":302},[296,5986,307],{"class":306},[296,5988,1349],{"class":313},[296,5990,397],{"class":302},[296,5992,1644],{"class":313},[296,5994,514],{"class":302},[296,5996,1194],{"class":313},[296,5998,1294],{"class":302},[296,6000,1653],{"class":408},[296,6002,1360],{"class":302},[296,6004,6005,6007,6009,6011,6013,6015,6017,6019,6021],{"class":298,"line":1747},[296,6006,1341],{"class":306},[296,6008,1752],{"class":302},[296,6010,307],{"class":306},[296,6012,1349],{"class":313},[296,6014,397],{"class":302},[296,6016,1671],{"class":306},[296,6018,1294],{"class":302},[296,6020,1676],{"class":408},[296,6022,1360],{"class":302},[296,6024,6025,6027,6029,6031],{"class":298,"line":1769},[296,6026,1366],{"class":306},[296,6028,1369],{"class":302},[296,6030,1372],{"class":306},[296,6032,1778],{"class":302},[296,6034,6035],{"class":298,"line":1781},[296,6036,1381],{"class":302},[296,6038,6039,6041,6043,6045,6047,6049,6051,6053,6055],{"class":298,"line":1786},[296,6040,1387],{"class":306},[296,6042,511],{"class":313},[296,6044,514],{"class":302},[296,6046,1394],{"class":313},[296,6048,1183],{"class":302},[296,6050,1799],{"class":408},[296,6052,1802],{"class":302},[296,6054,1405],{"class":313},[296,6056,1408],{"class":302},[296,6058,6059],{"class":298,"line":1809},[296,6060,1414],{"class":302},[296,6062,6063,6065,6067,6069],{"class":298,"line":1814},[296,6064,1366],{"class":306},[296,6066,1369],{"class":302},[296,6068,1372],{"class":306},[296,6070,1823],{"class":302},[296,6072,6073],{"class":298,"line":1826},[296,6074,1381],{"class":302},[296,6076,6077,6079,6081,6083,6085,6087,6089,6091,6093],{"class":298,"line":1831},[296,6078,1387],{"class":306},[296,6080,511],{"class":313},[296,6082,514],{"class":302},[296,6084,1394],{"class":313},[296,6086,1183],{"class":302},[296,6088,1844],{"class":408},[296,6090,1847],{"class":302},[296,6092,1405],{"class":313},[296,6094,1408],{"class":302},[296,6096,6097],{"class":298,"line":1854},[296,6098,1414],{"class":302},[296,6100,6101,6103,6105,6107,6109,6111,6113,6115,6117,6119,6121,6123,6125],{"class":298,"line":1859},[296,6102,1366],{"class":306},[296,6104,1864],{"class":302},[296,6106,459],{"class":313},[296,6108,1869],{"class":302},[296,6110,1872],{"class":313},[296,6112,1327],{"class":302},[296,6114,1877],{"class":306},[296,6116,477],{"class":302},[296,6118,459],{"class":313},[296,6120,1327],{"class":302},[296,6122,397],{"class":306},[296,6124,1888],{"class":495},[296,6126,1221],{"class":302},[296,6128,6129],{"class":298,"line":1893},[296,6130,1381],{"class":302},[296,6132,6133,6135,6137,6139,6141,6143,6145],{"class":298,"line":1898},[296,6134,1387],{"class":306},[296,6136,1189],{"class":313},[296,6138,514],{"class":302},[296,6140,1907],{"class":313},[296,6142,1183],{"class":302},[296,6144,1912],{"class":408},[296,6146,1360],{"class":302},[296,6148,6149],{"class":298,"line":1917},[296,6150,1414],{"class":302},[296,6152,6153],{"class":298,"line":1922},[296,6154,625],{"emptyLinePlaceholder":624},[296,6156,6157,6159,6161,6163,6165],{"class":298,"line":1927},[296,6158,1930],{"class":302},[296,6160,307],{"class":306},[296,6162,456],{"class":302},[296,6164,459],{"class":313},[296,6166,317],{"class":302},[296,6168,6169,6171,6173,6175,6177],{"class":298,"line":1944},[296,6170,1947],{"class":302},[296,6172,307],{"class":306},[296,6174,477],{"class":302},[296,6176,459],{"class":313},[296,6178,317],{"class":302},[296,6180,6181,6183,6185,6187],{"class":298,"line":1961},[296,6182,1964],{"class":302},[296,6184,307],{"class":306},[296,6186,496],{"class":495},[296,6188,1471],{"class":302},[296,6190,6191],{"class":298,"line":1976},[296,6192,1979],{"class":465},[296,6194,6195,6197,6199,6201,6203,6205,6207,6209,6211,6213,6215],{"class":298,"line":1982},[296,6196,1420],{"class":313},[296,6198,1423],{"class":302},[296,6200,1426],{"class":306},[296,6202,1991],{"class":408},[296,6204,1994],{"class":306},[296,6206,1997],{"class":302},[296,6208,1426],{"class":306},[296,6210,1462],{"class":408},[296,6212,1465],{"class":495},[296,6214,1468],{"class":408},[296,6216,1471],{"class":302},[296,6218,6219,6221,6223,6225,6227],{"class":298,"line":2010},[296,6220,1275],{"class":306},[296,6222,511],{"class":313},[296,6224,514],{"class":302},[296,6226,517],{"class":313},[296,6228,2027],{"class":302},[296,6230,6231],{"class":298,"line":2016},[296,6232,1306],{"class":302},[296,6234,6235],{"class":298,"line":2030},[296,6236,625],{"emptyLinePlaceholder":624},[296,6238,6239,6241,6243,6245,6247,6249],{"class":298,"line":2035},[296,6240,1317],{"class":313},[296,6242,514],{"class":302},[296,6244,517],{"class":313},[296,6246,2049],{"class":313},[296,6248,1327],{"class":302},[296,6250,1330],{"class":306},[296,6252,6253],{"class":298,"line":2040},[296,6254,1269],{"class":302},[296,6256,6257],{"class":298,"line":2056},[296,6258,4512],{"class":465},[296,6260,6261,6263],{"class":298,"line":2061},[296,6262,2070],{"class":306},[296,6264,2073],{"class":302},[296,6266,6267,6269,6271,6273,6275,6277],{"class":298,"line":2067},[296,6268,1420],{"class":313},[296,6270,1423],{"class":302},[296,6272,1426],{"class":306},[296,6274,2085],{"class":408},[296,6276,1994],{"class":306},[296,6278,2090],{"class":302},[296,6280,6281,6283,6285,6287,6289,6291,6293,6295,6297],{"class":298,"line":2076},[296,6282,1435],{"class":306},[296,6284,2098],{"class":408},[296,6286,1994],{"class":306},[296,6288,2103],{"class":302},[296,6290,1426],{"class":306},[296,6292,1462],{"class":408},[296,6294,1465],{"class":495},[296,6296,1468],{"class":408},[296,6298,1471],{"class":302},[296,6300,6301,6303,6305,6307],{"class":298,"line":2093},[296,6302,1366],{"class":306},[296,6304,633],{"class":302},[296,6306,636],{"class":306},[296,6308,639],{"class":302},[296,6310,6311],{"class":298,"line":2116},[296,6312,1381],{"class":302},[296,6314,6315,6317,6319,6321,6323,6325,6327,6329,6331,6333,6335],{"class":298,"line":2122},[296,6316,2141],{"class":313},[296,6318,1423],{"class":302},[296,6320,1426],{"class":306},[296,6322,2148],{"class":408},[296,6324,1994],{"class":306},[296,6326,1997],{"class":302},[296,6328,1426],{"class":306},[296,6330,1462],{"class":408},[296,6332,1465],{"class":495},[296,6334,1468],{"class":408},[296,6336,1471],{"class":302},[296,6338,6339,6341,6343,6345,6347],{"class":298,"line":2133},[296,6340,2174],{"class":306},[296,6342,511],{"class":313},[296,6344,514],{"class":302},[296,6346,517],{"class":313},[296,6348,2183],{"class":302},[296,6350,6351],{"class":298,"line":2138},[296,6352,1414],{"class":302},[296,6354,6355,6357,6359,6361,6363],{"class":298,"line":2165},[296,6356,1275],{"class":306},[296,6358,511],{"class":313},[296,6360,514],{"class":302},[296,6362,517],{"class":313},[296,6364,2027],{"class":302},[296,6366,6367],{"class":298,"line":2171},[296,6368,1306],{"class":302},[296,6370,6371],{"class":298,"line":2186},[296,6372,625],{"emptyLinePlaceholder":624},[296,6374,6375,6377,6379,6381],{"class":298,"line":2191},[296,6376,2223],{"class":306},[296,6378,2226],{"class":313},[296,6380,1327],{"class":302},[296,6382,1330],{"class":306},[296,6384,6385],{"class":298,"line":2197},[296,6386,1269],{"class":302},[296,6388,6389],{"class":298,"line":2210},[296,6390,2247],{"class":465},[296,6392,6393,6395,6397,6399,6401,6403],{"class":298,"line":2215},[296,6394,1420],{"class":313},[296,6396,1423],{"class":302},[296,6398,1426],{"class":306},[296,6400,2259],{"class":408},[296,6402,1994],{"class":306},[296,6404,2264],{"class":302},[296,6406,6407,6409,6411,6413,6415,6417,6419,6421,6423],{"class":298,"line":2220},[296,6408,1435],{"class":306},[296,6410,2272],{"class":408},[296,6412,1994],{"class":306},[296,6414,2277],{"class":302},[296,6416,1426],{"class":306},[296,6418,1462],{"class":408},[296,6420,1465],{"class":495},[296,6422,1468],{"class":408},[296,6424,1471],{"class":302},[296,6426,6427,6429,6431,6433],{"class":298,"line":2233},[296,6428,1964],{"class":302},[296,6430,307],{"class":306},[296,6432,496],{"class":495},[296,6434,1471],{"class":302},[296,6436,6437],{"class":298,"line":2238},[296,6438,1306],{"class":302},[296,6440,6441],{"class":298,"line":2244},[296,6442,625],{"emptyLinePlaceholder":624},[296,6444,6445],{"class":298,"line":2250},[296,6446,2314],{"class":306},[296,6448,6449,6451],{"class":298,"line":2267},[296,6450,2320],{"class":313},[296,6452,4707],{"class":302},[296,6454,6455,6457,6459,6461,6463],{"class":298,"line":2290},[296,6456,2332],{"class":306},[296,6458,2103],{"class":302},[296,6460,307],{"class":306},[296,6462,496],{"class":495},[296,6464,1471],{"class":302},[296,6466,6467,6469,6471,6473,6475],{"class":298,"line":2301},[296,6468,2332],{"class":306},[296,6470,2277],{"class":302},[296,6472,307],{"class":306},[296,6474,496],{"class":495},[296,6476,1471],{"class":302},[296,6478,6479],{"class":298,"line":2306},[296,6480,1517],{"class":302},[296,6482,6483],{"class":298,"line":2311},[296,6484,625],{"emptyLinePlaceholder":624},[296,6486,6487,6489,6491],{"class":298,"line":2317},[296,6488,1671],{"class":306},[296,6490,2377],{"class":313},[296,6492,1263],{"class":302},[296,6494,6495],{"class":298,"line":2329},[296,6496,644],{"class":302},[296,6498,6499],{"class":298,"line":2346},[296,6500,4756],{"class":465},[296,6502,6503,6505,6507,6509,6511,6513],{"class":298,"line":2362},[296,6504,2396],{"class":306},[296,6506,2399],{"class":306},[296,6508,2402],{"class":302},[296,6510,307],{"class":306},[296,6512,2407],{"class":495},[296,6514,1471],{"class":302},[296,6516,6517],{"class":298,"line":2367},[296,6518,625],{"emptyLinePlaceholder":624},[296,6520,6521],{"class":298,"line":2372},[296,6522,2420],{"class":306},[296,6524,6525],{"class":298,"line":2382},[296,6526,1269],{"class":302},[296,6528,6529,6531],{"class":298,"line":2387},[296,6530,2431],{"class":313},[296,6532,2434],{"class":302},[296,6534,6535,6537,6539,6541,6543,6545,6547],{"class":298,"line":2393},[296,6536,2440],{"class":302},[296,6538,397],{"class":306},[296,6540,758],{"class":302},[296,6542,2447],{"class":306},[296,6544,1183],{"class":302},[296,6546,2452],{"class":408},[296,6548,1360],{"class":302},[296,6550,6551,6553,6555,6557,6559,6561,6563],{"class":298,"line":2412},[296,6552,2440],{"class":302},[296,6554,397],{"class":306},[296,6556,337],{"class":302},[296,6558,2447],{"class":306},[296,6560,1183],{"class":302},[296,6562,2470],{"class":408},[296,6564,1360],{"class":302},[296,6566,6567],{"class":298,"line":2417},[296,6568,625],{"emptyLinePlaceholder":624},[296,6570,6571,6573,6575,6577,6579,6581,6583,6585,6587],{"class":298,"line":2423},[296,6572,1341],{"class":306},[296,6574,2485],{"class":302},[296,6576,307],{"class":306},[296,6578,511],{"class":313},[296,6580,514],{"class":302},[296,6582,2494],{"class":313},[296,6584,514],{"class":302},[296,6586,2499],{"class":313},[296,6588,317],{"class":302},[296,6590,6591,6593,6595,6597,6599,6601,6603],{"class":298,"line":2428},[296,6592,2507],{"class":302},[296,6594,2510],{"class":313},[296,6596,1183],{"class":302},[296,6598,2515],{"class":408},[296,6600,1204],{"class":302},[296,6602,2520],{"class":495},[296,6604,1360],{"class":302},[296,6606,6607,6609,6611,6613,6615,6617],{"class":298,"line":2437},[296,6608,1341],{"class":306},[296,6610,2530],{"class":302},[296,6612,307],{"class":306},[296,6614,2535],{"class":302},[296,6616,2538],{"class":313},[296,6618,2541],{"class":302},[296,6620,6621],{"class":298,"line":2457},[296,6622,625],{"emptyLinePlaceholder":624},[296,6624,6625,6627,6629,6631,6633,6635,6637],{"class":298,"line":2475},[296,6626,2431],{"class":313},[296,6628,2554],{"class":302},[296,6630,307],{"class":306},[296,6632,511],{"class":313},[296,6634,514],{"class":302},[296,6636,517],{"class":313},[296,6638,2027],{"class":302},[296,6640,6641,6643,6645,6647,6649],{"class":298,"line":2480},[296,6642,2570],{"class":306},[296,6644,2573],{"class":302},[296,6646,307],{"class":306},[296,6648,496],{"class":495},[296,6650,1471],{"class":302},[296,6652,6653,6655,6657,6659,6661,6663,6665],{"class":298,"line":2504},[296,6654,2585],{"class":306},[296,6656,2588],{"class":302},[296,6658,2591],{"class":306},[296,6660,511],{"class":313},[296,6662,514],{"class":302},[296,6664,517],{"class":313},[296,6666,2600],{"class":302},[296,6668,6669],{"class":298,"line":2525},[296,6670,1381],{"class":302},[296,6672,6673,6675,6677,6679,6681,6683,6685,6687,6689,6691,6693,6695],{"class":298,"line":2544},[296,6674,2141],{"class":313},[296,6676,1423],{"class":302},[296,6678,1426],{"class":306},[296,6680,2617],{"class":408},[296,6682,1994],{"class":306},[296,6684,2622],{"class":306},[296,6686,2625],{"class":302},[296,6688,1426],{"class":306},[296,6690,1462],{"class":408},[296,6692,1465],{"class":495},[296,6694,1468],{"class":408},[296,6696,1471],{"class":302},[296,6698,6699,6701,6703,6705,6707],{"class":298,"line":2549},[296,6700,2647],{"class":302},[296,6702,307],{"class":306},[296,6704,310],{"class":302},[296,6706,314],{"class":313},[296,6708,317],{"class":302},[296,6710,6711,6713,6715,6717,6719,6721,6723,6725,6727,6729,6731,6733,6735,6737],{"class":298,"line":2567},[296,6712,2141],{"class":313},[296,6714,1423],{"class":302},[296,6716,1426],{"class":306},[296,6718,2667],{"class":408},[296,6720,1994],{"class":306},[296,6722,511],{"class":313},[296,6724,514],{"class":302},[296,6726,2676],{"class":313},[296,6728,2679],{"class":302},[296,6730,1426],{"class":306},[296,6732,1462],{"class":408},[296,6734,1465],{"class":495},[296,6736,1468],{"class":408},[296,6738,1471],{"class":302},[296,6740,6741,6743,6745,6747,6749,6751,6753],{"class":298,"line":2582},[296,6742,2695],{"class":306},[296,6744,2588],{"class":302},[296,6746,2700],{"class":306},[296,6748,511],{"class":313},[296,6750,514],{"class":302},[296,6752,517],{"class":313},[296,6754,2600],{"class":302},[296,6756,6757],{"class":298,"line":2603},[296,6758,2714],{"class":302},[296,6760,6761,6763],{"class":298,"line":2608},[296,6762,2720],{"class":306},[296,6764,1471],{"class":302},[296,6766,6767],{"class":298,"line":2638},[296,6768,2728],{"class":302},[296,6770,6771],{"class":298,"line":2644},[296,6772,625],{"emptyLinePlaceholder":624},[296,6774,6775,6777,6779,6781,6783,6785,6787],{"class":298,"line":2658},[296,6776,2695],{"class":306},[296,6778,2741],{"class":302},[296,6780,2744],{"class":306},[296,6782,2573],{"class":302},[296,6784,2591],{"class":306},[296,6786,2751],{"class":495},[296,6788,1221],{"class":302},[296,6790,6791],{"class":298,"line":2692},[296,6792,2714],{"class":302},[296,6794,6795,6797,6799,6801,6803,6805,6807],{"class":298,"line":2711},[296,6796,2764],{"class":302},[296,6798,2510],{"class":313},[296,6800,1183],{"class":302},[296,6802,2515],{"class":408},[296,6804,1204],{"class":302},[296,6806,2775],{"class":495},[296,6808,1360],{"class":302},[296,6810,6811,6813,6815,6817,6819,6821,6823],{"class":298,"line":2717},[296,6812,2783],{"class":313},[296,6814,1423],{"class":302},[296,6816,1426],{"class":306},[296,6818,2790],{"class":408},[296,6820,1465],{"class":495},[296,6822,2795],{"class":408},[296,6824,1471],{"class":302},[296,6826,6827,6829,6831],{"class":298,"line":2725},[296,6828,3729],{"class":306},[296,6830,3732],{"class":495},[296,6832,1471],{"class":302},[296,6834,6835],{"class":298,"line":2731},[296,6836,2728],{"class":302},[296,6838,6839],{"class":298,"line":2736},[296,6840,2808],{"class":465},[296,6842,6843,6845,6847,6849,6851,6853,6855,6857,6859,6861,6863],{"class":298,"line":2756},[296,6844,2814],{"class":302},[296,6846,2817],{"class":313},[296,6848,1183],{"class":302},[296,6850,1644],{"class":313},[296,6852,514],{"class":302},[296,6854,2826],{"class":313},[296,6856,514],{"class":302},[296,6858,2831],{"class":313},[296,6860,1183],{"class":302},[296,6862,2836],{"class":495},[296,6864,2839],{"class":302},[296,6866,6867],{"class":298,"line":2761},[296,6868,1414],{"class":302},[296,6870,6871],{"class":298,"line":2780},[296,6872,625],{"emptyLinePlaceholder":624},[296,6874,6875,6877,6879,6881,6883,6885,6887,6889,6891,6893,6895,6897,6899,6901],{"class":298,"line":2800},[296,6876,1420],{"class":313},[296,6878,1423],{"class":302},[296,6880,1426],{"class":306},[296,6882,2861],{"class":408},[296,6884,1994],{"class":306},[296,6886,511],{"class":313},[296,6888,514],{"class":302},[296,6890,2676],{"class":313},[296,6892,2679],{"class":302},[296,6894,1426],{"class":306},[296,6896,1462],{"class":408},[296,6898,1465],{"class":495},[296,6900,1468],{"class":408},[296,6902,1471],{"class":302},[296,6904,6905,6907,6909,6911,6913,6915,6917,6919,6921,6923,6925,6927],{"class":298,"line":2805},[296,6906,1275],{"class":306},[296,6908,2889],{"class":302},[296,6910,2591],{"class":306},[296,6912,511],{"class":313},[296,6914,514],{"class":302},[296,6916,517],{"class":313},[296,6918,1494],{"class":302},[296,6920,1445],{"class":306},[296,6922,496],{"class":495},[296,6924,1451],{"class":306},[296,6926,1888],{"class":495},[296,6928,1471],{"class":302},[296,6930,6931],{"class":298,"line":2811},[296,6932,1306],{"class":302},[296,6934,6935,6937,6939,6941,6943,6945,6947],{"class":298,"line":2842},[296,6936,2920],{"class":306},[296,6938,1369],{"class":302},[296,6940,1186],{"class":306},[296,6942,1189],{"class":313},[296,6944,2929],{"class":302},[296,6946,1197],{"class":306},[296,6948,2934],{"class":302},[296,6950,6951],{"class":298,"line":2847},[296,6952,1269],{"class":302},[296,6954,6955,6957,6959,6961,6963,6965,6967,6969,6971,6973,6975,6977,6979],{"class":298,"line":2852},[296,6956,1420],{"class":313},[296,6958,2947],{"class":302},[296,6960,1426],{"class":306},[296,6962,2952],{"class":408},[296,6964,1994],{"class":306},[296,6966,2957],{"class":302},[296,6968,2960],{"class":313},[296,6970,1327],{"class":302},[296,6972,1426],{"class":306},[296,6974,1462],{"class":408},[296,6976,1465],{"class":495},[296,6978,1468],{"class":408},[296,6980,1471],{"class":302},[296,6982,6983,6985,6987],{"class":298,"line":2884},[296,6984,1275],{"class":306},[296,6986,2751],{"class":495},[296,6988,1471],{"class":302},[296,6990,6991],{"class":298,"line":2912},[296,6992,1306],{"class":302},[296,6994,6995],{"class":298,"line":2917},[296,6996,668],{"class":302},[20,6998,6999,7000,7003,7004,7007,7008,7011],{},"选择 ",[64,7001,7002],{},"linux-debug","，先 ",[53,7005,7006],{},"Build","，然后在下面几行设置断点，点击 CMake Tools 的 ",[53,7009,7010],{},"Debug","：",[122,7013,7014,7027],{},[125,7015,7016],{},[128,7017,7018,7021,7024],{},[131,7019,7020],{},"断点位置",[131,7022,7023],{},"暂停时看什么",[131,7025,7026],{},"对应前面的讲解",[144,7028,7029,7057,7080],{},[128,7030,7031,7039,7054],{},[149,7032,7033,7035,7036,7038],{},[64,7034,89],{}," 中打印 ",[64,7037,3280],{}," 的语句",[149,7040,7041,7043,7044,721,7046,7043,7048,721,7050,7043,7052],{},[64,7042,547],{}," 为 ",[64,7045,409],{},[64,7047,561],{},[64,7049,566],{},[64,7051,576],{},[64,7053,581],{},[149,7055,7056],{},"第一次根 tick 只准备任务",[128,7058,7059,7065,7077],{},[149,7060,7061,3003,7063],{},[64,7062,81],{},[64,7064,689],{},[149,7066,7067,7068,7070,7071,7074,7075],{},"第一次暂停时计数为 ",[64,7069,581],{},"，按 ",[64,7072,7073],{},"F10"," 执行这一行后变成 ",[64,7076,699],{},[149,7078,7079],{},"每次运行检查只把计数加一",[128,7081,7082,7089,7101],{},[149,7083,7084,3003,7086],{},[64,7085,81],{},[64,7087,7088],{},"if (completed_ticks_ >= required_ticks_)",[149,7090,7091,7092,36,7094,36,7096,7098,7099],{},"三次到这里时，计数依次为 ",[64,7093,699],{},[64,7095,712],{},[64,7097,566],{},"，要求始终为 ",[64,7100,566],{},[149,7102,7103],{},"前两次条件不成立，第三次成立",[20,7105,7106,7107,7109,7110,7113,7114,7116,7117,7119],{},"断点暂停在某一行时，先看执行这一行之前的值；",[64,7108,7073],{}," 表示单步执行，",[64,7111,7112],{},"F5"," 表示继续运行到下一个断点。\n同一次 ",[64,7115,81],{}," 中，先执行加一，再到达 ",[64,7118,630],{}," 判断，所以在这两个位置看到的计数会不同。",[20,7121,7122,7123,7125,7126,7128,7129,7131,7132,7134,7135,7137,7138,42,7140,7142,7143,7145],{},"第一次和第二次到达 ",[64,7124,630],{}," 时，按 ",[64,7127,7073],{}," 会跳过成功分支，执行最后的 ",[64,7130,589],{},"。\n第三次到达 ",[64,7133,630],{}," 时，计数已经为 ",[64,7136,566],{},"；继续单步会进入打印 ",[64,7139,70],{},[64,7141,728],{}," 的分支。\n它返回后，主程序拿到本次根 tick 的 ",[64,7144,169],{},"，结束循环。",[20,7147,7148,7149,7152],{},"在回调断点暂停时，还可以展开 VSCode 的 ",[53,7150,7151],{},"调用堆栈（CALL STACK）","，查看是谁调用了当前回调。",[20,7154,7155,7156,3003,7158,7160],{},"从当前回调沿调用者向外看，可以对应到导航节点的执行、父控制节点，以及 ",[64,7157,230],{},[64,7159,754],{},"，帮助理解回调是怎样被库调用的。",[20,7162,7163],{},[1077,7164],{"alt":98,"src":7165},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792415882439-bfbdefb7.webp",[20,7167,7168],{},[1077,7169],{"alt":98,"src":7170},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792415926303-d3afec95.webp",[20,7172,7173],{},[1077,7174],{"alt":98,"src":7175},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792415991771-85e33ffa.webp",[281,7177,7178],{"id":7178},"再观察运行中的任务怎样被中止",[20,7180,7181,7182,5480,7184,7186,7187,7189,7190,42,7192,7194,7195,7197,7198,48],{},"结束这次调试，将 ",[64,7183,5479],{},[64,7185,2520],{},"，保存后 ",[53,7188,7006],{},"。\n保留 ",[64,7191,89],{},[64,7193,81],{}," 的断点，并在 ",[64,7196,203],{}," 打印中止信息的语句处增加断点，再次点击 ",[53,7199,7010],{},[20,7201,7202,7203,7205,7206,7208,7209,7211,7212,7214,7215,7217,7218,7220,7221,7223,7224,7226,7227,7229],{},"这次先进入 ",[64,7204,89],{},"，随后只进入一次 ",[64,7207,81],{},"，将计数加到 ",[64,7210,699],{},"。\n第二次根 tick 结束后，主程序把允许标志改为 ",[64,7213,2775],{},"；继续运行，第三次根 tick 会因为条件失败而进入 ",[64,7216,203],{},"，此时仍能看到目标为 ",[64,7219,66],{},"、计数为 ",[64,7222,699],{},"。\n在清零语句上单步后，计数变成 ",[64,7225,581],{},"。这次执行不会再走到 ",[64,7228,724],{}," 的成功分支。",[122,7231,7232,7242],{},[125,7233,7234],{},[128,7235,7236,7239],{},[131,7237,7238],{},"执行过程",[131,7240,7241],{},"实际观察到的回调",[144,7243,7244,7259],{},[128,7245,7246,7249],{},[149,7247,7248],{},"关闭取消",[149,7250,7251,7253,7254,7256,7257],{},[64,7252,89],{}," 一次，",[64,7255,81],{}," 三次，最后返回 ",[64,7258,169],{},[128,7260,7261,7264],{},[149,7262,7263],{},"开启取消",[149,7265,7266,7253,7268,7270,7271,7273,7274],{},[64,7267,89],{},[64,7269,81],{}," 一次，随后进入 ",[64,7272,203],{},"，本次根 tick 返回 ",[64,7275,173],{},[20,7277,7278],{},[1077,7279],{"alt":98,"src":7280},"https:\u002F\u002Fcdn.tungchiahui.cn\u002Ftungwebsite\u002Fassets\u002Fimages\u002F2023\u002F12\u002F30\u002F1792416273447-d6bc3b12.webp",[20,7282,7283,7284,7286,7287,48],{},"要观察本篇的取消逻辑，使用条件变化或 ",[64,7285,5330],{}," 的对照。\nVSCode 的“停止调试”控制的是调试进程，不能用它来保证程序一定执行到 ",[64,7288,203],{},[20,7290,7291,7292,7294,7295,7298,7299,7302],{},"全部观察完成后，恢复最初的完整程序和 XML，再将取消设置改回 ",[64,7293,2775],{},"。\n本篇完整程序及正常完成、条件中止、普通 Sequence 对照、主动停止、无效次数和断点观察，已在 Ubuntu 22.04 的 ",[64,7296,7297],{},"ysu_ros_humble"," 容器中，使用 ",[53,7300,7301],{},"C++20、CMake 3.22.1、GCC 11.4、BehaviorTree.CPP 3.8.7"," 验证。\n测试使用临时工程和 Ninja，没有修改容器内已有练习工程。",[102,7304],{},[12,7306,7307],{"id":7307},"接入真实导航时替换什么",[20,7309,7310,7311,7314],{},"本篇用 ",[64,7312,7313],{},"completed_ticks_ >= required_ticks_"," 作为成功条件，是为了让回调过程容易观察。\n接入真实导航时，应把这个计数模拟换成导航系统的请求和结果检查：",[122,7316,7317,7326],{},[125,7318,7319],{},[128,7320,7321,7323],{},[131,7322,133],{},[131,7324,7325],{},"真实导航中对应的工作",[144,7327,7328,7337,7354],{},[128,7329,7330,7334],{},[149,7331,7332],{},[64,7333,89],{},[149,7335,7336],{},"发送一次导航请求，保存后续检查需要的任务信息",[128,7338,7339,7343],{},[149,7340,7341],{},[64,7342,81],{},[149,7344,7345,7346,7348,7349,7351,7352],{},"检查该请求的最新结果；仍在执行就返回 ",[64,7347,115],{},"，确认到达后返回 ",[64,7350,169],{},"，任务失败时返回 ",[64,7353,173],{},[128,7355,7356,7360],{},[149,7357,7358],{},[64,7359,203],{},[149,7361,7362],{},"对仍在执行的请求发起取消，并处理当前任务需要的清理",[20,7364,7365,7366,7368],{},"成功条件由节点实现决定，再通过返回值告诉行为树。\n因此，理解本篇代码时，要把“库根据状态选择哪个回调”和“节点根据什么条件报告成功”分开看：前者由 ",[64,7367,119],{}," 提供，后者由我们编写的导航节点实现。",[102,7370],{},[12,7372,7373],{"id":7373},"当前学习进度",[20,7375,7376,7377,7380],{},"本篇补齐了持续动作的生命周期、主循环驱动和中止处理。\n下一篇",[64,7378,7379],{},"组合实际任务","复用持续导航，把电量检查、子树数据映射、有限重试和多个 XML 文件组织成一个完整任务。",[7382,7383,7384],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}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);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":98,"searchDepth":469,"depth":469,"links":7386},[7387,7388,7395,7401,7402,7403,7404,7407,7411,7412],{"id":14,"depth":469,"text":15},{"id":106,"depth":469,"text":106,"children":7389},[7390,7391,7392,7393,7394],{"id":283,"depth":487,"text":284},{"id":381,"depth":487,"text":382},{"id":596,"depth":487,"text":597},{"id":747,"depth":487,"text":748},{"id":895,"depth":487,"text":896},{"id":951,"depth":469,"text":951,"children":7396},[7397,7398,7400],{"id":1082,"depth":487,"text":1027},{"id":3010,"depth":487,"text":7399},"tree.sleep() 的参数与作用",{"id":3114,"depth":487,"text":1030},{"id":3245,"depth":469,"text":3245},{"id":3349,"depth":469,"text":3349},{"id":3447,"depth":469,"text":3448},{"id":3606,"depth":469,"text":3606,"children":7405},[7406],{"id":5340,"depth":487,"text":5341},{"id":5469,"depth":469,"text":5470,"children":7408},[7409,7410],{"id":5473,"depth":487,"text":5473},{"id":7178,"depth":487,"text":7178},{"id":7307,"depth":469,"text":7307},{"id":7373,"depth":469,"text":7373},"1200-0400-0200-0500","2023-12-30","2023-12-30-ros2-tutorial","\u002Fwiki\u002F2023-12-30-ros2-tutorial","Ros2 Tutorial","md",false,{},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0500-chi-xu-ren-wu-yu-zhong-zhi",{"title":5,"description":98},"wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0500-持续任务与中止","5j1xJv6JQkbzse70tckzq2V-NPB6opC_d1NmxKSc-nM",[7426,7433,7439,7445,7451,7457,7462,7468,7474,7480,7486,7492,7498,7504,7510,7516,7522,7528,7534,7540,7546,7552,7558,7564,7566,7571,7577,7583,7589,7595,7601,7607,7613,7619,7625,7630,7636,7641,7647,7653,7659,7665,7671,7677,7683,7689,7695,7701,7707,7713,7719,7725,7731,7737,7743,7749,7755,7761,7767,7773,7779,7785,7791,7797,7803,7809,7815,7821,7827],{"path":7427,"stem":7428,"title":7429,"authors":7430,"date":7414,"chapterOrder":7431,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0100-ros2-jie-shao","wiki\u002F2023-12-30-ros2-tutorial\u002F0100-ROS2介绍","ROS2介绍",[7],"0100",0,{"path":7434,"stem":7435,"title":7436,"authors":7437,"date":7414,"chapterOrder":7438,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0200-ru-men-cao-zuo","wiki\u002F2023-12-30-ros2-tutorial\u002F0200-入门操作","入门操作",[7],"0200",{"path":7440,"stem":7441,"title":7442,"authors":7443,"date":7414,"chapterOrder":7444,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0300-gong-zuo-kong-jian-yu-gong-neng-bao","wiki\u002F2023-12-30-ros2-tutorial\u002F0300-工作空间与功能包","工作空间与功能包",[7],"0300",{"path":7446,"stem":7447,"title":7448,"authors":7449,"date":7414,"chapterOrder":7450,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0400-si-da-tong-xin","wiki\u002F2023-12-30-ros2-tutorial\u002F0400-四大通信","四大通信",[7],"0400",{"path":7452,"stem":7453,"title":7454,"authors":7455,"date":7414,"chapterOrder":7456,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0500-ros2-qi-ta-tong-xin-ji-zhi","wiki\u002F2023-12-30-ros2-tutorial\u002F0500-ROS2其他通信机制","ROS2其他通信机制",[7],"0500",{"path":7458,"stem":7459,"title":3262,"authors":7460,"date":7414,"chapterOrder":7461,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0600-launch","wiki\u002F2023-12-30-ros2-tutorial\u002F0600-Launch",[7],"0600",{"path":7463,"stem":7464,"title":7465,"authors":7466,"date":7414,"chapterOrder":7467,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0700-hui-su-rosbag2","wiki\u002F2023-12-30-ros2-tutorial\u002F0700-回溯rosbag2","回溯rosbag2",[7],"0700",{"path":7469,"stem":7470,"title":7471,"authors":7472,"date":7414,"chapterOrder":7473,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0800-zuo-biao-bian-huan-tf","wiki\u002F2023-12-30-ros2-tutorial\u002F0800-坐标变换TF","坐标变换TF",[7],"0800",{"path":7475,"stem":7476,"title":7477,"authors":7478,"date":7414,"chapterOrder":7479,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F0900-ke-shi-hua-ping-tai-rviz2-yu-urdf-jian-mo-yu-yan","wiki\u002F2023-12-30-ros2-tutorial\u002F0900-可视化平台RVIZ2与URDF建模语言","可视化平台RVIZ2与URDF建模语言",[7],"0900",{"path":7481,"stem":7482,"title":7483,"authors":7484,"date":7414,"chapterOrder":7485,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1000-stage-ros2-fang-zhen-ping-tai","wiki\u002F2023-12-30-ros2-tutorial\u002F1000-Stage_Ros2仿真平台","Stage_Ros2仿真平台",[7],"1000",{"path":7487,"stem":7488,"title":7489,"authors":7490,"date":7414,"chapterOrder":7491,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1100-0100-gazeboclassic","wiki\u002F2023-12-30-ros2-tutorial\u002F1100-0100-GazeboClassic","Gezebo Classic",[7],"1100-0100",{"path":7493,"stem":7494,"title":7495,"authors":7496,"date":7414,"chapterOrder":7497,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1100-0200-ignitiongazebo","wiki\u002F2023-12-30-ros2-tutorial\u002F1100-0200-IgnitionGazebo","Ignition Gazebo（Gazebo Fortress）",[7],"1100-0200",{"path":7499,"stem":7500,"title":7501,"authors":7502,"date":7414,"chapterOrder":7503,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1100-0300-gazebosim","wiki\u002F2023-12-30-ros2-tutorial\u002F1100-0300-GazeboSim","Gz Sim（Gazebo Harmonic）",[7],"1100-0300",{"path":7505,"stem":7506,"title":7507,"authors":7508,"date":7414,"chapterOrder":7509,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1100-0400-igngz2gzsim","wiki\u002F2023-12-30-ros2-tutorial\u002F1100-0400-Igngz2gzsim","将Ign Gazebo迁移至Gz Sim",[7],"1100-0400",{"path":7511,"stem":7512,"title":7513,"authors":7514,"date":7414,"chapterOrder":7515,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1100-gezebo-fang-zhen-ping-tai","wiki\u002F2023-12-30-ros2-tutorial\u002F1100-Gezebo仿真平台","Gezebo仿真平台",[7],"1100",{"path":7517,"stem":7518,"title":7519,"authors":7520,"date":7414,"chapterOrder":7521,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0100-humble-ban-ben","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0100-Humble版本","Humble导航仿真",[7],"1200-0100",{"path":7523,"stem":7524,"title":7525,"authors":7526,"date":7414,"chapterOrder":7527,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0200-jazzy-ban-ben","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0200-Jazzy版本","Jazzy导航仿真",[7],"1200-0200",{"path":7529,"stem":7530,"title":7531,"authors":7532,"date":7414,"chapterOrder":7533,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0300-humble2jazzy","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0300-Humble2Jazzy","Humble与Jazzy导航的差异",[7],"1200-0300",{"path":7535,"stem":7536,"title":7537,"authors":7538,"date":7414,"chapterOrder":7539,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0100-you-xian-zhuang-tai-ji-fsm","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0100-有限状态机FSM","有限状态机（Finite State Machine）",[7],"1200-0400-0100",{"path":7541,"stem":7542,"title":7543,"authors":7544,"date":7414,"chapterOrder":7545,"chapterDepth":487,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0100-ji-ben-gai-nian","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0100-基本概念","基本概念",[7],"1200-0400-0200-0100",{"path":7547,"stem":7548,"title":7549,"authors":7550,"date":7414,"chapterOrder":7551,"chapterDepth":487,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0200-kong-zhi-yu-zhuang-shi-gui-ze","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0200-控制与装饰规则","控制与装饰规则",[7],"1200-0400-0200-0200",{"path":7553,"stem":7554,"title":7555,"authors":7556,"date":7414,"chapterOrder":7557,"chapterDepth":487,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0300-di-yi-ge-wan-zheng-cheng-xu","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0300-第一个完整程序","第一个完整程序",[7],"1200-0400-0200-0300",{"path":7559,"stem":7560,"title":7561,"authors":7562,"date":7414,"chapterOrder":7563,"chapterDepth":487,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0400-jie-dian-zhi-jian-chuan-shu-ju","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0400-节点之间传数据","节点之间传数据",[7],"1200-0400-0200-0400",{"path":7421,"stem":7423,"title":5,"authors":7565,"date":7414,"chapterOrder":7413,"chapterDepth":487,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},[7],{"path":7567,"stem":7568,"title":7379,"authors":7569,"date":7414,"chapterOrder":7570,"chapterDepth":487,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0600-zu-he-shi-ji-ren-wu","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-0600-组合实际任务",[7],"1200-0400-0200-0600",{"path":7572,"stem":7573,"title":7574,"authors":7575,"date":7414,"chapterOrder":7576,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-xing-wei-shu-bt","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-0200-行为树BT","行为树（BehaviorTree.CPP）",[7],"1200-0400-0200",{"path":7578,"stem":7579,"title":7580,"authors":7581,"date":7414,"chapterOrder":7582,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-fsm-yu-bt","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-0400-FSM与BT","有限状态机FSM与行为树BT",[7],"1200-0400",{"path":7584,"stem":7585,"title":7586,"authors":7587,"date":7414,"chapterOrder":7588,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1200-ji-qi-ren-dao-hang-navigation2-fang-zhen-pian","wiki\u002F2023-12-30-ros2-tutorial\u002F1200-机器人导航Navigation2(仿真篇)","机器人导航Navigation2(仿真篇)",[7],"1200",{"path":7590,"stem":7591,"title":7592,"authors":7593,"date":7414,"chapterOrder":7594,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0100-0100-boost-aiso","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0100-0100-Boost.Aiso","Boost.Asio库",[7],"1300-0100-0100",{"path":7596,"stem":7597,"title":7598,"authors":7599,"date":7414,"chapterOrder":7600,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0100-0200-ros2-serial-driver","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0100-0200-ros2_serial_driver","ROS2 Serial Driver库",[7],"1300-0100-0200",{"path":7602,"stem":7603,"title":7604,"authors":7605,"date":7414,"chapterOrder":7606,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0100-chuan-kou-tong-xin","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0100-串口通信","UART串口通信",[7],"1300-0100",{"path":7608,"stem":7609,"title":7610,"authors":7611,"date":7414,"chapterOrder":7612,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0200-0100-socketcan","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0200-0100-socketcan","SocketCAN",[7],"1300-0200-0100",{"path":7614,"stem":7615,"title":7616,"authors":7617,"date":7414,"chapterOrder":7618,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0200-0200-ros2-socketcan","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0200-0200-ros2_socketcan","ROS2_SocketCAN",[7],"1300-0200-0200",{"path":7620,"stem":7621,"title":7622,"authors":7623,"date":7414,"chapterOrder":7624,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0200-can-tong-xin","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0200-CAN通信","CAN通信",[7],"1300-0200",{"path":7626,"stem":7627,"title":7592,"authors":7628,"date":7414,"chapterOrder":7629,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0300-0100-boost-aiso","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0300-0100-Boost.Aiso",[7],"1300-0300-0100",{"path":7631,"stem":7632,"title":7633,"authors":7634,"date":7414,"chapterOrder":7635,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0300-tcp-tong-xin","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0300-TCP通信","TCP通信",[7],"1300-0300",{"path":7637,"stem":7638,"title":7592,"authors":7639,"date":7414,"chapterOrder":7640,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0400-0100-boost-aiso","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0400-0100-Boost.Aiso",[7],"1300-0400-0100",{"path":7642,"stem":7643,"title":7644,"authors":7645,"date":7414,"chapterOrder":7646,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-0400-udp-tong-xin","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-0400-UDP通信","UDP通信",[7],"1300-0400",{"path":7648,"stem":7649,"title":7650,"authors":7651,"date":7414,"chapterOrder":7652,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1300-linux-ying-jian-tong-xin","wiki\u002F2023-12-30-ros2-tutorial\u002F1300-Linux硬件通信","Linux硬件通信",[7],"1300",{"path":7654,"stem":7655,"title":7656,"authors":7657,"date":7414,"chapterOrder":7658,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0100-ji-qi-ren-zu-cheng","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0100-机器人组成","机器人组成",[7],"1400-0100",{"path":7660,"stem":7661,"title":7662,"authors":7663,"date":7414,"chapterOrder":7664,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0200-0100-yuan-cheng-kai-fa-ssh","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0200-0100-远程开发SSH","远程开发SSH",[7],"1400-0200-0100",{"path":7666,"stem":7667,"title":7668,"authors":7669,"date":7414,"chapterOrder":7670,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0200-0200-yuan-cheng-fang-wen-zhuo-mian","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0200-0200-远程访问桌面","远程访问桌面",[7],"1400-0200-0200",{"path":7672,"stem":7673,"title":7674,"authors":7675,"date":7414,"chapterOrder":7676,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0200-gong-kong-ji-zhi-yuan-cheng-kai-fa-huan-jing","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0200-工控机之远程开发环境","工控机之远程开发环境",[7],"1400-0200",{"path":7678,"stem":7679,"title":7680,"authors":7681,"date":7414,"chapterOrder":7682,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0300-gong-kong-ji-zhi-wai-jie-usb-she-bei","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0300-工控机之外接USB设备","工控机之外接USB设备",[7],"1400-0300",{"path":7684,"stem":7685,"title":7686,"authors":7687,"date":7414,"chapterOrder":7688,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0400-fen-bu-shi-da-jian","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0400-分布式搭建","分布式搭建",[7],"1400-0400",{"path":7690,"stem":7691,"title":7692,"authors":7693,"date":7414,"chapterOrder":7694,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0500-you-hua-ri-zhi","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0500-优化日志","优化日志",[7],"1400-0500",{"path":7696,"stem":7697,"title":7698,"authors":7699,"date":7414,"chapterOrder":7700,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0100-li-cheng-ji-odom","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0100-里程计Odom","里程计Odom",[7],"1400-0600-0100",{"path":7702,"stem":7703,"title":7704,"authors":7705,"date":7414,"chapterOrder":7706,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0200-guan-xing-ji-imu","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0200-惯性计IMU","惯性计IMU",[7],"1400-0600-0200",{"path":7708,"stem":7709,"title":7710,"authors":7711,"date":7414,"chapterOrder":7712,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0300-ji-guang-lei-da-lidar","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0300-激光雷达LiDAR","激光雷达LiDAR",[7],"1400-0600-0300",{"path":7714,"stem":7715,"title":7716,"authors":7717,"date":7414,"chapterOrder":7718,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0400-xiang-ji-camera","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0400-相机Camera","相机Camera",[7],"1400-0600-0400",{"path":7720,"stem":7721,"title":7722,"authors":7723,"date":7414,"chapterOrder":7724,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0500-quan-qiu-ding-wei-gnss","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0500-全球定位GNSS","全球定位GNSS",[7],"1400-0600-0500",{"path":7726,"stem":7727,"title":7728,"authors":7729,"date":7414,"chapterOrder":7730,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0600-shou-bing-joy","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0600-手柄joy","手柄JOY",[7],"1400-0600-0600",{"path":7732,"stem":7733,"title":7734,"authors":7735,"date":7414,"chapterOrder":7736,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0700-jian-pan-kong-zhi-jie-dian","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-0700-键盘控制节点","键盘控制节点",[7],"1400-0600-0700",{"path":7738,"stem":7739,"title":7740,"authors":7741,"date":7414,"chapterOrder":7742,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-ying-jian-ping-tai","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0600-硬件平台","硬件平台",[7],"1400-0600",{"path":7744,"stem":7745,"title":7746,"authors":7747,"date":7414,"chapterOrder":7748,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0700-zuo-biao-xi-yu-hua-ti-guan-xi","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0700-坐标系与话题关系","坐标系与话题关系",[7],"1400-0700",{"path":7750,"stem":7751,"title":7752,"authors":7753,"date":7414,"chapterOrder":7754,"chapterDepth":487,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0100-0100-lun-shi-li-cheng-ji-biao-ding","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0100-0100-轮式里程计标定","轮式里程计标定",[7],"1400-0800-0100-0100",{"path":7756,"stem":7757,"title":7758,"authors":7759,"date":7414,"chapterOrder":7760,"chapterDepth":487,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0100-0200-lun-shi-li-cheng-ji-yu-imu-rong-he","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0100-0200-轮式里程计与IMU融合","轮式里程计与IMU融合",[7],"1400-0800-0100-0200",{"path":7762,"stem":7763,"title":7764,"authors":7765,"date":7414,"chapterOrder":7766,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0100-lun-shi-li-cheng-ji-biao-ding-yu-rong-he","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0100-轮式里程计标定与融合","轮式里程计标定与融合",[7],"1400-0800-0100",{"path":7768,"stem":7769,"title":7770,"authors":7771,"date":7414,"chapterOrder":7772,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0200-ji-guang-lei-da-gong-ju","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0200-激光雷达工具","激光雷达工具",[7],"1400-0800-0200",{"path":7774,"stem":7775,"title":7776,"authors":7777,"date":7414,"chapterOrder":7778,"chapterDepth":469,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0300-xiang-ji-shi-yong-jin-jie","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-0300-相机使用进阶","相机使用进阶",[7],"1400-0800-0300",{"path":7780,"stem":7781,"title":7782,"authors":7783,"date":7414,"chapterOrder":7784,"chapterDepth":299,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-ying-jian-ping-tai-jin-jie","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-0800-硬件平台进阶","硬件平台进阶",[7],"1400-0800",{"path":7786,"stem":7787,"title":7788,"authors":7789,"date":7414,"chapterOrder":7790,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1400-ji-qi-ren-ying-jian","wiki\u002F2023-12-30-ros2-tutorial\u002F1400-机器人硬件","机器人硬件",[7],"1400",{"path":7792,"stem":7793,"title":7794,"authors":7795,"date":7414,"chapterOrder":7796,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1500-ros2-control","wiki\u002F2023-12-30-ros2-tutorial\u002F1500-ROS2_Control","ROS2_Control",[7],"1500",{"path":7798,"stem":7799,"title":7800,"authors":7801,"date":7414,"chapterOrder":7802,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1600-moveit2-gong-ye-ji-qi-ren-ji-xie-bi","wiki\u002F2023-12-30-ros2-tutorial\u002F1600-Moveit2工业机器人机械臂","Moveit2工业机器人机械臂",[7],"1600",{"path":7804,"stem":7805,"title":7806,"authors":7807,"date":7414,"chapterOrder":7808,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1700-ji-qi-ren-dao-hang-navigation2-shi-ti-pian","wiki\u002F2023-12-30-ros2-tutorial\u002F1700-机器人导航Navigation2(实体篇)","机器人导航Navigation2(实体篇)",[7],"1700",{"path":7810,"stem":7811,"title":7812,"authors":7813,"date":7414,"chapterOrder":7814,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1800-microros","wiki\u002F2023-12-30-ros2-tutorial\u002F1800-MicroROS","MicroROS",[7],"1800",{"path":7816,"stem":7817,"title":7818,"authors":7819,"date":7414,"chapterOrder":7820,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F1900-webots-fang-zhen-ping-tai","wiki\u002F2023-12-30-ros2-tutorial\u002F1900-Webots仿真平台","Webots仿真平台",[7],"1900",{"path":7822,"stem":7823,"title":7824,"authors":7825,"date":7414,"chapterOrder":7826,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":7419},"\u002Fwiki\u002F2023-12-30-ros2-tutorial\u002F2000-opencv","wiki\u002F2023-12-30-ros2-tutorial\u002F2000-OpenCV","OpenCV",[7],"2000",{"path":7416,"stem":7828,"title":7829,"authors":7830,"date":7414,"chapterOrder":7831,"chapterDepth":7432,"docKey":7415,"docRoot":7416,"docTitle":7417,"isWikiDoc":624,"isWikiIndex":624},"wiki\u002F2023-12-30-ros2-tutorial\u002Findex","ROS2机器人操作系统教程",[7],null,[7833,7835,7838,7841],{"name":7,"image":7834},"\u002Fimages\u002Fmember_photo\u002F董佳辉.jpg",{"name":7836,"image":7837},"宫金良","\u002Fimages\u002Fmember_photo\u002F宫金良.jpg",{"name":7839,"image":7840},"巩丽","\u002Fimages\u002Fmember_photo\u002F巩丽.png",{"name":7842,"image":7843},"张彦斐","\u002Fimages\u002Fmember_photo\u002F张彦斐.jpg",1792431903440]