【实战项目 21-25】第 21/25 课

🤖 第21课:酒店配送

📌 酒店配送项目概述

酒店配送是服务机器人最成熟的商业应用——从大堂取物品,乘电梯到客房,电话通知客人,完成递送:

🏨 酒店配送场景

大堂吧 → 取餐/饮料 → 乘电梯 → 导航到客房 →
拨打房间电话 → 等待开门 → 递送 → 确认 → 返回

📌 配送流程实现

import json, math, random
from collections import deque

class HotelDeliveryRobot:
    """酒店配送机器人"""
    def __init__(self, name="HotelBot-01"):
        self.name = name
        self.position = {"x": 0, "y": 0, "floor": 1}
        self.state = "idle"
        self.battery = 100
        self.current_task = None
        self.completed_tasks = 0
        
        # 酒店楼层布局
        self.hotel = {
            1: {"name": "大堂", "rooms": ["前台","大堂吧","商务中心","电梯口"],
                "points": {"前台":(2,5),"大堂吧":(8,5),"商务中心":(15,5),"电梯口":(20,5)}},
            3: {"name": "客房3层", "rooms": ["301","302","303","304","305","306","走廊","电梯口","服务间"],
                "points": {"301":(2,2),"302":(6,2),"303":(10,2),"304":(14,2),
                           "305":(2,8),"306":(6,8),"走廊":(10,5),"电梯口":(20,5),"服务间":(18,8)}},
            5: {"name": "客房5层", "rooms": ["501","502","503","504","505","走廊","电梯口","服务间"],
                "points": {"501":(2,2),"502":(6,2),"503":(10,2),"504":(14,2),
                           "505":(2,8),"走廊":(10,5),"电梯口":(20,5),"服务间":(18,8)}},
            7: {"name": "行政层", "rooms": ["701套房","702套房","行政酒廊","电梯口"],
                "points": {"701套房":(2,5),"702套房":(10,5),"行政酒廊":(15,8),"电梯口":(20,5)}},
        }
        self.elevator_wait = 30  # 电梯等待时间
        self.nav_speed = 0.8     # 导航速度

    def create_delivery_task(self, room, item, guest_name="客人"):
        """创建配送任务"""
        floor = int(room[0])  # 房间号第一位是楼层
        if floor not in self.hotel:
            return None
        return {
            "id": f"D{random.randint(1000,9999)}",
            "type": "delivery",
            "item": item,
            "room": room,
            "floor": floor,
            "guest": guest_name,
            "status": "pending",
        }

    def execute_delivery(self, task):
        """执行配送任务"""
        log = []
        target_floor = task["floor"]
        target_room = task["room"]
        
        # Step 1: 取物品
        log.append(f"📦 取{task['item']}从服务间")
        self.state = "picking"
        
        # Step 2: 导航到电梯
        if self.position["floor"] != target_floor:
            log.append(f"🛗 导航到电梯 (当前{self.position['floor']}F→目标{target_floor}F)")
            self.state = "to_elevator"
            log.append(f"   等待电梯 {self.elevator_wait}秒")
            log.append(f"   乘电梯到{target_floor}F")
            self.position["floor"] = target_floor
            self.battery -= 3
        
        # Step 3: 导航到房间
        log.append(f"🗺️ 导航到房间{target_room}")
        self.state = "navigating"
        self.battery -= 5
        self.position["x"] = self.hotel[target_floor]["points"].get(target_room, (10,5))[0]
        self.position["y"] = self.hotel[target_floor]["points"].get(target_room, (10,5))[1]
        
        # Step 4: 通知客人
        log.append(f"📞 拨打房间电话通知{task['guest']}")
        self.state = "notifying"
        
        # Step 5: 等待开门
        log.append(f"⏳ 等待客人开门...")
        self.state = "waiting"
        wait_time = random.randint(5, 60)
        log.append(f"   等待了{wait_time}秒")
        
        # Step 6: 递送
        log.append(f"🤲 递送{task['item']}给{task['guest']}")
        self.state = "delivering"
        
        # Step 7: 确认
        log.append(f"✅ {task['item']}已送达{target_room}")
        self.state = "idle"
        self.completed_tasks += 1
        self.battery -= 2
        
        return {"success": True, "log": log, "battery": round(self.battery, 1)}

robot = HotelDeliveryRobot()
print("酒店配送机器人模拟")
print("=" * 55)

# 模拟多个配送任务
tasks = [
    robot.create_delivery_task("305", "毛巾", "张先生"),
    robot.create_delivery_task("503", "外卖", "李女士"),
    robot.create_delivery_task("701", "红酒", "王总"),
]

for task in tasks:
    print(f"\n📋 任务{task['id']}: {task['item']} → {task['room']} ({task['guest']})")
    result = robot.execute_delivery(task)
    for entry in result["log"]:
        print(f"  {entry}")
    print(f"  电量: {result['battery']}%")

print(f"\n📊 完成{robot.completed_tasks}个任务, 剩余电量{robot.battery:.1f}%")
print("✅ 酒店配送验证通过")
✅ 验证通过 酒店配送机器人模拟 ======================================================= 📋 任务D3583: 毛巾 → 305 (张先生) 📦 取毛巾从服务间 🛗 导航到电梯 (当前1F→目标3F) 等待电梯 30秒 乘电梯到3F 🗺️ 导航到房间305 📞 拨打房间电话通知张先生 ⏳ 等待客人开门... 等待了22秒 🤲 递送毛巾给张先生 ✅ 毛巾已送达305 电量: 90% 📋 任务D7005: 外卖 → 503 (李女士) 📦 取外卖从服务间 🛗 导航到电梯 (当前3F→目标5F) 等待电梯 30秒 乘电梯到5F 🗺️ 导航到房间503 📞 拨打房间电话通知李女士 ⏳ 等待客人开门... 等待了44秒 🤲 递送外卖给李女士 ✅ 外卖已送达503 电量: 80% 📋 任务D5264: 红酒 → 701 (王总) 📦 取红酒从服务间 🛗 导航到电梯 (当前5F→目标7F) 等待电梯 30秒 乘电梯到7F 🗺️ 导航到房间701 📞 拨打房间电话通知王总 ⏳ 等待客人开门... 等待了30秒 🤲 递送红酒给王总 ✅ 红酒已送达701 电量: 70% 📊 完成3个任务, 剩余电量70.0% ✅ 酒店配送验证通过

📌 任务队列与调度

class HotelTaskQueue:
    """酒店任务队列管理"""
    def __init__(self):
        self.queue = []
        self.priority_map = {
            "VIP": 5, "行政层": 4, "普通配送": 2, "回收": 1
        }

    def add_task(self, room, item, guest="", floor=1, category="普通配送"):
        priority = self.priority_map.get(category, 2)
        # 紧急度加成
        import time
        self.queue.append({
            "room": room, "item": item, "guest": guest,
            "floor": floor, "category": category, "priority": priority,
            "create_time": time.time(), "status": "pending"
        })

    def schedule(self, robot_floor=1):
        """按楼层聚类+优先级排序"""
        floor_groups = {}
        for task in self.queue:
            floor_groups.setdefault(task["floor"], []).append(task)
        
        for f in floor_groups:
            floor_groups[f].sort(key=lambda t: (-t["priority"], t["create_time"]))
        
        # 选择最近楼层的任务开始
        available_floors = sorted(floor_groups.keys(), key=lambda f: abs(f - robot_floor))
        
        scheduled = []
        for floor in available_floors:
            scheduled.extend(floor_groups[floor])
        return scheduled

    def batch_by_floor(self, tasks):
        """按楼层批量处理"""
        batches = {}
        for t in tasks:
            batches.setdefault(t["floor"], []).append(t)
        return batches

queue = HotelTaskQueue()
queue.add_task("301", "牙刷", "赵先生", 3, "普通配送")
queue.add_task("505", "行李", "刘总", 5, "VIP")
queue.add_task("305", "外卖", "陈女士", 3, "普通配送")
queue.add_task("701", "果盘", "周总", 7, "行政层")
queue.add_task("503", "充电器", "吴先生", 5, "普通配送")
queue.add_task("302", "毛巾", "郑女士", 3, "普通配送")

scheduled = queue.schedule(robot_floor=1)
batches = queue.batch_by_floor(scheduled)

print("酒店任务队列管理")
print("=" * 55)
print("\n📋 调度顺序:")
for i, t in enumerate(scheduled):
    print(f"  {i+1}. {t['room']} {t['item']}({t['category']}) → {t['guest']} P{t['priority']}")

print(f"\n📋 按楼层批量:")
for floor, tasks in sorted(batches.items()):
    items = ", ".join(f"{t['room']}-{t['item']}" for t in tasks)
    print(f"  {floor}F: {items}")

print("\n✅ 任务调度验证通过")
✅ 验证通过 酒店任务队列管理 ======================================================= 📋 调度顺序: 1. 301 牙刷(普通配送) → 赵先生 P2 2. 305 外卖(普通配送) → 陈女士 P2 3. 302 毛巾(普通配送) → 郑女士 P2 4. 505 行李(VIP) → 刘总 P5 5. 503 充电器(普通配送) → 吴先生 P2 6. 701 果盘(行政层) → 周总 P4 📋 按楼层批量: 3F: 301-牙刷, 305-外卖, 302-毛巾 5F: 505-行李, 503-充电器 7F: 701-果盘 ✅ 任务调度验证通过

📌 紧急情况处理

class HotelEmergencyHandler:
    """酒店紧急情况处理"""
    def __init__(self):
        self.emergencies = {
            "fire_alarm": {
                "action": "停止所有配送,导航到安全出口,语音引导疏散",
                "priority": "critical",
                "notify": ["前台","安保","119"]
            },
            "guest_medical": {
                "action": "导航到房间,拨打120,引导医护到房间",
                "priority": "critical",
                "notify": ["前台","120","值班经理"]
            },
            "elevator_breakdown": {
                "action": "停止使用电梯,转楼梯配送,通知工程部",
                "priority": "high",
                "notify": ["工程部","前台"]
            },
            "robot_stuck": {
                "action": "尝试脱困3次,失败后通知前台人工处理",
                "priority": "medium",
                "notify": ["前台","工程部"]
            },
            "low_battery": {
                "action": "完成当前任务后返回充电,调配其他机器人",
                "priority": "medium",
                "notify": ["调度中心"]
            },
        }
        self.current_state = "normal"

    def handle(self, emergency_type, context=None):
        self.current_state = "emergency"
        info = self.emergencies.get(emergency_type)
        if not info:
            return {"handled": False, "reason": "未知紧急类型"}

        print(f"\n🚨 紧急事件: {emergency_type}")
        print(f"   优先级: {info['priority']}")
        print(f"   行动: {info['action']}")
        print(f"   通知: {', '.join(info['notify'])}")

        # 模拟处理
        steps = info["action"].split(",")
        for i, step in enumerate(steps):
            print(f"   步骤{i+1}: {step.strip()}")

        self.current_state = "normal"
        return {"handled": True, "steps": len(steps)}

handler = HotelEmergencyHandler()
print("酒店紧急情况处理")
print("=" * 55)
handler.handle("fire_alarm")
handler.handle("guest_medical", {"room": "503"})
handler.handle("robot_stuck")

print("\n✅ 紧急处理验证通过")
✅ 验证通过 酒店紧急情况处理 ======================================================= 🚨 紧急事件: fire_alarm 优先级: critical 行动: 停止所有配送,导航到安全出口,语音引导疏散 通知: 前台, 安保, 119 步骤1: 停止所有配送 步骤2: 导航到安全出口 步骤3: 语音引导疏散 🚨 紧急事件: guest_medical 优先级: critical 行动: 导航到房间,拨打120,引导医护到房间 通知: 前台, 120, 值班经理 步骤1: 导航到房间 步骤2: 拨打120 步骤3: 引导医护到房间 🚨 紧急事件: robot_stuck 优先级: medium 行动: 尝试脱困3次,失败后通知前台人工处理 通知: 前台, 工程部 步骤1: 尝试脱困3次 步骤2: 失败后通知前台人工处理 ✅ 紧急处理验证通过

📌 酒店场景特殊挑战

⚠️ 特殊挑战与解决方案

挑战描述方案
地毯摩擦力大,轮式机器人打滑麦克纳姆轮+防滑算法
窄走廊与客人/推车会车困难靠右行驶+避让策略
多电梯不同电梯协议不同通用适配层+降级方案
客房电话需要电话系统对接VOIP接口+备用敲门
隐私不能进入客房门口递送+不拍摄客房内

📌 练习

📝 练习 1

实现多机协同配送:2台机器人同时服务不同楼层,电梯协调使用。

📝 练习 2

设计夜间服务模式:22:00后降低音量、减速运行、仅响应紧急配送。

📝 练习 3

实现配送质量评估:统计配送时长、成功率、客人满意度,自动生成日报。

📌 成就

🏆 本课成就

◀ 上一课 📚 目录 下一课 ▶