kLink概述

视频1 kLink:以台灯机器人为例

kLink是Launcher处理自动化的模块,自动化要解决机器人怎么处理五花八门工作,实现的顶层逻辑是这样的:小程序写出子任务,任务编辑器由这些子任务生成数个复合任务,然后用户根据自个需要,以恰当条件触发执行这些复合任务。

小程序子任务有时称单任务,复合任务则称cpp任务。

图1 kLink机制
  • 按下门铃后,机器人执行访客来访任务。
  • 来人问“打包袋有卖吗”,机器人执行问询商品任务。
  • 气温超过35度,机器人执行打开空调任务。
  • 11点,机器人执行抄三表(电表、水表、燃气表)任务。

以上这些可归结为触发哪条件后,机器人去执行哪任务。launcher把这个自动化模块称为kLink。实现kLink的代码分布到在各个地方,但最后关联“触发条件”和“执行任务”的是在一个叫kLink的窗口。

图2: kLink窗口

触发条件分为四类:IoT事件(智能家居传感器),语音,变量和定时。对应着图2右上角四个按钮,要是没改过优先级,任务列表中也是按着这个次序排列任务。

在launcher,还有一种触发任务的方法是在app界面直接点按钮。因而触发方式总计是五种,在属于klink的四种触发执行的任务称为kLink任务。

 

一、触发条件

1.1 IoT事件

IoT事件是由IoT驱动上报的事件。Iot是“Internet of Things”缩写,指物联网。它们可认为就是些传感器类智能家居产生的事件,像门铃按下,一氧化碳传感器报警。

 

1.2 语音命令

来人通过说话,命令机器人执行哪任务。

来人说命令时,得尽可能提供“自然”的表达方式,这就涉及到语义分析。语义分析是个大课题,launcher只是用了简单的词语匹配。由于方法局限性,会使得命令受限于较多格式。举个例子,要问是否有卖打包袋,如果把“有卖”这个词做为商品名称这个变量必须出现的后缀,那命令可以是“打包袋有卖吗”,至于“有卖打包袋吗”就认不出了。

launcher提供了“触发”窗口,用于编写你需要的语音命令。

 

1.3 变量

launcher内有数个环境变量,它们在启动后就一直有效,期间小程序可读写它们。像env_hour24_time_表示这一天已过了秒数,env_temperature_表示温度。当某一刻改了温度,像超过35度,那么就可由“env_temperature_>=35”这个判断做为触发条件。

对变量任务,两次执行间隔至少5秒(var_mask_threshold)。这么做有两个原因,1)用户不小心,写了个会导致不断触发的触发条件,有5秒后,至少让有机会改正条件。2)满足触发条件、但不满足执行时,让写日志间隔至少增加到5秒。

虽然满足了触发条件,但不满足可执行条件时,像没安装底盘驱动,变量任务会把错误写向日志。5秒后,如果还是满足触发条件,会再执行,要是还是不满足可执行条件,那还是会把错误写向日志。这就造成要是用户不处理那个不可执行原因,日志每隔5秒就会加一条。但其它任务,包括定时,要不是不满足可执行条件,只会向错误日志写一条。

没有任务在运行,才会执行变量触发的任务,即变量触发不会抢占当前任务。

 

1.3 定时

几点几分几秒,让机器人去执行哪任务。

和变量触发一样,没有任务在运行,才会执行定时触发的任务。不一样的,定时有过期时间。到点了,机器人却在一直执行哪任务,为避免错过,会给适当逾期时长(overdue_threshold),目前设置是5分钟。但过了5分钟,这任务今天就不再触发了。

 

二、执行任务

任务是由开发者自编程,为完成某一场景目标,而形成的一系列操作的集合。

任务分cpp任务和单任务。cpp任务也称为复合任务,往往由数个单任务组成。举个巡检任务例子,先是去沙发抓拍,然后去门口开灯,最后去窗台开窗帘。巡检是个cpp任务,内中抓拍、开灯、开窗帘,则是单任务。在实现方式上,单任务一定得用小程序,cpp任务则可用有两种。

 

2.1 cpp任务编写方式

有两种编写方式,一是界面生成,二是小程序生成。

  • 界面生成。launcher提供了任务生成界面,虽然是界面编写,但也能生成逻辑复杂任务。这种方法让普通用户任何时候都可做到定制。像访客来访,今天会到快递和昨天不一样,在原任务改下单号就行。
  • 小程序生成。用小程序,就用了上了C++,可实现逻辑很复杂任务。但是,可以把计算复杂操作编成block单任务,然后由cpp任务去调用。

考虑到灵活性、后续维护等,能用界面的就要用界面。cpp任务中“cpp”语义是c++语言,这种任务较复杂,用小程序的话,只能用C++生成。即使是界面编写,界面是生成一个*.cfg文件。触发后,这文件会交叫一个叫tcfg_cpp_api的C++类去解析,并执行。

 

2.2 单任务

编写cpp任务时,往往需要调用其它小程序实现的单任务。像上面的抓拍,开灯、开窗帘,有6种类型单任务。

  • 蓝牙任务(task_ble)。执行期间要使用蓝牙,可用这种任务控制智能家,像空调、智能灯。编写语言建议用Lua。
  • 相机任务(task_camera)。执行期间要使用相机。这种任务往往会使用个深度识别模型(DDN),然后得出个结果,像外面是不是下雨,商品有没有掉出货架。编写语言建议用C++.
  • 机器臂任务(task_movie)。执行期间要使用机械臂,同时联贯使用深度相机。编写语言建议用C++。
  • 阻塞式任务(task_block)。可认为就是个函数块计算,要等到这任务结束了,主进程才继续后绪操作。举个例子,按下餐桌铃,执行问询上菜进度任务,当从云端得到答案了,任务就结束,主进程才继续后面代码。编写语言建议用C++.
  • 充电任务(task_charge)。任务的目标是要让机器人对准充电桩。要充电了,机器人会先自主导航到“充电”位置,然后运行这里的充电任务。编写语言建议用C++.

单任务只能由小程序实现。阻塞式外,其它四种都是异步任务,即任务开始执行后,不能确定它啥时结束,但它结束后,会向系统发一个消息。

 

三、优先级

优先级有9档,值越大,优先级越高。对IoT和语音类型,默认优先级6,用户后续可自修改。对变量和定时,优先级固定3。

任务间会发生抢占,不仅优先级高的会抢占优先级低的,同优先级的也会。但是,变量和定时只能在没有任务运行时,才会执行,因而没有去抢占判断,但它们可能被更高优先级的抢掉。

对IoT、变量,可能需要设个比定时还低的优先级。有个放门口的红外探测器,探测到有人,就播报迎宾词。对应那条“人体红外探测器”。把探测器优先级设为2,这比定时任务还低,是考虑到门口可能经常有人走动,避免它抢占掉“巡检、巡逻”任务。

cpp任务有个“可恢复”字段。对可恢复任务,执行过程中,如果出现要执行其它任务而结束本任务,在其它任务执行完后,会在断点处开始继续执行本任务。一般用在需要较长时间的任务,像巡检。

cpp任务中有个“同任务同优先级时不可抢占”字段。默认情况下,同优先级时可抢占。这里不可抢占指的是如果要执行的是同优先级、并且同是此任务时,那不能抢占。一般用在会有多个触发源、且先来先服务完的任务。像餐厅,多个餐桌铃触发的问询上菜进度任务。

新任务一旦不能调度去执行,那它就会被丢弃,之后也不再会被执行。

 

四、变量

对“打包袋有卖吗”这个语音命令,“打包袋”这个词是可变的,还可能牙膏、充电线,等等。这个字符串类型的词语就是个变量。

变量用变量名唯一识别。变量名由小程序Bundle ID和短变量名两部分组成,中间用“__”连接。示例:aplt.launcher.fake__position、aplt.leagor.basic__goods。变量名中字符必须纯英文。

变量如何在这机制中发挥作用?——除环境变量用于做触发方式外,另外主要用途是做为单任务的输入参数或输出参数。对“问询商品”任务,商品名称这变量就可作为它的输入参数。对识别外面是否下雨任务,则可用一个布尔类型的输出变量表示执行结果。

全部评论: 0

    写评论: