def is_enable_into_car(self): """ 是否允许进车 """ # 获取模型 model = self.get_model() model = model_selection(model, axis=1, gt=W2) # 3号堆模型,卸料区 model = model_selection(model, axis=2, ge=H3) # 卸料区高度大于H3(卸料区限高) if model.shape[0] == 0: # 无高于限高的料堆 # 允许进车 return True else: # 不允许进车 return False
def generate_data_2_db(self): """ 如果表为空,则生成数据 :return: list类型的数据 """ # 获取模型 model = self.get_model() # 记录当前时间 date_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # 读取配置 config_stack_boundary = self.get_stack_boundaries() # 插入数据 generate_data = [] for boundary in config_stack_boundary: # 筛选出模型 model0 = model_selection(model, axis=1, ge=boundary[0], lt=boundary[1]) # 空的条件是,该区域最高点小于H5 is_empty = int(np.max(model0[:, 2]) < H5) # 插入新纪录 sql = "insert into test(id, dust_warehouse_id, boundary_min, boundary_max, stack_time, is_empty) values(" \ "%s, %s, %s,%s, %s,%s) " values = (str(uuid.uuid1()), self.dust_warehouse_id, boundary[0], boundary[1], date_time, is_empty) generate_data.append(list(values)) self.db_client.execute(sql, values) return generate_data
def cal_put_coordinates(boundary_center_coordinates, put_coordinates_array): """ 计算放料点,原则是先放中心区,从远至近 :param boundary_center_coordinates: 该区域离上料口最近的边界中心点位置 :param put_coordinates_array: 可放料点集合 :return: 放料点坐标 """ # 在中心方向上的可放料点 can_put_coordinate = model_selection(put_coordinates_array, axis=0, eq=boundary_center_coordinates[0]) if can_put_coordinate.shape[0] != 0: # 在中心方向上有可放料点 # 取距上料口最近的点 put_coordinates = can_put_coordinate[np.argmin(can_put_coordinate[:, 1])] else: # 在中心方向上无可放料点 # 取距中心方向最近点放料 put_coordinates = find_nearest_point(boundary_center_coordinates, put_coordinates_array) return put_coordinates
def listen(self): """ 开始监听 """ status_reader = ModbusClient(port=status_port) # 建立状态池连接 # 放置次数 put_times = 0 # 无需倒料 completed = True # 空置区域 empty_area = None while not self.stop: # 当没有停止指令时 # 开始监听除灰仓 # 通过地址获取卸料口状态 status_code = status_reader.get( self.dust_warehouse_address) # 读取所有的设备状态 status = dust_warehouse_status_dict[status_code] # 任务id task_id = str(uuid.uuid1()) # 开始检测 if completed and status == "allow": # 当前监听到需要倒料 # 当检测到配置文件更改后,将表清零 data = self.check_config() # tuple类型 if not data: # 如果表为空,则根据模型插入数据至数据库中,并记录插入的数据 data = self.generate_data_2_db() # list类型 # 数据转为array data = np.array(data)[:, 2:] # 寻找一个最近的空置区域 if empty_area is None: # 判断条件:状态为空置 empty_area = data[data[:, 3] == empty][0:2][0] elif not completed and status == "allow": # 当前正在倒料中 # 从卸料区的固定抓料点抓料 get_coordinates = dust_warehouse_get_coordinates_dict[ self.dust_warehouse_id] # 2维 # 在空置区域里,横向X方向从最远至近依次放料 x = self.x_range[0] + divmod(put_times, dust_stack_times)[0] * radius if x >= self.x_range[1]: # 放完一层后,放中间 x = np.average(self.x_range) # y方向为区域的中心线 y = np.average(empty_area) put_coordinates = [x, y] # 插入任务单 # 抓料点和取料点之间的最高高度,从卸料区到缓冲区 h = dust_stack_times * increase_height + safety_height # 放入任务 p = task_priority.index('清理除尘仓') self.task_list[p][task_id] = [ get_coordinates, put_coordinates, h, active, int(time.time()) ] # 开始判断倒料任务是否完成 while True: try: p = task_priority.index('已完成') self.logger.info('任务已完成' + str(self.task_list[p][task_id])) except KeyError: # 任务未完成 time.sleep(1) continue else: # 任务已完成 # 删除已完成任务 self.task_list[p].pop(task_id) # 结束循环 break # 放置次数 +1 put_times += 1 elif not completed and status == "disallow": # 当前不允许倒料,但是任务未完成 # 获取卸料区模型 model = self.get_model() # 判断卸料区有无H4以上(可抓)的料堆 can_get_coordinates = model_selection(model, axis=1, le=W3 - radius) can_get_coordinates = model_selection(can_get_coordinates, axis=2, ge=H4) if can_get_coordinates.shape[0] == 0: # 当没有可抓点时 # 获取该区域的模型 empty_area_model = model_selection(model, axis=1, ge=empty_area[0], lt=empty_area[1]) if np.max(empty_area_model[:, 2]) >= H5: # 料场非空 # 堆放完毕,更新区域的堆放时间和非空 sql = 'UPDATE dust_warehouse SET stack_time = %s, is_empty = 0 where boundary_min = %s and ' \ 'boundary_max = %s ' values = (datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S"), empty_area[0], empty_area[1]) self.db_client.execute(sql, values) # 放置次数清零 put_times = 0 # 空置区域 empty_area = None # 此次倒料完成,跳过以下步骤,进入下个循环,继续监听 # 状态更新为无需倒料 completed = True continue else: # 当有可抓点时 # 每次抓完一个最高点后,预测模型,然后再抓下一个最高点,直至预测模型中没有可抓点 while np.max(can_get_coordinates[:, 2]) >= H4: # 先抓最高点 get_coordinates = can_get_coordinates[np.argmax( can_get_coordinates[:, 2])][0:2] # 在空置区域里,横向X方向从远至近依次放料 x = self.x_range[0] + divmod( put_times, dust_stack_times)[0] * radius if x >= self.x_range[1]: # 放完一层后,放中间 x = np.average(self.x_range) # y方向为区域的中心线 y = np.average(empty_area) put_coordinates = [x, y] # 插入任务单 # 抓料点和取料点之间的最高高度,从卸料区到缓冲区 h = dust_stack_times * increase_height + safety_height # 放入任务 p = task_priority.index('清理除尘仓') self.task_list[p][task_id] = [ get_coordinates, put_coordinates, h, active, int(time.time()) ] # 等待该倒料任务完成 while True: try: p = task_priority.index('已完成') self.logger.info( '任务已完成' + str(self.task_list[p][task_id])) except KeyError: # 任务未完成 time.sleep(1) continue else: # 任务已完成 # 删除已完成任务 self.task_list[p].pop(task_id) # 结束循环 break # 放置次数 +1 put_times += 1 # 预测模型 can_get_coordinates = predict_model( get_coordinates, put_coordinates, can_get_coordinates) # 任务未完成,还需要倒料 completed = False
def listen(self): """ 开始监听每个上料口 """ status_reader = ModbusClient(port=status_port) # 建立状态池连接 feed_type = None # 初始化上料类型为空 task_id_record = [] # 已安排的任务记录表,用于判断这些任务是否完成 no_empty_area = None while not self.stop: # 当没有停止指令时 # 先记录原先的上料类型 feed_type_old = feed_type # 开始判断上料口状态 # 通过地址获取状态 status_code = status_reader.get( self.feed_status_address) # 读取所有的设备状态 status = feed_status_dict[status_code] # 获取当前的上料类型 ,先记录原来的上料类型 feed_type_code = status_reader.get( self.feed_type_address) # 读取所有的设备状态 feed_type = feed_type_value_dict[feed_type_code] # 通过上料类型获取对应料场的范围 x_range, y_range = ([], []) for key, value in sub_warehouse_type_dict.items(): if value == feed_type: x_range.append(sub_warehouse_range_dict[key][0]) y_range.append(sub_warehouse_range_dict[key][1]) x_range = [x_range[0][0], x_range[-1][-1]] y_range = [y_range[0][0], y_range[-1][-1]] # 把任务id记录,用于后面判断是否完成 task_id = str(uuid.uuid1()) # 任务id task_id_record.append(task_id) # 开始检测上料状态 if status == "plug" or (feed_type_old is not None and feed_type_old != feed_type): # 当检测到堵料或者上料类型切换 # 检查有没有紧急和一般上料任务 priority = [ task_priority.index('紧急上料'), task_priority.index('上料') ] is_exists_task, indexes = self.is_exists_task(priority, x_range, y_range, task_type='feed') if is_exists_task: # 任务已完成 for index in indexes: # 修改任务优先级为已完成 self.task_list = change_task_priority( self.task_list, index[0], index[1], task_priority.index('已完成')) elif status == "emergency feed": # 当检测到紧急上料 # 检查有没有紧急任务 priority = [task_priority.index('紧急上料')] is_exists_emergency_feed_task = self.is_exists_task( priority, x_range, y_range, task_type='feed')[0] if not is_exists_emergency_feed_task: # 此时没有紧急上料任务 priority = [task_priority.index('上料')] is_exists_feed_task, indexes = self.is_exists_task( priority, x_range, y_range, task_type='feed') if is_exists_feed_task: # 若存在一般上料任务,优先级改为紧急 for index in indexes: # 修改任务优先级为紧急 self.task_list = change_task_priority( self.task_list, index[0], index[1], task_priority.index('紧急上料')) else: # 若不存在一般上料任务,插入一条 # 先获取上料口关联的料场模型 model = self.get_model(feed_type, x_range, y_range) # 筛选出主堆区的料堆,高度大于H4,要避开H1/2预留空间 model = model_selection(model, axis=1, lt=W1 - H1 / 2) model = model_selection(model, axis=2, gt=H4) # 计算取料点 get_coordinates = find_nearest_point( self.feed_port_coordinate, model[:, 0:2]) # 放入字典 p = task_priority.index('紧急上料') self.task_list[p][task_id] = [ get_coordinates, self.feed_port_coordinate, feed_rise_height, active, int(time.time()) ] elif status == "feed": # 当检测到上料 # 检查有没有安排上料任务 priority = [task_priority.index('上料')] is_exists_feed_task = self.is_exists_task(priority, x_range, y_range, task_type='feed')[0] if not is_exists_feed_task: # 若未安排一般上料任务 # 检查该上料口有无关联的除尘仓 dust_warehouse_id = feed_port_dust_warehouse_dict[ self.feed_port_id] if dust_warehouse_id != -1: # 关联除尘灰仓 # 放料点为上料口 put_coordinates = self.feed_port_coordinate # 2维 # 任务优先级为普通上料 p = task_priority.index('上料') # 获取区域模型 # 除尘灰的范围 sub_warehouse_no = dust_warehouse_sub_warehouse_dict[ dust_warehouse_id] dust_warehouse_range = sub_warehouse_range_dict[ sub_warehouse_no] # 已知可抓料区? if not no_empty_area: # 若此时不知道no_empty_area,求no_empty_area,可能出现的情况:1,首次;2,之前的no_empty_area复位 # 获取除尘区中24小时以上且不为空的区域 sql = "SELECT * FROM dust_warehouse WHERE TO_DAYS(NOW()) - TO_DAYS(stack_time) >= 1 and is_empty = {0} and dust_warehouse_id = {1}".format( not_empty, dust_warehouse_id) data = self.db_client.query(sql) # 满足条件的数据 if data: # 存在满足条件的数据 # 获取不为空区域 no_empty_area = np.array(data)[0][2:4] # 因为是首次对该区域抓料,先抓距上料口最远的点 get_coordinates = [ dust_warehouse_range[0][0], np.average(no_empty_area) ] # 插入任务单 self.task_list[p][task_id] = [ get_coordinates, put_coordinates, feed_rise_height, active, int(time.time()) ] # 下个循环 continue else: # 若此时知道no_empty_area # 判断料场是否为空 # 获取该非空置区域的模型 no_empty_area_model = self.get_model( 'chuchen', dust_warehouse_range[0], no_empty_area) if np.max(no_empty_area_model[:, 2]) <= H5: # 区域置空 # 上料完毕,更新为空置 sql = 'UPDATE dust_warehouse SET is_empty = 1 where boundary_min = %s and ' \ 'boundary_max = %s ' values = (no_empty_area[0], no_empty_area[1]) self.db_client.execute(sql, values) # 可抓取区复位 no_empty_area = None else: # 区域非空 # 抓料点集合 no_empty_area_get_coordinates = model_selection( no_empty_area_model, axis=2, gt=H5) # 先抓最远点 ,x坐标最小 get_coordinates = no_empty_area_get_coordinates[ np.argmin( no_empty_area_get_coordinates[:, 0])][:, 0:2] # 插入任务单 self.task_list[p][task_id] = [ get_coordinates, put_coordinates, feed_rise_height, active, int(time.time()) ] # 下个循环 continue # 若上述条件均不满足 # 开始寻找有无倒料的任务,准备合并 priority = [ task_priority.index('紧急清理卸料区'), task_priority.index('清理卸料区'), task_priority.index('清理缓冲区') ] # 可以被合并的倒料任务优先级 # 寻找有无倒料任务 is_exists_upload_task, indexes = self.is_exists_task( priority, x_range, y_range, task_type='upload') if is_exists_upload_task: # 若存在倒料任务 # 将第一条倒料任务改为上料 index = indexes[0] # 修改任务优先级为普通上料 self.task_list = change_task_priority( self.task_list, index[0], index[1], task_priority.index('上料')) # 修改目的地为上料口 self.task_list[index[0]][ index[1]][1] = self.feed_port_coordinate # 修改高度为上料高度 self.task_list[index[0]][ index[1]][2] = feed_rise_height else: # 若不存在倒料任务,插入一条上料 # 先获取上料口关联的料场模型 model = self.get_model(feed_type, x_range, y_range) # 筛选出主堆区的料堆,高度大于H4,要避开H1/2预留空间 model = model_selection(model, axis=1, lt=W1 - H1 / 2) model = model_selection(model, axis=2, gt=H4) # 计算取料点 get_coordinates = find_nearest_point( self.feed_port_coordinate, model[:, 0:2]) # 放入字典 p = task_priority.index('上料') self.task_list[p][task_id] = [ get_coordinates, self.feed_port_coordinate, feed_rise_height, active, int(time.time()) ] else: # 此时为不上料 # 删除已完成的该模块产生的上料任务 for taskId in task_id_record: try: p = task_priority.index('已完成') self.logger.info('任务已完成' + str(self.task_list[p][taskId])) self.task_list[p].pop(taskId) except KeyError: continue else: task_id_record.remove(taskId)
def generate(self): """ 开始产生任务 """ while not self.stop: # 当没有停止指令时 # 开始规划任务 perform_completed = False # 规划的task_num任务执行完成数量 generate_times = 0 # 规划的次数 task_id_record = [] # 已安排的任务记录表,用于判断这些任务是否完成 # 更新模型 self.update_model() # 开始规划任务小于每批次产生的任务数量,由于任务规划中模型是靠预测出来的,所以此任务数量不宜设置过大 while generate_times < task_num: # 规划的次数 +1 generate_times += 1 # 模型划分 model3 = model_selection(self.model, axis=1, gt=W2) # 3号堆模型,卸料区 # 2号堆模型,缓冲区,前预留H2/2空间,防止坡度过大 model2 = model_selection(self.model, axis=1, ge=W1 - radius, le=W2 - H2 / 2) model1 = model_selection(self.model, axis=1, le=W1 - H1 / 2) # 1号堆模型,主堆区,预留H1/2空间,防止坡度过大 # 需倒料点集 unload_stock_emergency_clean_points = model_selection( model3, axis=2, ge=H3) # 紧急清理卸料区点集 unload_stock_clean_points = model_selection(model3, axis=2, ge=H4, lt=H3) # 清理卸料区点集 cache_stock_clean_points = model_selection(model2, axis=2, ge=H2) # 清理缓冲区点集 # 可堆放点集 # 主堆区分三层 if np.min(model1[:, 2]) < H1 / 3: main_stock_can_stacked_points = model_selection( model1, axis=2, lt=H1 / 3)[:, 0:2] # 主堆区可堆放点(二维) elif 2 * H1 / 3 >= np.min(model1[:, 2]) >= H1 / 3: # 主堆区可堆放点(二维) main_stock_can_stacked_points = model_selection(model1, axis=2, lt=2 * H1 / 3)[:, 0:2] else: main_stock_can_stacked_points = model_selection( model1, axis=2, lt=H1)[:, 0:2] # 主堆区可堆放点(二维) # 缓冲区分二层 if np.min(model2[:, 2]) < H2 / 2: cache_stock_can_stacked_points = model_selection( model2, axis=2, lt=H2 / 2)[:, 0:2] # 缓冲区可堆放点(二维) else: cache_stock_can_stacked_points = model_selection( model2, axis=2, lt=H2)[:, 0:2] # 缓冲区可堆放点(二维) # 提升高度 h1 = np.max( model1[:, 2]) + safety_height # 送往1号堆的提升高度,1号堆最高+抓斗安全距离 h2 = np.max( model2[:, 2]) + safety_height # 送往2号堆的提升高度,2号堆最高+抓斗安全距离 # 开始产生任务 get_coordinates = np.array([]) put_coordinates = np.array([]) task_id = str(uuid.uuid1()) # 把任务id记录,用于后面判断是否完成 task_id_record.append(task_id) # 有紧急清理卸料区点 if unload_stock_emergency_clean_points.shape[0] >= 0: # 先抓其中的最高点 get_coordinates = unload_stock_emergency_clean_points[ np.argmax(unload_stock_emergency_clean_points[:, 2])] # 在缓冲区计算放料点 # 缓冲区边界中心点 boundary_center_coordinates = [ np.average(sub_warehouse_range_dict[ self.sub_warehouse_no][0]), W1 ] put_coordinates = cal_put_coordinates( boundary_center_coordinates, cache_stock_can_stacked_points) # 抓料点和取料点之间的最高高度,从卸料区到缓冲区 h = max(h2, get_coordinates[2] + safety_height) # 插入任务 p = task_priority.index('紧急清理卸料区') self.task_list[p][task_id] = [ get_coordinates[0:2], put_coordinates, h, active, int(time.time()) ] # 需要倒料,任务规划进行中 self.generate_completed = False # 有清理卸料区点 elif unload_stock_clean_points.shape[0] >= 0: # 先抓其中的最高点 get_coordinates = unload_stock_clean_points[np.argmax( unload_stock_clean_points[:, 2])] # 在主堆区计算放料点 boundary_center_coordinates = [ np.average(sub_warehouse_range_dict[ self.sub_warehouse_no][0]), sub_warehouse_range_dict[self.sub_warehouse_no][1][0] ] put_coordinates = cal_put_coordinates( boundary_center_coordinates, main_stock_can_stacked_points) # 抓料点和取料点之间的最高高度,从卸料区到主堆区 h = max(h1, h2, get_coordinates[2] + safety_height) # 放入字典 p = task_priority.index('清理卸料区') self.task_list[p][task_id] = [ get_coordinates[0:2], put_coordinates, h, active, int(time.time()) ] # 需要倒料,任务规划进行中 self.generate_completed = False # 有清理缓冲区点 elif cache_stock_clean_points.shape[0] >= 0: # 先抓其中的最高点 get_coordinates = cache_stock_clean_points[np.argmax( cache_stock_clean_points[:, 2])] # 在主堆区计算放料点 boundary_center_coordinates = [ np.average(sub_warehouse_range_dict[ self.sub_warehouse_no][0]), sub_warehouse_range_dict[self.sub_warehouse_no][1][0] ] put_coordinates = cal_put_coordinates( boundary_center_coordinates, main_stock_can_stacked_points) # 抓料点和取料点之间的最高高度,从缓冲区到主堆区 h = max(h1, get_coordinates[2] + safety_height) # 放入字典 p = task_priority.index('清理缓冲区') self.task_list[p][task_id] = [ get_coordinates[0:2], put_coordinates, h, active, int(time.time()) ] # 需要倒料,任务规划进行中 self.generate_completed = False # 无需倒料 else: self.generate_completed = True # 任务规划完毕 # 任务规划后的模型预测 self.model = predict_model(get_coordinates, put_coordinates, self.model) # 判断任务是否规划完毕 if not self.generate_completed: continue else: break # 开始判断任务是否完成 while not perform_completed: for taskId in task_id_record: try: p = task_priority.index('已完成') self.logger.info("子料仓" + str(self.sub_warehouse_no) + '任务已完成' + str(self.task_list[p][taskId])) except KeyError: perform_completed = False break else: perform_completed = True time.sleep(1) # 删除已完成任务 for taskId in task_id_record: p = task_priority.index('已完成') self.task_list[p].pop(taskId)