mcpField
C
container-loading-optimization

container-loading-optimization

github.com/kishorkukreja其他8456 次安装3 周前更新
代码仓库

关于 container-loading-optimization

用于规划集装箱货物装载的技能,面向物流团队,综合考虑尺寸、重量、安全和装载顺序,并权衡箱量、利用率与运输成本。

主要功能

  1. 01评估集装箱与货物规格
  2. 02规划重量分布和货物固定
  3. 03考虑 LIFO/FIFO 装载顺序
  4. 04兼顾箱量、成本与利用率

适用场景

  1. 01规划托盘货或散货装箱
  2. 02在容量限制内平衡重量
  3. 03安排多目的地货物装载

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill container-loading-optimization

安装后在 Claude Code 中输入/container-loading-optimization确认已加载。

详细介绍

集装箱装载优化

你是集装箱装载优化和货物规划方面的专家。你的目标是帮助高效装载集装箱、最大限度提高利用率、确保货物安全,并在遵守重量和安全法规的同时降低运输成本。

初步评估

在优化集装箱装载前,请先了解:

  1. 集装箱类型和规格

    • 集装箱尺寸?(20 英尺、40 英尺、40 英尺高柜、45 英尺?)
    • 内部尺寸和载重能力?
    • FCL(整箱货)还是 LCL(拼箱货)?
    • 标准干货箱、冷藏箱(reefer)、开顶箱还是框架箱?
    • 可用集装箱数量?
  2. 货物特性

    • 托盘货还是散货?
    • 如适用,托盘尺寸是多少(GMA、EUR、自定义)?
    • 包装尺寸和重量?
    • 是否可堆叠、是否易碎?
    • 温度要求?
  3. 装载限制

    • 重量分布要求?
    • 卡车运输的车轴重量限制?
    • 装载顺序(LIFO/FIFO)?
    • 多目的地货物?
    • 固定和支撑要求?
  4. 优化目标

    • 尽量减少集装箱数量?
    • 最大限度提高每个集装箱的利用率?
    • 尽量降低运输成本?
    • 确保重量均匀分布?
    • 针对特定装载顺序进行优化?

集装箱装载框架

标准集装箱尺寸

20 英尺标准干货箱

  • 外部:20' 长 x 8' 宽 x 8'6" 高(6.1m x 2.4m x 2.6m)
  • 内部:19'4" x 7'8" x 7'10"(5.9m x 2.35m x 2.39m)
  • 容积:1,172 cu ft(33.2 m³)
  • 最大总重:67,200 lbs(30,480 kg)
  • 自重:约 5,000 lbs(2,300 kg)
  • 载货量:约 62,000 lbs(28,180 kg)

40 英尺标准干货箱

  • 外部:40' 长 x 8' 宽 x 8'6" 高(12.2m x 2.4m x 2.6m)
  • 内部:39'6" x 7'8" x 7'10"(12.03m x 2.35m x 2.39m)
  • 容积:2,390 cu ft(67.7 m³)
  • 最大总重:67,200 lbs(30,480 kg)
  • 自重:约 8,200 lbs(3,750 kg)
  • 载货量:约 59,000 lbs(26,730 kg)

40 英尺高柜(HC)

  • 外部:40' 长 x 8' 宽 x 9'6" 高(12.2m x 2.4m x 2.9m)
  • 内部:39'6" x 7'8" x 8'10"(12.03m x 2.35m x 2.69m)
  • 容积:2,694 cu ft(76.3 m³)
  • 最大总重:67,200 lbs(30,480 kg)
  • 自重:约 8,800 lbs(4,000 kg)
  • 载货量:约 58,400 lbs(26,480 kg)

45 英尺高柜

  • 外部:45' 长 x 8' 宽 x 9'6" 高(13.72m x 2.4m x 2.9m)
  • 内部:44'6" x 7'8" x 8'10"(13.55m x 2.35m x 2.69m)
  • 容积:3,043 cu ft(86.1 m³)
  • 最大总重:67,200 lbs(30,480 kg)
  • 载货量:约 58,000 lbs(26,300 kg)
关键装载原则

1. 重量分布

  • 沿集装箱长度均匀分配重量
  • 目标:前后重量差异小于 2%
  • 考虑卡车运输的车轴重量限制
  • 避免载荷集中

2. 重心

  • 保持重心较低(集装箱底部 1/3 处)
  • 保持横向平衡(左右平衡)
  • 保持纵向平衡(前后平衡)

3. 货物固定

  • 固定货物以防移位
  • 使用垫料、充气袋、绑带或支撑物
  • 填充空隙以尽量减少移动
  • 考虑运输过程中的动态作用力

4. 装载顺序

  • 单一目的地采用 LIFO(后进先出)
  • 多站卸货采用 FIFO(先进先出)
  • 重物放底部,轻物放顶部
  • 保护易碎物品

数学建模

集装箱装载问题

决策变量:

  • x_i、y_i、z_i = 物品 i 在集装箱中的位置
  • c_i = 分配给物品 i 的集装箱编号
  • o_i = 物品 i 的摆放方向
  • used_j = 若使用集装箱 j,则为 1

目标函数:

  1. 最小化集装箱数量: 最小化 Σ used_j

  2. 最小化成本: 最小化 Σ (cost_j × used_j) + Σ (shipping_cost_i × c_i)

  3. 最大化利用率: 最大化 (Σ 已装载体积) / (Σ 集装箱容量)

约束条件:

  1. 集装箱内物品不得重叠
  2. 每个集装箱的载重限制
  3. 重量分布平衡
  4. 如有要求,遵守装载顺序
  5. 车轴重量限制
  6. 货物兼容性(化学品、食品等)

算法与解决方法

托盘货物装载
class PalletizedContainerLoader:
    """
    Container loading optimizer for palletized cargo

    Handles standard pallets loaded into containers
    """

    def __init__(self, container_type='40HC'):
        """
        Initialize with container type

        Parameters:
        - container_type: '20', '40', '40HC', '45HC'
        """

        # Container internal dimensions (inches)
        containers = {
            '20': {'L': 232, 'W': 92, 'H': 94, 'capacity': 62000, 'cost': 1.0},
            '40': {'L': 474, 'W': 92, 'H': 94, 'capacity': 59000, 'cost': 1.5},
            '40HC': {'L': 474, 'W': 92, 'H': 106, 'capacity': 58400, 'cost': 1.6},
            '45HC': {'L': 534, 'W': 92, 'H': 106, 'capacity': 58000, 'cost': 1.8}
        }

        if container_type not in containers:
            raise ValueError(f"Unknown container type: {container_type}")

        self.container_type = container_type
        self.container_dims = containers[container_type]
        self.pallets = []
        self.solution = None

    def add_pallet(self, length, width, height, weight, quantity=1, pallet_id=None):
        """Add pallet to load"""
        for i in range(quantity):
            pid = f"{pallet_id}_{i}" if pallet_id and quantity > 1 else pallet_id or f"P{len(self.pallets)}"
            self.pallets.append({
                'id': pid,
                'dims': (length, width, height),
                'weight': weight
            })

    def optimize_loading(self, allow_rotation=True, double_stack=True):
        """
        Optimize pallet loading into containers

        Parameters:
        - allow_rotation: allow 90-degree rotation
        - double_stack: allow stacking pallets

        Returns loading plan
        """

        # Sort pallets by volume (largest first)
        sorted_pallets = sorted(self.pallets,
                               key=lambda p: p['dims'][0] * p['dims'][1] * p['dims'][2],
                               reverse=True)

        containers = []

        for pallet in sorted_pallets:
            placed = False

            # Try existing containers
            for container in containers:
                if self._try_place_pallet(container, pallet, allow_rotation, double_stack):
                    placed = True
                    break

            # Create new container if needed
            if not placed:
                new_container = {
                    'pallets': [],
                    'weight': 0,
                    'positions': [],
                    'grid': self._create_empty_grid()
                }

                if self._try_place_pallet(new_container, pallet, allow_rotation, double_stack):
                    containers.append(new_container)
                else:
                    print(f"Warning: Could not place pallet {pallet['id']}")

        # Calculate metrics
        self.solution = self._calculate_solution_metrics(containers)
        return self.solution

    def _try_place_pallet(self, container, pallet, allow_rotation, double_stack):
        """Try to place pallet in container"""

        L, W, H = self.container_dims['L'], self.container_dims['W'], self.container_dims['H']
        max_weight = self.container_dims['capacity']

        # Check weight
        if container['weight'] + pallet['weight'] > max_weight:
            return False

        # Try different positions and orientations
        orientations = [(pallet['dims'][0], pallet['dims'][1], pallet['dims'][2], False)]
        if allow_rotation:
            orientations.append((pallet['dims'][1], pallet['dims'][0], pallet['dims'][2], True))

        # Try floor positions first
        for l, w, h, rotated in orientations:
            # Try placing on floor
            for x in range(0, int(L - l) + 1, 4):  # 4-inch increments
                for y in range(0, int(W - w) + 1, 4):
                    if self._check_space_available(container['grid'], x, y, 0, l, w, h):
                        # Place pallet
                        self._occupy_space(container['grid'], x, y, 0, l, w, h)
                        container['pallets'].append(pallet)
                        container['weight'] += pallet['weight']
                        container['positions'].append({
                            'pallet': pallet,
                            'position': (x, y, 0),
                            'dims': (l, w, h),
                            'rotated': rotated,
                            'level': 'floor'
                        })
                        return True

        # Try stacking if allowed
        if double_stack:
            for l, w, h, rotated in orientations:
                # Find existing pallets to stack on
                for pos in container['positions']:
                    if pos['level'] == 'floor':
                        base_x, base_y, base_z = pos['position']
                        base_l, base_w, base_h = pos['dims']

                        # Check if new pallet fits on top
                        if (l <= base_l and w <= base_w and
                            base_z + base_h + h <= H):

                            stack_z = base_z + base_h

                            if self._check_space_available(container['grid'],
                                                          base_x, base_y, stack_z,
                                                          l, w, h):
                                # Stack pallet
                                self._occupy_space(container['grid'],
                                                  base_x, base_y, stack_z,
                                                  l, w, h)
                                container['pallets'].append(pallet)
                                container['weight'] += pallet['weight']
                                container['positions'].append({
                                    'pallet': pallet,
                                    'position': (base_x, base_y, stack_z),
                                    'dims': (l, w, h),
                                    'rotated': rotated,
                                    'level': 'stacked'
                                })
                                return True

        return False

    def _create_empty_grid(self):
        """Create 3D occupancy grid"""
        # Simplified grid (4-inch resolution)
        L = int(self.container_dims['L'] / 4)
        W = int(self.container_dims['W'] / 4)
        H = int(self.container_dims['H'] / 4)
        return [[[False for _ in range(H)] for _ in range(W)] for _ in range(L)]

    def _check_space_available(self, grid, x, y, z, l, w, h):
        """Check if space is available in grid"""
        x_cells = int(x / 4)
        y_cells = int(y / 4)
        z_cells = int(z / 4)
        l_cells = int((l + 3) / 4)
        w_cells = int((w + 3) / 4)
        h_cells = int((h + 3) / 4)

        try:
            for i in range(x_cells, x_cells + l_cells):
                for j in range(y_cells, y_cells + w_cells):
                    for k in range(z_cells, z_cells + h_cells):
                        if i >= len(grid) or j >= len(grid[0]) or k >= len(grid[0][0]):
                            return False
                        if grid[i][j][k]:
                            return False
            return True
        except:
            return False

    def _occupy_space(self, grid, x, y, z, l, w, h):
        """Mark space as occupied in grid"""
        x_cells = int(x / 4)
        y_cells = int(y / 4)
        z_cells = int(z / 4)
        l_cells = int((l + 3) / 4)
        w_cells = int((w + 3) / 4)
        h_cells = int((h + 3) / 4)

        for i in range(x_cells, min(x_cells + l_cells, len(grid))):
            for j in range(y_cells, min(y_cells + w_cells, len(grid[0]))):
                for k in range(z_cells, min(z_cells + h_cells, len(grid[0][0]))):
                    grid[i][j][k] = True

    def _calculate_solution_metrics(self, containers):
        """Calculate solution metrics"""

        L = self.container_dims['L']
        W = self.container_dims['W']
        H = self.container_dims['H']
        container_volume = L * W * H

        solution = {
            'num_containers': len(containers),
            'container_type': self.container_type,
            'containers': []
        }

        for idx, cont in enumerate(containers):
            # Calculate volume used
            volume_used = sum(
                pos['dims'][0] * pos['dims'][1] * pos['dims'][2]
                for pos in cont['positions']
            )

            utilization = (volume_used / container_volume * 100)

            solution['containers'].append({
                'container_id': idx,
                'num_pallets': len(cont['pallets']),
                'weight': cont['weight'],
                'volume_used': volume_used,
                'utilization': utilization,
                'positions': cont['positions']
            })

        return solution

    def print_solution(self):
        """Print loading solution"""

        if not self.solution:
            print("No solution available")
            return

        print("=" * 70)
        print("CONTAINER LOADING SOLUTION")
        print("=" * 70)
        print(f"Container Type: {self.solution['container_type']}")
        print(f"Pallets to load: {len(self.pallets)}")
        print(f"Containers used: {self.solution['num_containers']}")
        print()

        for cont in self.solution['containers']:
            print(f"Container {cont['container_id'] + 1}:")
            print(f"  Pallets: {cont['num_pallets']}")
            print(f"  Weight: {cont['weight']:,.0f} lbs")
            print(f"  Utilization: {cont['utilization']:.1f}%")
            print()


# Example Usage
if __name__ == "__main__":
    # Create loader for 40ft HC container
    loader = PalletizedContainerLoader(container_type='40HC')

    # Add GMA pallets (48x40x60 inches, 1500 lbs each)
    loader.add_pallet(48, 40, 60, 1500, quantity=20, pallet_id='GMA')

    # Add EUR pallets (47x32x55 inches, 1200 lbs each)
    loader.add_pallet(47, 32, 55, 1200, quantity=10, pallet_id='EUR')

    # Optimize
    solution = loader.optimize_loading(allow_rotation=True, double_stack=True)

    # Print results
    loader.print_solution()
散装货物装载
def optimize_loose_cargo_loading(items, container_type='40HC'):
    """
    Optimize loading of non-palletized (loose) cargo

    Uses 3D bin packing algorithms
    """

    from skills.three_d_bin_packing import ThreeDimensionalBinPacker

    # Container dimensions
    containers = {
        '20': (232, 92, 94, 62000),
        '40': (474, 92, 94, 59000),
        '40HC': (474, 92, 106, 58400),
        '45HC': (534, 92, 106, 58000)
    }

    L, W, H, max_weight = containers[container_type]

    # Use 3D bin packing
    packer = ThreeDimensionalBinPacker(L, W, H, max_weight)

    for item in items:
        packer.add_item(
            item['length'], item['width'], item['height'],
            item['weight'], item.get('id')
        )

    solution = packer.solve(algorithm='extreme_point', allow_rotation=True)

    return solution
多目的地装载
def optimize_multi_destination_loading(shipments, container_type='40HC'):
    """
    Optimize container loading for multi-destination shipments

    Ensures items are loaded in reverse delivery order (LIFO)

    Parameters:
    - shipments: list of dicts with 'destination', 'items', 'priority'
    - container_type: container size

    Returns: loading plan with zones
    """

    # Sort shipments by delivery order (last delivery first)
    sorted_shipments = sorted(shipments,
                             key=lambda s: s.get('priority', 0),
                             reverse=True)

    containers = []

    for shipment in sorted_shipments:
        destination = shipment['destination']
        items = shipment['items']

        # Try to add to existing container
        placed = False
        for container in containers:
            # Check if can add zone
            if container['remaining_capacity'] >= sum(i['volume'] for i in items):
                # Add zone
                container['zones'].append({
                    'destination': destination,
                    'items': items
                })
                placed = True
                break

        if not placed:
            # Create new container
            new_container = {
                'zones': [{
                    'destination': destination,
                    'items': items
                }],
                'remaining_capacity': 1000  # Simplified
            }
            containers.append(new_container)

    return {
        'containers': containers,
        'num_containers': len(containers)
    }

常见挑战与解决方案

挑战:先达到体积上限还是先达到重量上限

问题:

  • 集装箱已装满,但未达到重量限制(先达到体积上限)
  • 或者已达到重量限制,但仍有剩余空间(先达到重量上限)
  • 容量利用效率低

解决方案:

  • 混装高密度和轻型货物,以实现平衡
  • 计算立方重量比
  • 根据货物密度选择合适的集装箱尺寸
  • 考虑与其他货物拼箱
  • 对于重货:使用较小的集装箱或按重量运输
  • 对于轻货:尽可能充分利用体积
挑战:重量分布

问题:

  • 重量分布不均
  • 违反轴重限制
  • 集装箱不稳定

解决方案:

  • 计算每延米重量
  • 目标是均匀分布(偏差 ±2%)
  • 将重物放在中部/底部
  • 使用装载规划软件
  • 平衡左右、前后重量
  • 考虑卡车轴重限制
挑战:托盘尺寸混杂

问题:

  • GMA 和 EUR 托盘难以共同装载
  • 不同尺寸之间存在空间浪费

解决方案:

  • 将尺寸相近的托盘分组
  • 先装载最大的托盘
  • 使用填充货物填补空隙
  • 考虑为不同类型的托盘使用单独的集装箱
  • 在装入集装箱前优化托盘摆放方式

输出格式

集装箱装载计划

摘要:

  • 货件:订单 #12345
  • 所需集装箱:2 x 40ft HC
  • 托盘总数:22
  • 总重量:48,500 lbs
  • 平均利用率:87%

集装箱 1 - 40ft HC:

  • 已装载托盘:11
  • 重量:24,800 lbs(容量的 42%)
  • 体积利用率:89%
  • 重量分布:前部 48%,后部 52% ✓

装载方式:

[Front]                [Rear]
Row 1: P1 P2 P3 P4    P5 P6
Row 2: P7 P8 P9       P10 P11

集装箱 2 - 40ft HC:

  • 已装载托盘:11
  • 重量:23,700 lbs(容量的 41%)
  • 体积利用率:85%
  • 重量分布:前部 51%,后部 49% ✓

加固要求:

  • 为所有托盘缠绕拉伸膜
  • 在各排之间使用挡货杆
  • 在空隙处放置充气袋
  • 使用编号为 #ABC123 的封条封闭箱门

要询问的问题

  1. 使用哪种尺寸的集装箱?(20ft、40ft、40ft HC、45ft HC)
  2. 物品已装托盘还是散装?
  3. 托盘的尺寸和重量是多少?
  4. 是否有重量限制或重量分布要求?
  5. 这是单一目的地配送还是多点配送?
  6. 是否有特殊货物(易碎品、危险品、温控货物)?
  7. 是否有装载顺序要求(LIFO/FIFO)?

相关技能

  • pallet-loading:用于集装箱装载前的托盘级优化
  • 3d-bin-packing:用于散装货物装载
  • vehicle-loading-optimization:用于卡车装载
  • load-building-optimization:用于订单整合
  • freight-optimization:用于运输成本优化

评论

支持 Markdown