package main import ( "fmt" "math" "sync" "time" "encoding/json" "github.com/streadway/amqp" // RabbitMQ 消息队列 ) // RobotTask 定义机器人任务结构 type RobotTask struct { TaskID string `json:"task_id"` TaskType string `json:"task_type"` // "welcome", "coffee", "tea", "dessert", "delivery" Priority int `json:"priority"` EstDuration float64 `json:"est_duration"` // 预估执行时间(分钟) AssignedTo string `json:"assigned_to"` // 分配给的机器人 ID Status string `json:"status"` // "pending", "executing", "completed", "failed" Parameters map[string]interface{} `json:"parameters"` // 任务参数 CreatedAt time.Time `json:"created_at"` Deadline time.Time `json:"deadline"` // 截止时间 } // RobotInfo 机器人信息 type RobotInfo struct { RobotID string `json:"robot_id"` Brand string `json:"brand"` // 品牌:Leju, Haoyin, Qianxun, Yinhe Capabilities []string `json:"capabilities"` // 能力列表 BatteryLevel float64 `json:"battery_level"` // 电量(百分比) CurrentTask *RobotTask `json:"current_task"` Position Position `json:"position"` // 当前位置坐标 Status string `json:"status"` // "idle", "busy", "charging", "error" LastHeartbeat time.Time `json:"last_heartbeat"` // 最后心跳时间 } // Position 位置坐标 type Position struct { X float64 `json:"x"` Y float64 `json:"y"` Z float64 `json:"z"` // 三维空间中的高度 } // UnifiedScheduler 统一调度器 type UnifiedScheduler struct { robots map[string]*RobotInfo taskQueue chan *RobotTask completedQueue chan *RobotTask mu sync.RWMutex brandAdapters map[string]BrandAdapter mqConn *amqp.Connection mqChannel *amqp.Channel config SchedulerConfig } // BrandAdapter 品牌适配器接口 type BrandAdapter interface { // 发送命令到机器人 SendCommand(robotID string, cmd Command) error // 获取机器人状态 GetStatus(robotID string) (RobotStatus, error) // 注册机器人到系统 RegisterRobot(robotInfo RobotInfo) error // 心跳检测 HeartbeatCheck(robotID string) bool } // Command 统一命令结构 type Command struct { CmdType string `json:"cmd_type"` RobotID string `json:"robot_id"` TaskID string `json:"task_id"` Parameters map[string]interface{} `json:"parameters"` Timestamp time.Time `json:"timestamp"` } // RobotStatus 机器人状态 type RobotStatus struct { RobotID string `json:"robot_id"` IsBusy bool `json:"is_busy"` Battery float64 `json:"battery"` // 电量百分比 Position Position `json:"position"` CurrentTask string `json:"current_task"` TaskProgress float64 `json:"task_progress"` // 任务进度(0-100) ErrorCode int `json:"error_code"` // 错误码,0 表示正常 ErrorMsg string `json:"error_msg"` // 错误信息 Timestamp time.Time `json:"timestamp"` } // SchedulerConfig 调度器配置 type SchedulerConfig struct { MaxRobots int `json:"max_robots"` TaskQueueSize int `json:"task_queue_size"` HeartbeatInterval int `json:"heartbeat_interval"` // 心跳间隔(秒) TimeoutSeconds int `json:"timeout_seconds"` // 任务超时时间 OptimizationAlgorithm string `json:"optimization_algorithm"` // "hungarian", "rl", "hybrid" LogLevel string `json:"log_level"` // "debug", "info", "warn", "error" } // NewUnifiedScheduler 创建调度器实例 func NewUnifiedScheduler(config SchedulerConfig) (*UnifiedScheduler, error) { scheduler := &UnifiedScheduler{ robots: make(map[string]*RobotInfo), taskQueue: make(chan *RobotTask, config.TaskQueueSize), completedQueue: make(chan *RobotTask, config.TaskQueueSize), brandAdapters: make(map[string]BrandAdapter), config: config, } // 初始化消息队列 err := scheduler.initMessageQueue() if err != nil { return nil, fmt.Errorf("初始化消息队列失败:%v", err) } // 启动后台任务 go scheduler.monitorRobots() go scheduler.processTasks() go scheduler.handleCompletedTasks() return scheduler, nil } // initMessageQueue 初始化消息队列 func (s *UnifiedScheduler) initMessageQueue() error { conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/") if err != nil { return err } ch, err := conn.Channel() if err != nil { conn.Close() return err } // 声明交换机和队列 err = ch.ExchangeDeclare( "robot.scheduler", // 交换机名称 "topic", // 交换机类型 true, // 持久化 false, // 自动删除 false, // 内部 false, // 等待 nil, ) if err != nil { ch.Close() conn.Close() return err } s.mqConn = conn s.mqChannel = ch return nil } // RegisterBrandAdapter 注册品牌适配器 func (s *UnifiedScheduler) RegisterBrandAdapter(brand string, adapter BrandAdapter) { s.mu.Lock() defer s.mu.Unlock() s.brandAdapters[brand] = adapter } // AddRobot 添加机器人到系统 func (s *UnifiedScheduler) AddRobot(robot *RobotInfo) error { s.mu.Lock() defer s.mu.Unlock() if len(s.robots) >= s.config.MaxRobots { return fmt.Errorf("已达到最大机器人数量限制:%d", s.config.MaxRobots) } // 验证品牌适配器是否存在 adapter, ok := s.brandAdapters[robot.Brand] if !ok { return fmt.Errorf("未找到品牌适配器:%s", robot.Brand) } // 注册机器人到适配器 err := adapter.RegisterRobot(*robot) if err != nil { return fmt.Errorf("注册机器人失败:%v", err) } robot.Status = "idle" robot.LastHeartbeat = time.Now() s.robots[robot.RobotID] = robot // 发送注册成功消息 s.publishEvent("robot.registered", map[string]interface{}{ "robot_id": robot.RobotID, "brand": robot.Brand, "time": time.Now(), }) return nil } // SubmitTask 提交新任务 func (s *UnifiedScheduler) SubmitTask(task *RobotTask) error { task.CreatedAt = time.Now() task.Status = "pending" // 设置默认截止时间(如果未提供) if task.Deadline.IsZero() { task.Deadline = time.Now().Add(time.Duration(task.EstDuration*1.5) * time.Minute) } select { case s.taskQueue <- task: s.publishEvent("task.submitted", map[string]interface{}{ "task_id": task.TaskID, "type": task.TaskType, "time": time.Now(), }) return nil default: return fmt.Errorf("任务队列已满") } } // processTasks 处理任务分配 func (s *UnifiedScheduler) processTasks() { for task := range s.taskQueue { go s.assignTask(task) } } // assignTask 分配任务给合适的机器人 func (s *UnifiedScheduler) assignTask(task *RobotTask) { s.mu.RLock() // 第一步:筛选符合条件的机器人 candidates := make([]*RobotInfo, 0) for _, robot := range s.robots { if robot.Status == "idle" && contains(robot.Capabilities, task.TaskType) && robot.BatteryLevel > 20.0 { candidates = append(candidates, robot) } } s.mu.RUnlock() if len(candidates) == 0 { task.Status = "failed" task.AssignedTo = "" s.publishEvent("task.failed", map[string]interface{}{ "task_id": task.TaskID, "reason": "无可用机器人", "time": time.Now(), }) return } // 第二步:基于匈牙利算法的最优匹配 bestRobot := s.findOptimalRobot(task, candidates) if bestRobot == nil { task.Status = "failed" task.AssignedTo = "" s.publishEvent("task.failed", map[string]interface{}{ "task_id": task.TaskID, "reason": "匹配算法失败", "time": time.Now(), }) return }