讲在前面
以下的TS中para_template变量是一个字典类型,我们需要获取字典中的值。该值也是个字典类型,我们要获取该字典中的值,这里统一使用的方法是self.src(self.该字典的键)。
本例下方使用的变量
有空库位(等价于该库位上没有托盘)
self.src # 起点
self.dst # 终点
self.unload_area/self.upload_area # 卸载区域
self.load_area # 装载区域
self.pallet_type # 托盘类型
while循环
除了p2p没有使用while循环,其他都有异常判断,等待下次获取正确的托盘或库位,故都使用了while循环,while循环使用continue结束本次循环,break结束循环。
四种TS的程序流程图
omi相关
只有调用写入日志的omi没有使用await;该omi是self.logger.info()
其余omi是
作用 | omi名称 | 传入参数 | 返回值 |
---|---|---|---|
获取取卸货的opt | get_location_opt | location_name/location_id | (fetch_opt,put_opt) |
下发取卸货任务 | goto_location_act | destination/destination_id,put_opt,FollowTask(后置任务,可选flase/true),agv_type,AGV(指定AGV去做任务,一般为None),PreTask(前置任务id,无可写None) | task_id |
p2p(点到点)
用到的OMI接口
# 获取目标名的opt
get_location_opt(传入目标名/目标id)==>返回元组(fetch_opt,put_opt)
# 根据传入的是fetch_opt还是put_opt确定是取卸货任务
goto_location_act(传入目标名/目标id,put_opt,FollowTask(后置任务,可选flase/true),agv_type,AGV(指定AGV
去做任务,一般为None),PreTask(前置任务id,无可写None))==>返回task_id(int)
# 更新自定义订单状态
update_order_status()
编写代码出现的报错坑
agv_type写成了self.agv_type
get_location_opt写成了get_loaction_opt
goto_location_act写成了get_location_act
实现的逻辑
获取取货opt
src_fetch_opt,src_put_opt =await self.get_location_opt(self.src)
下发取货任务
task_id = await self.get_location_act(self.src,src_fetch_opt,True,agv_type,None,None)
更新订单状态
await self.update_order_status('src_finish')
获取卸货opt
dst_fetch_opt,dst_put_opt = await self.get_loaction_opt(self.dst)
下发卸货任务
task_id = await self.get_location_act(self.dst,dst_put_opt,False,agv_type,None,task_id)
完整代码
src_fetch_opt,src_put_opt =await self.get_location_opt(self.src)
task_id = await self.goto_location_act(self.src,src_fetch_opt,True,agv_type,None,None)
# 更新状态
await self.update_order_status('src_finish')
# 卸货
dst_fetch_opt,dst_put_opt = await self.get_location_opt(self.dst)
task_id = await self.goto_location_act(self.dst,dst_put_opt,False,agv_type,None,task_id)
await self.update_order_status('dst_finish')
p2a(点到区域)
用到的OMI接口
获取目标位置的当前托盘name和托盘类型name:get_location_pallet_and_type(目标位置名/目标ID)==>[(current_pallet_name,current_pallet_type),]
设置目标托盘的类型:set_pallet_type(pallet_name,pallet_type)==> 无返回值
添加托盘:add_pallet(pallet_name,pallet_type) ==>返回个数字,小于0则为添加失败
添加托盘批次:set_pallet_batch_no(pallet_name,str(time.time()).replace(".", "0"))==>无返回值
设置目标托盘的位置(添加托盘到库位):set_pallet_location(pallet_name,目标位置名/目标ID)==>成功返回0,不成功返回小于0
查询库位是否有当前托盘类型的托盘位置并锁定:get_put_location_by_rule([self.unload_area],self.pallet_type)
更新更新自定义订单状态:self.update_order_status
更新日志使用: self.logger.info
实现的逻辑
先进行异常情况判断,在进行正常的取卸货
1.判断起点是否有空托盘,无则新增,将托盘加到当前卸货库位
查询目标位置是否有托盘,返回元组类型的托盘信息
current_pallet_info = await self.get_location_pallet_and_type(self.src)
先判断托盘信息有是有效的,再设定托盘类型
if current_pallet_info != (None,None):
# 从托盘信息中提取出托盘名,托盘类型
current_pallet_name = current_pallet_info[0][0]
current_pallet_type = current_pallet_info[0][1]
# 在判断托盘类型是否相同(托盘类型这里可人为的传入),
if current_pallet_type != self.pallet_type:
# 设置托盘类型为我们人为给定的托盘
await self.set_pallet_type(current_pallet_name,self.pallet_type)
再判断托盘类型是无效的,创建托盘
self.logger.info('current_pallet_info:{} is error,aleady create pallet_name'.format(current_pallet_info))
pallet_name = time.strftime('%Y%m%d%H%M%S',time.localtime())
# 添加托盘接口,返回个数字,小于0则创建托盘失败
ret = await self.add_pallet(pallet_name,self.pallet_type)
若创建托盘失败,则更新订单,写入日志
if ret < 0:
# 更新订单信息
await self.update_order_status('pallet_name:{} add error '.format(pallet_name))
# 更新日志使用self.logger.info
self.logger.info('current_pallet_name:{} add pallet error!'.format(current_pallet_name))
# 本次循环无托盘信息,跳过(有可能库位会锁)
await self.ts_delay(5)
若创建托盘成功,设置托盘批次
# 添加创建成功的日志
self.logger.info('pallet_name:{} create success'.format(current_pallet_name))
# 添加托盘批次
await self.set_pallet_batch_no(pallet_name,str(time.time()).replace(".", "0"))
设置托盘到当前卸货库位,并判断是否设置成功
ret = await self.set_pallet_location(pallet_name,self.unload_area)
if ret < 0:
# 更新订单信息
await self.update_order_status('pallet_name:{} already add {}'.format(pallet_name,self.unload_area))
# 更新日志使用self.logger.info
self.logger.info('pallet_name:{} already add {}'.format(pallet_name,self.unload_area))
# 本次循环无托盘信息,跳过(有可能库位会锁)
await self.ts_delay(5)
2.判断是否有空库位,进行正常的取卸货
查询目标位置是否有当前托盘类型的空托盘位置
dst_empty_location = await self.get_put_location_by_rule([self.unload_area],self.pallet_type)
判断:有则进行起点取货,终点卸货
if dst_empty_location != (None,None):
await self.update_order_status('active')
'''
AGV执行任务的主要就是这四句
'''
# 起点取货
task_id = await self.goto_location_load(self.src,True,agv_type,None,None)
# 更新状态
await self.update_order_status('source finish')
# 终点卸货
task_id = await self.goto_location_unload(dst_empty_location[0],True,agv_type,None,task_id)
# 更新状态
await self.update_order_status('source finish')
没有的话:循环等待下次(库位有可能会锁)
await self.ts_delay(5)
continue
a2a(区域到区域)
本文中区域等同于库位
OMI接口
查询取货有无托盘,有无空库位,并锁定(空库位代表该库位有托盘):get_fetch_locations_by_rule([self.load_area], self.pallet_type,["leaf_reverse"]# 默认按location ID逆序排列)==>src_full_location对象实际是(location_name, pallet_name)元组
取货(需要库管信息):goto_location_load(src_full_location[0], True, agv_type)==> int task_id 失败则结束订单
卸货(需要库管信息):goto_location_unload(dst_empty_location[0],True,agv_type,None,None(有前置任务则填task_id))
释放锁定的库位:release_location(src_full_location[0])==> 成功则返回0解除锁定;失败则返回1解除锁定失败(location不存在)
get_parent_by_type(dst_empty_location[0], parent_location_type(父节点的类型,手动指定))==>失败返回None,成功返回parent_location
实现的逻辑
查询有无托盘,有无空库位,并锁定
src_full_pallet = await self.get_fetch_locations_by_rule([self.load_area],self.pallet_type)
dst_empty_location = await self.get_fetch_locations_by_rule([self.upload_area],self.pallet_type)
有托盘,有空库位
if src_full_pallet != (None,None) and dst_empty_location != (None,None):
# 起点取货
task_id = await self.goto_location_load(src_full_pallet[0],True,agv_type)
await self.update_order_status('load finish')
# 终点卸货
task_id = await self.goto_location_load(dst_empty_location[0],False,agv_type,None,task_id)
await self.update_order_status('upload finish')
有托盘,无空库位(无空读起来很扭)
elif src_full_pallet != (None,None) and dst_empty_location == (None,None):
# 注意:这里获取到了dst_empty_location虽然为None,但对于库位来说它的父对象巷道也锁到了
ret = await self.release_location(src_full_pallet[0])
parent_location = await self.get_parent_by_type(src_full_pallet[0],self.parent_location_type)
ret = await self.release_location(src_full_pallet[0],parent_location)
await self.update_order_status('No empty location ')
await self.ts_delay(5)
无托盘,有空库位
elif src_full_pallet == (None,None) and dst_empty_location != (None,None):
ret = await self.release_location(src_full_pallet[0])
parent_location = await self.get_parent_by_type(dst_empty_location[0],self.parent_location_type)
ret = await self.release_location(src_full_pallet[0],parent_location)
await self.update_order_status('No empty pallet')
await self.ts_delay(5)
a2p(区域到点)
OMI接口
查询区域是否有托盘/空库位,并锁定:get_fetch_locations_by_rule([self.load_area], self.pallet_type,["leaf_reverse"]# 默认按location ID逆序排列)==>src_full_location对象实际是(location_name, pallet_name)元组
取货(带库管信息):goto_location_load(src_full_location[0], True, agv_type)==> int task_id 失败则结束订单
卸货(带库管信息):goto_location_unload(dst,follow_task,agv_type, None, task_id)==> task_id
具体实现的逻辑
查询区域是否有托盘,并锁定
src_full_pallet = await self.get_fetch_locations_by_rule([self.load_area],self.pallet_type)
有则进行取货卸货
if src_full_pallet != (None,None):
task_id = await self.goto_location_load(src_full_pallet[0],True,agv_type)
await self.update_order_status('source_finish')
task_id = await self.goto_location_unload(self.dst,False,agv_type,None,task_id)
await self.update_order_status('source_finish')
没有则循环在次等待
await self.update_order_status('no fit pallet')
await self.ts_delay(5)