导航+摄像头(测距)+机械臂执行逻辑

示例目标:用户在小程序单击navigation_goal_按钮后,把机器人导航到目标物“moveit”,并操作机械臂夹起目标物。

图1 导航+摄像头(测距)+机械臂

1、(小程序)navigation_goal_:set_did_navigation_left_click("moveit", "__ROSE_MOVEIT");

set_did_navigation_left_click用于挂接当用户单击navigation_goal_按钮后,会执行什么操作。针对示例,一旦单击按钮,将使机器人开始导航,导航到目标物标识“moveit”绑定的坐标、角度。第二个参数“__ROSE_MOVEIT”是个保留字符串,表示导航成功后,要执行机械臂操作。

第二个参数可以设为一个lua函数,表示导航成功后执行这个lua函数。要控制某个蓝牙智能家居,就用这种方法。

2、某一时刻,用户单击navigation_goal_按钮,执行ros_instance_.moveto_guid(object_id, bh, luafunc)

参数object_id是目标物标识“moveit”,bh是导航成功后行为类型,此处是navigation_bh_moveit,表示操作机械臂。在navigation_bh_moveit类型时,第三个参数luafunc固定是NULL。

当set_did_navigation_left_click的第二个参数是lua函数时,bh将是navigation_bh_luafunc,第三个参数luafunc指示了要执行的lua函数。

2.1 判断当前条件是否满足导航要求,不满足就报错,报错后结束此次导航

  • 必须设置了当前地图。
  • 必须已把当前小程序的目标物标识“moveit”绑定到了当前地图的某个位置。并找到这个位置,位置的uuid标识存储在栈内变量uuid。
  • 必须已设置有效的底盘驱动、雷达驱动,并且它们不能用同一个串口。
  • bh是操作机械臂时,必须设置了有效的机械臂驱动,机械臂驱动包括一个moveit_model,这模型包括urdf、srdf、zx查找表(moveit.rsp)。

2.2 生成任务task_ptr(类型ttask*),并注册到系统

生成任务时,需要知道导航要到达的坐标+角度,这是通过位置标识uuid找到tmap_position,tmap_position存储着这两个信息。

注册是通过register_slot。register_slot会按需把tros_instance变换到started状态。

3、弹出“地图”界面,在app_post_initialize调用moveto_guid_bh

为什么要弹出“地图”?——操作机械臂时须要使用摄像头,目前使用摄像头需要一个track控件,这里用了“地图”界面中的track。

“地图”窗口类型是场景,初始化完成后会调用app_post_initialize,也就是说,在初始化完成后调用moveto_guid_bh。

bh是执行lua函数时,不须要track控件,因而在navigation_bh_luafunc类型下,是在moveto_guid未尾时调用moveto_guid_bh。

不论哪种bh,接下是进入moveto_guid_bh。

4、执行阻塞式任务:moveto_function

  1. 执行start_navigation_node,启动导航相关节点
  2. 阻塞,直到move_base节点已启动。move_base节点是在新线程运行的, 这里须同步下它和主线程。
  3. 执行do_send_goal,它有两个任务。1)机器人存在机械臂时,把机械臂设置到“navigation”状态。机械臂驱动保证把“navigation”状态对应到最适宜导航。2)调用sendGoal方法,向move_base节点发送导航目标。

sendGoal后,moveto_function就结束了。在其它节点线程,像move_base节点,将开始导航工作。moveto_function是作为阻塞式任务被执行,要求有一个bool返回值,它总是返回true。

5、让task_指向栈内变量task_ptr

task_是tros_instance成员,这样后面逻辑就可以从task_拿到这个任务了。task_ptr也将由tros_instance负责释放。


至此,用户在小程序单击navigation_goal_按钮,导致执行C++层的ros_instance_.moveto_guid方法,moveto_guid执行完毕。后面是相关导航节点进入操作,主线程则等待它们反馈,跟据反馈执行相应操作。在这里,中间过程就不详述了,直到导航结束时,move_base节点会发来导航结果,看主线程如何处理这个结果。

1、tros_instance::did_move_base_result

不论导航成功还是失败,move_base都会发出“move_base/result”话题,指示导航结果。tros_instance收到这话题,调用did_move_base_result。

  1. 调用各tslot的did_move_base_result方法。“地图”是当中一个slot,发现导航成功,而且导航后行为是操作机械臂,于是调用tcamera_rfinder::start_pickplace。并返回true,使得变量keep_task是true,即要求tros_instance::did_move_base_result继续保留task_。
  2. 导航后行为是navigation_bh_luafunc时,执行小程序层函数luafunc。如果keep_task是false,销毁task_。对操作机械臂,“1.1”已写了,不销毁task_,后面会看到,要等操作机械臂结束后,才会销毁task_。

如果导航失败,或导航成功后不是操作机械臂,那到现在,task_已销毁,此次小程序导致的导航已结束。

tcamera_rfinder::start_pickplace会指示tcamera_rfinder模块开始操作机械臂,它不是个同步操作,即不是操作完机械臂了再返回。在tcamera_rfinder模块,用了一个状态机,状态变量pickplace_step_。平时状态是空闲(nposm)。start_pickplace会启动摄像头,因为摄像头绑在机械臂,于是须要把机械臂设置到“camera”状态。机械臂驱动保证“camera”状态对应到最适宜拍摄正前方,设置完机械臂后,进入step_lookupzx状态。

2、step_lookupzx状态

此个状态下,tcamera_rfinder执行lookup_zx方法。首先调用目标物小程序的get_geometry方法得到个taplt_object_geometry结构,当中height字段指示了希望机械臂爪子要到达的高度。有了这个高度后,把它作为z,在moveit_model的zx查找表找到x、以及要达到这个zx、手臂group中各关节的关节值joints。

得到x和joints后,状态机进入step_finetune状态。

3、step_finetune状态

摄像头进入测距模式(task_range)。测距总逻辑是算出现在机器人离目标物的直线距离,然后和x比较,相差太大就移动机器人,太远让靠近目标物,太近就远离目标物。不断重复这个调整过程。如果测距成功,机器人会“站”在一个距离值接近x值的位置。

测距成功后,摄像头恢复到空闲模式,tcamera_rfinder进入step_pick状态。

只要没成功,测距一直会进行。要退出测距只有两种方法,一是成功,二是取消此次操作机械臂。

4、step_pick状态

在此个状态下,tcamera_rfinder执行pick方法。机械臂按step_lookupzx找到的joints控制手臂group各关节,以及控制爪子group关节。操和完后成后,关闭摄像头,tcamera_rfinder状态机进入空闲(nposm)状态。

在tcamera_rfinder模块,不论是此处的成功操作机械臂结束,还是失败,像测距时取消,tcamera_rfinder末尾都会调用app_pickplace_finished方法。它是个虚方法,“地图”就重载了它,内中会销毁task_。

至此,此次小程序导致的导航全部结束。

全部评论: 0

    写评论: