<代码分享> 一种无人机配合卡车配送的车辆路径规划模型

article/2025/8/8 9:58:06

本文为本人博客《一种无人机配合卡车配送的车辆路径规划模型》的代码分享。
由于近期此文的关注者较多,代码分享较为不便,因此决定专门写一篇博客以提供源码。
感谢各位博友关注,本人能力有限,如有错误,还请及时批评指正!
原文链接:https://blog.csdn.net/Zhang_0702_China/article/details/115215219


代码文件结构


代码的文件结构如下:
  • config: 参数、输入数据(随机生成)
  • docs: 模型文档、参考文献(见前面原文链接
  • log: 运行日志
  • model: 模型核心模块
  • output: 输出文件,即可视化结果
  • utils: 工具模块,本文代码只涉及日志打印工具
  • visual: 可视化模块
  • main_tsp.py: TSP 模型主程序
  • main_vrp.py: VRP 模型主程序

把后面提供的代码粘贴到对应文件即可运行。
文件结构

具体代码


参数与输入数据


TSP:

from datetime import datetime
import random
import mathfrom utils.logger import log_tsp as logdts = datetime.now()# nodes
NUM_NODE = 50
NUM_NODE_NAV = 20
LIST_NODE_UAV = list(range(NUM_NODE - NUM_NODE_NAV + 1, NUM_NODE + 1))# coordinates
random.seed(2021)
RANGE_COORDINATE = (0, 100)
LIST_COORDINATE = [(random.randint(RANGE_COORDINATE[0], RANGE_COORDINATE[1]),random.randint(RANGE_COORDINATE[0], RANGE_COORDINATE[1])) for _ in range(NUM_NODE)]# distance
ORIGIN = (round((RANGE_COORDINATE[1] - RANGE_COORDINATE[0]) / 2),round((RANGE_COORDINATE[1] - RANGE_COORDINATE[0]) / 2))
LIST_COORDINATE_ = [ORIGIN] + LIST_COORDINATE
MAT_DISTANCE = [[0.0 for _ in range(0, NUM_NODE + 1)] for _ in range(0, NUM_NODE + 1)]
range_wave = (0.8, 1.2)
for i in range(0, NUM_NODE + 1):for j in range(0, NUM_NODE + 1):distance = round(math.sqrt((LIST_COORDINATE_[i][0] - LIST_COORDINATE_[j][0]) ** 2+ (LIST_COORDINATE_[i][1] - LIST_COORDINATE_[j][1]) ** 2)* (range_wave[0] + random.random() * (range_wave[1] - range_wave[0])), 4)MAT_DISTANCE[i][j] = distance# cost
COST_UAV = 0.2dte = datetime.now()
tm = round((dte - dts).seconds + (dte - dts).microseconds / (10 ** 6), 3)
log.info(msg="random data generating time:  {} s".format(tm))

VRP:

from datetime import datetime
import random
import mathfrom utils.logger import log_vrp as logdts = datetime.now()# nodes
NUM_NODE = 50
NUM_NODE_NAV = 10
LIST_NODE_UAV = list(range(NUM_NODE - NUM_NODE_NAV + 1, NUM_NODE + 1))# coordinates
random.seed(2021)
RANGE_COORDINATE = (0, 100)
LIST_COORDINATE = [(random.randint(RANGE_COORDINATE[0], RANGE_COORDINATE[1]),random.randint(RANGE_COORDINATE[0], RANGE_COORDINATE[1])) for _ in range(NUM_NODE)]# distance
ORIGIN = (round((RANGE_COORDINATE[1] - RANGE_COORDINATE[0]) / 2),round((RANGE_COORDINATE[1] - RANGE_COORDINATE[0]) / 2))
LIST_COORDINATE_ = [ORIGIN] + LIST_COORDINATE
MAT_DISTANCE = [[0.0 for _ in range(0, NUM_NODE + 1)] for _ in range(0, NUM_NODE + 1)]
range_wave = (0.8, 1.2)
for i in range(0, NUM_NODE + 1):for j in range(0, NUM_NODE + 1):distance = round(math.sqrt((LIST_COORDINATE_[i][0] - LIST_COORDINATE_[j][0]) ** 2+ (LIST_COORDINATE_[i][1] - LIST_COORDINATE_[j][1]) ** 2)* (range_wave[0] + random.random() * (range_wave[1] - range_wave[0])), 4)MAT_DISTANCE[i][j] = distance# cost
COST_UAV = 0.1# weight, load
upper_weight_item = 20
LIST_WEIGHT = [random.randint(0, upper_weight_item) for _ in range(NUM_NODE)]
UPPER_LOAD = 100
log.info(msg="total weight:  {}".format(sum(LIST_WEIGHT)))dte = datetime.now()
tm = round((dte - dts).seconds + (dte - dts).microseconds / (10 ** 6), 3)
log.info(msg="random data generating time:  {} s".format(tm))

模型核心模块


在 TSP 模型中,通过 GG 模型的建模方式消除子回路;在 VRP 模型中,通过卡车载重约束的传递性消除子回路。
有关 TSP 模型的建模方式可见本人博客:https://blog.csdn.net/Zhang_0702_China/article/details/106983492

模型求解通过调用 Gurobi 求解器的方式实现,有关 Gurobi 求解器的 Python 调用,可见本人博客:
https://blog.csdn.net/Zhang_0702_China/article/details/115520346

TSP:

from datetime import datetime
from typing import List, Dict, Tuplefrom gurobipy import *from utils.logger import log_tsp as logdef tsp_gg(num_node: int, list_node_uav: List[int], mat_distance: List[List[int]], cost_uav: float = 0.5) \-> Tuple[List[int], Dict[int, Tuple[int, int]]]:"""TSP model, GG formulation:param num_node:  number of nodes:param list_node_uav:  nodes can be served by uav:param mat_distance:  distance matrix,  0 index for hub:param cost_uav:  cost coefficient of uav:return: list_route:  list of nodes in truck route:return: dict_uav_route:  dict of uav routes"""log.info(msg=">>> TSP model, GG formulation, start")model = Model('tsp_gg')""" variables """# if truck flow from i to jx = model.addVars([(i, j) for i in range(0, num_node + 1) for j in range(0, num_node + 1)], vtype=GRB.BINARY,name='x_')# if uav flow from i to jy = model.addVars([(i, j) for i in range(0, num_node + 1) for j in range(0, num_node + 1)], vtype=GRB.BINARY,name='y_')# if served by trucks = model.addVars([i for i in range(1, num_node + 1)], vtype=GRB.BINARY, name='s_')# sub-loop eliminationa = model.addVars([(i, j) for i in range(0, num_node + 1) for j in range(0, num_node + 1)], vtype=GRB.CONTINUOUS,name='a_')""" constraints """# cons 1: stream in / outfor i in range(0, num_node + 1):# nodes can only served by truckif i not in list_node_uav:model.addConstr(quicksum(x[j, i] for j in range(0, num_node + 1)) == 1, name='cons_1_in_x_[{}]'.format(i))model.addConstr(quicksum(x[i, j] for j in range(0, num_node + 1)) == 1, name='cons_1_out_x_[{}]'.format(i))# nodes can served by truck or uavelse:model.addConstr(quicksum(x[j, i] + y[j, i] for j in range(0, num_node + 1)) == 1,name='cons_1_in_xy_[{}]'.format(i))model.addConstr(quicksum(x[i, j] + y[i, j] for j in range(0, num_node + 1)) == 1,name='cons_1_out_xy_[{}]'.format(i))# truck or uavmodel.addConstr(quicksum(y[j, i] for j in range(0, num_node + 1))== quicksum(y[i, j] for j in range(0, num_node + 1)), name='cons_1_y[{}]'.format(i))# cons 2: self-loop eliminationmodel.addConstr(quicksum(x[i, i] for i in range(0, num_node + 1)) == 0, name='cons_2_x')model.addConstr(quicksum(y[i, i] for i in range(0, num_node + 1)) == 0, name='cons_2_y')# cons 3: get, if served by truckfor i in range(1, num_node + 1):model.addConstr(s[i] == quicksum(x[i, j] for j in range(0, num_node + 1)), name='cons_3_[{}]'.format(i))# cons 4: sub-loop eliminationfor i in range(1, num_node + 1):list_n_i = list(range(0, i)) + list(range(i + 1, num_node + 1))list_n_i_ori = list(range(1, i)) + list(range(i + 1, num_node + 1))model.addConstr(quicksum(a[i, j] for j in list_n_i) - quicksum(a[j, i] for j in list_n_i_ori) == s[i],name='cons_4_a_[{}]'.format(i))for j in range(0, num_node + 1):model.addConstr(a[i, j] <= num_node * x[i, j], name='cons_4_ax_[{},{}]'.format(i, j))# cons 5: uav orderfor j in list_node_uav:for i in range(0, num_node + 1):for k in range(0, num_node + 1):model.addConstr(y[i, j] + y[j, k] <= 2 * x[i, k] + 1, name='cons_5_[{},{},{}]'.format(i, j, k))# cons 6: only one uavfor i in range(0, num_node + 1):model.addConstr(quicksum(y[i, j] for j in range(0, num_node + 1)) <= 1, name='cons_6_out_[{}]'.format(i))model.addConstr(quicksum(y[j, i] for j in range(0, num_node + 1)) <= 1, name='cons_6_in_[{}]'.format(i))""" objective & solve """# obj: total weighted distancecost = quicksum(x[i, j] * mat_distance[i][j] + y[i, j] * mat_distance[i][j] * cost_uavfor i in range(0, num_node + 1) for j in range(0, num_node + 1))model.setObjective(cost, sense=GRB.MINIMIZE)model.setParam(GRB.Param.TimeLimit, 300)model.setParam(GRB.Param.MIPGap, 0.02)dts_solve = datetime.now()model.optimize()dte_solve = datetime.now()tm_solve = round((dte_solve - dts_solve).seconds + (dte_solve - dts_solve).microseconds / (10 ** 6), 3)log.info(msg="solving time:  {} s".format(tm_solve))""" result """x_ = model.getAttr('X', x)y_ = model.getAttr('X', y)s_ = model.getAttr('X', s)# truck routelist_route = [0]to = Nonewhile to != 0:for i in range(0, num_node + 1):if x_[list_route[-1], i] > 0.9:to = ilist_route.append(i)break# uav routeslist_node_uav_ = []dict_uav_route = {}for j in list_node_uav:if s_[j] < 0.1:list_node_uav_.append(j)fr, to = None, Nonefor i in range(0, num_node + 1):if y_[i, j] > 0.9:fr = ibreakfor k in range(0, num_node + 1):if y_[j, k] > 0.9:to = kbreaktup_fr_to = (fr, to)dict_uav_route[j] = tup_fr_tolog.info(msg="nodes can be served by uav:  {}".format(list_node_uav))log.info(msg="nodes served by uav:  {}".format(list_node_uav_))log.info(msg="<<< TSP model, GG formulation, end")return list_route, dict_uav_route

VRP:

from datetime import datetime
from typing import List, Dict, Tuplefrom gurobipy import *from utils.logger import log_vrp as logdef vrp_load(num_node: int, list_node_uav: List[int], list_weight: List[int], upper_load: int,mat_distance: List[List[int]], cost_uav: float = 0.5) \-> Tuple[List[List[int]], Dict[int, Tuple[int, int]]]:"""VRP model, load limit mode:param num_node:  number of nodes:param list_node_uav:  nodes can be served by uav:param list_weight:  weight of each node:param upper_load:  upper limit of vehicle loads:param mat_distance:  distance matrix,  0 index for hub:param cost_uav:  cost coefficient of uav:return: list_routes:  list of truck routes:return: dict_uav_route:  dict of uav routes"""log.info(msg=">>> VRP model, load limit mode, start")model = Model('vrp_load')""" variables """# if truck flow from i to jx = model.addVars([(i, j) for i in range(0, num_node + 1) for j in range(0, num_node + 1)], vtype=GRB.BINARY,name='x_')# if uav flow from i to jy = model.addVars([(i, j) for i in range(0, num_node + 1) for j in range(0, num_node + 1)], vtype=GRB.BINARY,name='y_')# if served by trucks = model.addVars([i for i in range(1, num_node + 1)], vtype=GRB.BINARY, name='s_')# load limit: arc weightz = model.addVars([(i, j) for i in range(0, num_node + 1) for j in range(0, num_node + 1)], ub=upper_load,vtype=GRB.CONTINUOUS, name='a_')""" constraints """# cons 1: stream in / out, not including originfor i in range(1, num_node + 1):# nodes can only served by truckif i not in list_node_uav:model.addConstr(quicksum(x[j, i] for j in range(0, num_node + 1)) == 1, name='cons_1_in_x_[{}]'.format(i))model.addConstr(quicksum(x[i, j] for j in range(0, num_node + 1)) == 1, name='cons_1_out_x_[{}]'.format(i))# nodes can served by truck or uavelse:model.addConstr(quicksum(x[j, i] + y[j, i] for j in range(0, num_node + 1)) == 1,name='cons_1_in_xy_[{}]'.format(i))model.addConstr(quicksum(x[i, j] + y[i, j] for j in range(0, num_node + 1)) == 1,name='cons_1_out_xy_[{}]'.format(i))# truck or uavmodel.addConstr(quicksum(y[j, i] for j in range(0, num_node + 1))== quicksum(y[i, j] for j in range(0, num_node + 1)), name='cons_1_y[{}]'.format(i))# cons 2: self-loop eliminationmodel.addConstr(quicksum(x[i, i] for i in range(0, num_node + 1)) == 0, name='cons_2_x')model.addConstr(quicksum(y[i, i] for i in range(0, num_node + 1)) == 0, name='cons_2_y')# cons 3: get, if served by truckfor i in range(1, num_node + 1):model.addConstr(s[i] == quicksum(x[i, j] for j in range(0, num_node + 1)), name='cons_3_[{}]'.format(i))# cons 4: load limit, including sub-loop eliminationbig_m = 10 ** 6for j in range(1, num_node + 1):for i in range(0, num_node + 1):list_not_j = list(range(0, j)) + list(range(j + 1, num_node + 1))list_uav_not_j = list_node_uav.copy()if j in list_uav_not_j:list_uav_not_j.remove(j)model.addConstr(z[i, j] >= list_weight[j - 1] + quicksum(z[j, k] for k in list_not_j)+ quicksum(y[j, u] * list_weight[u - 1] for u in list_uav_not_j) + (x[i, j] - 1) * big_m,name='cons_4_[{},{}]'.format(i, j))model.addConstr(z[i, j] <= x[i, j] * big_m, name='cons_4_zx_[{},{}]'.format(i, j))# todo: sun-loop elimination:  2-node loopif i:model.addConstr(x[i, j] + x[j, i] <= 1, name='cons_4_loop_2[{},{}]'.format(i, j))# cons 5: uav orderfor j in list_node_uav:for i in range(0, num_node + 1):for k in range(0, num_node + 1):model.addConstr(y[i, j] + y[j, k] <= 2 * x[i, k] + 1, name='cons_5_[{},{},{}]'.format(i, j, k))# cons 6: only one uavfor i in range(0, num_node + 1):model.addConstr(quicksum(y[i, j] for j in range(0, num_node + 1)) <= 1, name='cons_6_out_[{}]'.format(i))model.addConstr(quicksum(y[j, i] for j in range(0, num_node + 1)) <= 1, name='cons_6_in_[{}]'.format(i))# cons 7: valid inequalitymodel.addConstr(quicksum(x[0, j] for j in range(1, num_node + 1)) >= math.ceil(sum(list_weight) / upper_load),name='cons_7')""" objective & solve """num_vehicle = quicksum(x[0, j] for j in range(1, num_node + 1))sum_distance = quicksum(x[i, j] * mat_distance[i][j] + y[i, j] * mat_distance[i][j] * cost_uavfor i in range(0, num_node + 1) for j in range(0, num_node + 1))model.setObjective(num_vehicle * big_m + sum_distance, sense=GRB.MINIMIZE)model.setParam(GRB.Param.TimeLimit, 600)model.setParam(GRB.Param.MIPGap, 0.05)dts_solve = datetime.now()model.optimize()dte_solve = datetime.now()tm_solve = round((dte_solve - dts_solve).seconds + (dte_solve - dts_solve).microseconds / (10 ** 6), 3)log.info(msg="solving time:  {} s".format(tm_solve))""" result """x_ = model.getAttr('X', x)y_ = model.getAttr('X', y)s_ = model.getAttr('X', s)num_vehicle_ = int(sum(x_[0, j] for j in range(1, num_node + 1)))log.info("total vehicles: {}".format(num_vehicle_))# uav routeslist_node_uav_ = []dict_uav_route = {}for j in list_node_uav:if s_[j] < 0.1:list_node_uav_.append(j)fr, to = None, Nonefor i in range(0, num_node + 1):if y_[i, j] > 0.9:fr = ibreakfor k in range(0, num_node + 1):if y_[j, k] > 0.9:to = kbreaktup_fr_to = (fr, to)dict_uav_route[j] = tup_fr_tolog.info(msg="nodes can be served by uav:  {}".format(list_node_uav))log.info(msg="nodes served by uav:  {}".format(list_node_uav_))# truck routeslist_routes = []set_node = set(range(0, num_node + 1))while len(set_node) > 1 + len(list_node_uav_):  # todo: number of nodes served by trucklist_route_cur = [0]to = Nonewhile to != 0:if to:set_node.remove(to)for i in set_node:if x_[list_route_cur[-1], i] > 0.9:to = ilist_route_cur.append(to)breaklist_routes.append(list_route_cur)log.info(msg="<<< TSP model, GG formulation, end")return list_routes, dict_uav_route

工具模块(日志打印工具)


源码中采用调用 logging 打印日志的方法。
参见本人另一篇博客:https://blog.csdn.net/Zhang_0702_China/article/details/107982958

import os
import logging
from logging.handlers import TimedRotatingFileHandlerPATH = os.path.dirname(os.path.dirname(__file__))class Logger(object):"""log writer"""def __init__(self, log_name: str):"""log writer, initialise:param log_name:  file name of log"""self.log_name = log_nameself.log = logging.getLogger(name=self.log_name)self.log.setLevel(logging.INFO)# initialise logginglogging.basicConfig()# output formatfmt_st = "%(asctime)s[%(levelname)s][%(processName)s][%(threadName)s]:%(message)s"formatter = logging.Formatter(fmt=fmt_st)# log filepath_root = os.path.join(PATH, "log")  # root directory of logif not os.path.exists(path_root):os.makedirs(name=path_root)path = os.path.join(path_root, self.log_name)# level and formatfile_handler = logging.handlers.TimedRotatingFileHandler(filename=path)file_handler.setLevel(level=logging.INFO)file_handler.setFormatter(fmt=formatter)self.log.addHandler(hdlr=file_handler)def info(self, msg: str):"""info:param msg:  info:return: nothing"""msg_ = " " + msgself.log.info(msg=msg_)def error(self, msg: str):"""error info:param msg:  error info:return: nothing"""msg_ = " " + msgself.log.error(msg=msg_)log_tsp = Logger(log_name='tsp.log')
log_vrp = Logger(log_name='vrp.log')

可视化模块


TSP:

import os
from typing import List, Dict, Tuple
import matplotlib.pyplot as pltfrom config import tsp as configPATH = os.path.dirname(os.path.dirname(__file__))def scatter_route_tsp(list_route: List[int], dict_uav_route: Dict[int, Tuple[int, int]]):"""scatters and route of tsp result:param list_route:  list of nodes in truck route:param dict_uav_route:  dict of uav routes:return: nothing"""num_node = config.NUM_NODElist_node_uav = config.LIST_NODE_UAVorigin = config.ORIGINlist_coordinate_ = config.LIST_COORDINATE_range_coordinate = config.RANGE_COORDINATE# scattersplt.scatter(x=origin[0], y=origin[1], s=50, c='black', label='origin')for i in range(1, num_node + 1):color = 'blue' if i not in list_node_uav else 'red'plt.scatter(x=list_coordinate_[i][0], y=list_coordinate_[i][1], s=20, c=color, label=str(i))width = 0.2head_width = 2head_length = 3alpha = 0.7color_truck, color_uav = 'green', 'orange'line_width = 0.5# truck routefor i in range(len(list_route) - 1):plt.arrow(x=list_coordinate_[list_route[i]][0], y=list_coordinate_[list_route[i]][1],dx=list_coordinate_[list_route[i + 1]][0] - list_coordinate_[list_route[i]][0],dy=list_coordinate_[list_route[i + 1]][1] - list_coordinate_[list_route[i]][1],width=width, length_includes_head=True, head_width=head_width, head_length=head_length,alpha=alpha, color=color_truck, linestyle='-', linewidth=line_width)# uav routefor i in dict_uav_route.keys():plt.arrow(x=list_coordinate_[dict_uav_route[i][0]][0], y=list_coordinate_[dict_uav_route[i][0]][1],dx=list_coordinate_[i][0] - list_coordinate_[dict_uav_route[i][0]][0],dy=list_coordinate_[i][1] - list_coordinate_[dict_uav_route[i][0]][1],width=width, length_includes_head=True, head_width=head_width, head_length=head_length,alpha=alpha, color=color_uav, linestyle='--', linewidth=line_width)plt.arrow(x=list_coordinate_[i][0], y=list_coordinate_[i][1],dx=list_coordinate_[dict_uav_route[i][1]][0] - list_coordinate_[i][0],dy=list_coordinate_[dict_uav_route[i][1]][1] - list_coordinate_[i][1],width=width, length_includes_head=True, head_width=head_width, head_length=head_length,alpha=alpha, color=color_uav, linestyle='--', linewidth=line_width)# x, y rangeedge = 5plt.xlim(range_coordinate[0] - edge, range_coordinate[1] + edge)plt.ylim(range_coordinate[0] - edge, range_coordinate[1] + edge)# savepath = os.path.join(PATH, "output/tsp.png")plt.savefig(path)

VRP:

import os
from typing import List, Dict, Tuple
import matplotlib.pyplot as pltfrom config import vrp as configPATH = os.path.dirname(os.path.dirname(__file__))def scatter_route_vrp(list_routes: List[List[int]], dict_uav_route: Dict[int, Tuple[int, int]]):"""scatters and route of vrp result:param list_routes:  list of truck route:param dict_uav_route:  dict of uav routes:return: nothing"""num_node = config.NUM_NODElist_node_uav = config.LIST_NODE_UAVorigin = config.ORIGINlist_coordinate_ = config.LIST_COORDINATE_range_coordinate = config.RANGE_COORDINATE# scattersplt.scatter(x=origin[0], y=origin[1], s=50, c='black', label='origin')for i in range(1, num_node + 1):color = 'blue' if i not in list_node_uav else 'red'plt.scatter(x=list_coordinate_[i][0], y=list_coordinate_[i][1], s=20, c=color, label=str(i))width = 0.2head_width = 2head_length = 3alpha = 0.7color_truck, color_uav = 'green', 'orange'line_width = 0.5# truck routesfor route in list_routes:for i in range(len(route) - 1):plt.arrow(x=list_coordinate_[route[i]][0], y=list_coordinate_[route[i]][1],dx=list_coordinate_[route[i + 1]][0] - list_coordinate_[route[i]][0],dy=list_coordinate_[route[i + 1]][1] - list_coordinate_[route[i]][1],width=width, length_includes_head=True, head_width=head_width, head_length=head_length,alpha=alpha, color=color_truck, linestyle='-', linewidth=line_width)# uav routesfor i in dict_uav_route.keys():plt.arrow(x=list_coordinate_[dict_uav_route[i][0]][0], y=list_coordinate_[dict_uav_route[i][0]][1],dx=list_coordinate_[i][0] - list_coordinate_[dict_uav_route[i][0]][0],dy=list_coordinate_[i][1] - list_coordinate_[dict_uav_route[i][0]][1],width=width, length_includes_head=True, head_width=head_width, head_length=head_length,alpha=alpha, color=color_uav, linestyle='--', linewidth=line_width)plt.arrow(x=list_coordinate_[i][0], y=list_coordinate_[i][1],dx=list_coordinate_[dict_uav_route[i][1]][0] - list_coordinate_[i][0],dy=list_coordinate_[dict_uav_route[i][1]][1] - list_coordinate_[i][1],width=width, length_includes_head=True, head_width=head_width, head_length=head_length,alpha=alpha, color=color_uav, linestyle='--', linewidth=line_width)# x, y rangeedge = 5plt.xlim(range_coordinate[0] - edge, range_coordinate[1] + edge)plt.ylim(range_coordinate[0] - edge, range_coordinate[1] + edge)# savepath = os.path.join(PATH, "output/vrp.png")plt.savefig(path)

主程序


TSP(main_tsp.py):

from datetime import datetimefrom utils.logger import log_tsp as log
from config import tsp as config
from model.tsp import tsp_gg
from visual.tsp import scatter_route_tspDTS = datetime.now()NUM_NODE = config.NUM_NODE
LIST_NODE_UAV = config.LIST_NODE_UAV.copy()
MAT_DISTANCE = config.MAT_DISTANCE.copy()
COST_UAV = config.COST_UAV
log.info(msg="number of nodes:  {}".format(NUM_NODE))
log.info(msg="node can served by uav:  {}".format(LIST_NODE_UAV))# model
list_route, dict_uav_route = tsp_gg(num_node=NUM_NODE, list_node_uav=LIST_NODE_UAV, mat_distance=MAT_DISTANCE,cost_uav=COST_UAV)
log.info(msg="truck route:  {}".format(list_route))
for i in dict_uav_route.keys():log.info(msg="uav served node:  {},  {}".format(i, dict_uav_route[i]))# visualisation
scatter_route_tsp(list_route=list_route, dict_uav_route=dict_uav_route)DTE = datetime.now()
TM = round((DTE - DTS).seconds + (DTE - DTS).microseconds / (10 ** 6), 3)
log.info(msg="total time:  {} s".format(TM))

VRP(main_vrp.py):

from datetime import datetimefrom utils.logger import log_vrp as log
from config import vrp as config
from model.vrp import vrp_load
from visual.vrp import scatter_route_vrpDTS = datetime.now()NUM_NODE = config.NUM_NODE
LIST_NODE_UAV = config.LIST_NODE_UAV.copy()
LIST_WEIGHT = config.LIST_WEIGHT
UPPER_LOAD = config.UPPER_LOAD
MAT_DISTANCE = config.MAT_DISTANCE.copy()
COST_UAV = config.COST_UAV
log.info(msg="number of nodes:  {}".format(NUM_NODE))
log.info(msg="node can served by uav:  {}".format(LIST_NODE_UAV))# model
list_routes, dict_uav_route = vrp_load(num_node=NUM_NODE, list_node_uav=LIST_NODE_UAV, list_weight=LIST_WEIGHT, upper_load=UPPER_LOAD,mat_distance=MAT_DISTANCE, cost_uav=COST_UAV)
for i in range(len(list_routes)):log.info(msg="truck route {}:  {}".format(i + 1, list_routes[i]))
for i in dict_uav_route.keys():log.info(msg="uav served node:  {},  {}".format(i, dict_uav_route[i]))# visualisation
scatter_route_vrp(list_routes=list_routes, dict_uav_route=dict_uav_route)DTE = datetime.now()
TM = round((DTE - DTS).seconds + (DTE - DTS).microseconds / (10 ** 6), 3)
log.info(msg="total time:  {} s".format(TM))

运行效果


TSP


如前面参数与输入数据模块所示,源码中的 TSP 算例有 50 个点,其中后面 20 个可使用无人机配送,无人机的距离成本系数设为 0.2(即同样的距离又无人机配送的成本为卡车配送的 20%),源码的运行日志如下:

2021-08-04 19:37:03,923[INFO][MainProcess][MainThread]: random data generating time:  0.004 s
2021-08-04 19:37:04,787[INFO][MainProcess][MainThread]: number of nodes:  50
2021-08-04 19:37:04,787[INFO][MainProcess][MainThread]: node can served by uav:  [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
2021-08-04 19:37:04,787[INFO][MainProcess][MainThread]: >>> TSP model, GG formulation, start
2021-08-04 19:38:16,624[INFO][MainProcess][MainThread]: solving time:  49.773 s
2021-08-04 19:38:16,633[INFO][MainProcess][MainThread]: nodes can be served by uav:  [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
2021-08-04 19:38:16,633[INFO][MainProcess][MainThread]: nodes served by uav:  [31, 32, 33, 36, 37, 39, 40, 41, 42, 44, 49, 50]
2021-08-04 19:38:16,634[INFO][MainProcess][MainThread]: <<< TSP model, GG formulation, end
2021-08-04 19:38:16,690[INFO][MainProcess][MainThread]: truck route:  [0, 34, 24, 27, 5, 1, 21, 14, 35, 48, 12, 43, 17, 20, 18, 19, 2, 26, 15, 8, 47, 13, 29, 38, 28, 9, 22, 6, 4, 30, 10, 11, 25, 46, 16, 3, 23, 45, 7, 0]
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  31,  (20, 18)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  32,  (10, 11)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  33,  (22, 6)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  36,  (1, 21)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  37,  (13, 29)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  39,  (9, 22)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  40,  (17, 20)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  41,  (18, 19)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  42,  (26, 15)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  44,  (21, 14)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  49,  (19, 2)
2021-08-04 19:38:16,691[INFO][MainProcess][MainThread]: uav served node:  50,  (6, 4)
2021-08-04 19:38:17,174[INFO][MainProcess][MainThread]: total time:  72.387 s

可视化结果图:
TSP 可视化结果

VRP


关于 VRP 模型的算例,源码中的设置为 50 个点,其中最后 10 个点可使用无人机配送,无人机的距离成本系数设为 0.1,每辆车的载重上限为 100,每个物品的重量上限为 20,源码的运行日志如下:

2021-08-04 19:40:21,300[INFO][MainProcess][MainThread]: total weight:  486
2021-08-04 19:40:21,300[INFO][MainProcess][MainThread]: random data generating time:  0.004 s
2021-08-04 19:40:22,168[INFO][MainProcess][MainThread]: number of nodes:  50
2021-08-04 19:40:22,168[INFO][MainProcess][MainThread]: node can served by uav:  [41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
2021-08-04 19:40:22,168[INFO][MainProcess][MainThread]: >>> VRP model, load limit mode, start
2021-08-04 19:41:23,075[INFO][MainProcess][MainThread]: solving time:  38.906 s
2021-08-04 19:41:23,092[INFO][MainProcess][MainThread]: total vehicles: 5
2021-08-04 19:41:23,093[INFO][MainProcess][MainThread]: nodes can be served by uav:  [41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
2021-08-04 19:41:23,094[INFO][MainProcess][MainThread]: nodes served by uav:  [42, 43, 44, 45, 46, 47, 48, 49, 50]
2021-08-04 19:41:23,094[INFO][MainProcess][MainThread]: <<< TSP model, GG formulation, end
2021-08-04 19:41:23,175[INFO][MainProcess][MainThread]: truck route 1:  [0, 6, 4, 30, 25, 11, 10, 32, 3, 16, 23, 0]
2021-08-04 19:41:23,175[INFO][MainProcess][MainThread]: truck route 2:  [0, 7, 33, 22, 39, 9, 13, 29, 37, 38, 28, 0]
2021-08-04 19:41:23,175[INFO][MainProcess][MainThread]: truck route 3:  [0, 19, 2, 26, 15, 8, 0]
2021-08-04 19:41:23,175[INFO][MainProcess][MainThread]: truck route 4:  [0, 34, 24, 36, 1, 5, 27, 0]
2021-08-04 19:41:23,175[INFO][MainProcess][MainThread]: truck route 5:  [0, 41, 31, 18, 20, 17, 40, 12, 35, 14, 21, 0]
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  42,  (26, 15)
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  43,  (19, 2)
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  44,  (36, 1)
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  45,  (34, 24)
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  46,  (3, 16)
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  47,  (15, 8)
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  48,  (35, 14)
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  49,  (2, 26)
2021-08-04 19:41:23,176[INFO][MainProcess][MainThread]: uav served node:  50,  (0, 6)
2021-08-04 19:41:23,652[INFO][MainProcess][MainThread]: total time:  61.484 s

可视化结果图:
VRP 可视化结果



http://chatgpt.dhexx.cn/article/Z0AEqcjt.shtml

相关文章

(附源码)springboot车辆管理系统 毕业设计031034

车辆管理系统的设计与实现 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&…

QT+SQL Server实现车辆管理系统 -代码具体实现

QTSQL Server 实现车辆管理系统 -代码具体实现 1.摘要2.整体框架3.具体代码实现3.1 连接数据库3.2 登录操作3.3 申请账户3.4 添加车辆信息3.5 查询车辆信息3.6删除车辆信息3.7修改车辆信息3.8 添加司机信息 4.总结5.资源下载链接 1.摘要 前面一篇文章简要介绍了车辆管理系统的…

如何使用低代码进行车队管理?

处理任何业务都具有挑战性&#xff0c;但车队管理无疑是所有业务中的佼佼者。无论是司机短缺、环境问题、国际法规还是行业不稳定&#xff0c;车队经理都必须面对这一切。除此之外&#xff0c;还有数字化和路线优化的概念。数字化转型车队管理业务意味着消除挑战&#xff0c;拥…

车辆自然驾驶轨迹数据集/交通流数据介绍

文章目录 NGSIMNGSIM 概览快速路车道选择算法Interstate 80 Freeway 数据集Lankershim Boulevard 数据集US highway101数据集动态交通分配DTACORSIM Argoverse Motion Forecasting DatasetAIMSUNHighDITS DataHub 美国智能交通数据库Data.govPeMSPortland Oregon Region data英…

3D车辆检测AP评价指标代码的理解

课题研究的是单目3D车辆的识别&#xff0c;采用的目标检测网络是SMOKE&#xff0c;为了可以更好的定量评测训练模型的性能&#xff0c;需要使用到合理的评测指标&#xff0c;目前比较流行的评测指标是得到多组precision和recall值画出PR曲线&#xff0c;然后计算PR曲线下的面积…

根据车辆型号自动生成车辆编号

开发工具与关键技术&#xff1a;Visual Studio 2015 linq 正则 作者&#xff1a;孙水兵 撰写时间&#xff1a;2019年6月26一、 功能 根据不同的类型的车辆型号&#xff0c;生成以车辆型号开头的车辆编号。 二、 达到的效果 用户选择了车辆型号之后&#xff0c;将对应的车辆编…

【路径规划】基于遗传算法求解多车多类型车辆的车辆路径优化问题附matlab代码

1 内容介绍 多车辆多路线的交通路线优化涉及到排序问题,是一个N-P难题,高效精确的算法存在的可能性不大.提出了基于遗传算法的求解方法,给出了实例来证明如何利用遗传算法解决多车辆多路线的优化问题.结果证明,一般情况下利用遗传算法对于多车辆多路线的行车路线优化能得到一组…

机动车登记信息代码

原链接&#xff1a;机动车登记信息代 搜索结果本栏目用于收集和整理行业相关标准&#xff0c;如机械行业&#xff0c;化工行业等。http://www.gb99.cn/e/search/result/?searchid76243针对其中第七项车辆信息牌照代码如下&#xff1a;

利用低代码平台进行车辆管理,为交通行业添砖加瓦

概要&#xff1a;本文介绍了交通行业车辆管理的重要性&#xff0c;并详细阐述了基于低代码平台设计的车辆管理系统的优势。通过快速开发、易于维护、增加灵活性、提高数据可靠性、降低成本以及实时监控等多个方面&#xff0c;这种车辆管理系统可以帮助企业提高效率和降低成本&a…

(c++课程设计)简单车辆管理系统(有五种类型的车辆)代码+报告

关于这个课程设计 &#xff0c;差点没把我头发愁没。 好了其实本质还是东拼西凑&#xff0c;编程能力没怎么长进&#xff0c;花里胡哨的东西却学了不少&#xff08;不是&#xff09; 万恶的学院&#xff0c;虽然要求三人一组&#xff0c;但是却分一二三类&#xff0c;三个人代…

什么是车辆识别代码(VIN)

车辆识别代码(VIN),VIN是英文Vehicle Identification Number(车辆识别码)的缩写。因为ASE标准规定:VIN码由17位字符组成,所以俗称十七位码。正确解读VIN码,对于我们正确地识别车型,以致进行正确地诊断和维修都是十分重要的。车辆识别代码根据国家车辆管理标准确定,包…

Eigen学习笔记1:在VS2015下Eigen(矩阵变换)的配置

一、Eigen简介 Eigen是一个高层次的C 库&#xff0c;有效支持线性代数&#xff0c;矩阵和矢量运算&#xff0c;数值分析及其相关的算法。 Eigen适用范围广&#xff0c;支持包括固定大小、任意大小的所有矩阵操作&#xff0c;甚至是稀疏矩阵&#xff1b;支持所有标准的数值类型&…

鲁鹏老师三维重建课程之单视图重建

配置Json环境 使用Jsoncpp包中的.cpp和 .h文件 解压上面下载的 Jsoncpp 文件&#xff0c;把 jsoncpp-src-0.5.0文件拷贝到工程目录下&#xff0c; 将 jsoncpp-src-0.5.0\jsoncpp-src-0.5.0\include\json 和 jsoncpp-src-0.5.0\jsoncpp-src-0.5.0\src\lib_json 目录里的文…

常用 Linux 软件汇总!很全,但不敢说最全

点击下方公众号「关注」和「星标」 回复“1024”获取独家整理的学习资料&#xff01; 音频 Airtime - Airtime 是一款用于调度和远程站点管理的开放广播软件 Ardour - 在 Linux 上录音&#xff0c;编辑&#xff0c;和混音 Audacious - 开源音频播放器&#xff0c;按你想要的方式…

RoadMap:面向自动驾驶视觉定位的轻量级语义地图(ICRA2021)

点击上方“3D视觉工坊”&#xff0c;选择“星标” 干货第一时间送达 标题&#xff1a;RoadMap: A Light-Weight Semantic Map for Visual Localization towards Autonomous Driving 作者&#xff1a;Tong Qin, Yuxin Zheng, Tongqing Chen, Yilun Chen, and Qing Su 来源&#…

计算机图形学作业( 三):使用openGL画一个立方体,并实现平移、旋转和放缩变换

计算机图形学作业( 三):使用openGL画一个立方体,并实现平移、旋转和放缩变换 题目引入GLM库画立方体模型、观察和投影修改着色器立方体的顶点深度测试立方体变换平移旋转放缩渲染管线的理解代码题目 引入GLM库 利用 openGL 进行 3D 绘图需要用到大量的数学矩阵运算,而 Op…

一文掌握基于深度学习的自动驾驶小车开发(Pytorch实现,含完整数据和源码,树莓派+神经计算棒)

目录 一 . 基本介绍 二、模拟平台安装和基本使用 三、基于OpenCV的自动驾驶控制 3.1基于HSV空间的特定颜色区域提取 3.2基于canny算子的边缘轮廓提取 3.3感兴趣区域定位 3.4基于霍夫变换的线段检测 3.5动作控制&#xff1a;转向角 四、基于深度学习的自动驾驶控制 4.…

OpenGL坐标变换及其数学原理,两种摄像机交互模型(附源程序)

&#xfeff;&#xfeff; 实验平台&#xff1a;win7&#xff0c;VS2010 先上结果截图&#xff08;文章最后下载程序&#xff0c;解压后直接运行BIN文件夹下的EXE程序&#xff09;&#xff1a; a.鼠标拖拽旋转物体&#xff0c;类似于OGRE中的“OgreBites::CameraStyle::CS_ORB…

Python-WingIde各种调试方法

一、 本地从IDE启动文件调试 主要步骤:设置断点,F5开始调试 二、 本地从IDE外启动文件调试 1.) 从WingIDE的安装目录(默认C:\Program Files (x86)\Wing IDE 6.0)复制wingdbstub.py到被调试代码所在目录 2.) 代码中添加importwingdbstub 3.) IDE左下角设置如图 4.) 在…

图形处理单元(GPU)的演进

CPU 和 GPU 好久没有更新了&#xff0c;最近在阅读 CUDA 相关的一些论文&#xff0c;因为都是碎片化阅读&#xff0c;容易导致读过后&#xff0c;可能过一段时间又忘记掉&#xff0c;所以决定抽时间翻译翻译阅读的论文&#xff0c;一方面增强自己记忆&#xff0c;一方面与大家共…