Terrain walking

本文针对行走抖动问题提供了解决方案,包括调整地图高度差、优化插值算法及采用高度变化阈值策略等,确保行走过程流畅。

需要注意到几个问题

1. 如果行走时出现抖动,那么可能是地图高度差太大,也就是忽高忽低。

2. 插值不够狠,多几次,使地图变得smooth一些

3. 当高度差改变一定值时在更新当前高度,比如至少改变1.0时才更新,比如前一次的高度是2.0, 现在的高度是1.5,那么差是0.5,太小,不做改变,当前高度仍保持为2.0,但是差要累加。当累加值超过1.0时,再改变。比如前一次高度是2.0, 此次高度是1.5,不改变,但是差是0.5,如果下一次高度是1.0,则累加差是1.0,所以改变高度。也就是掠过了中间1.5的改变,这样不会抖动。

做mujoco原生渲染#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 人形机器人仿真完整演示 - 场景设置修复版 """ import sys import os import time import json import numpy as np import matplotlib.pyplot as plt from typing import Dict, List, Tuple import threading import argparse import mujoco # 导入自定义模块 from mujoco_simulation import HumanoidRobot from advanced_control import ( IntelligentDecisionSystem, PathPlanner, EnergyOptimizer, AdaptiveController, EnvironmentState, RobotState, TaskType, TerrainType ) class HumanoidDemo: """人形机器人仿真演示类""" def __init__(self): """初始化演示系统""" print("🤖 人形机器人仿真演示系统") print("=" * 60) # 创建人形机器人 self.robot = HumanoidRobot() # 创建高级控制模块 self.decision_system = IntelligentDecisionSystem() self.path_planner = PathPlanner() self.energy_optimizer = EnergyOptimizer() self.adaptive_controller = AdaptiveController() # 演示配置 self.demo_config = { 'duration': 30.0, 'enable_ai': True, 'enable_optimization': True, 'enable_adaptation': True, 'record_data': True, 'save_video': True } # 演示数据 self.demo_data = { 'timestamps': [], 'robot_states': [], 'environment_states': [], 'decisions': [], 'energy_consumption': [], 'performance_metrics': [] } print("✅ 演示系统初始化完成") def setup_demo_scenario(self, scenario_type: str = "comprehensive"): """设置演示场景""" scenarios = { "comprehensive": self._setup_comprehensive_scenario, "walking": self._setup_walking_scenario, "obstacle": self._setup_obstacle_scenario, "terrain": self._setup_terrain_scenario, "interference": self._setup_interference_scenario } if scenario_type in scenarios: print(f"🎬 设置 {scenario_type} 演示场景...") scenarios[scenario_type]() else: print(f"⚠️ 未知场景类型: {scenario_type},使用综合场景") self._setup_comprehensive_scenario() def _setup_comprehensive_scenario(self): """设置综合演示场景""" self.scenario_timeline = [ [0, 5, "walking", "平地行走"], [5, 10, "obstacle", "动态避障"], [10, 15, "terrain", "斜坡行走"], [15, 20, "terrain", "楼梯攀爬"], [20, 25, "interference", "风力干扰"], [25, 30, "walking", "恢复行走"] ] self.environment_config = { 'obstacles': [ {'position': [2, 0, 0.5], 'radius': 0.3, 'type': 'static'}, {'position': [4, 1, 0.3], 'radius': 0.3, 'type': 'dynamic'}, {'position': [6, -1, 0.4], 'radius': 0.2, 'type': 'moving'} ], 'terrain_sequence': ['flat', 'slope', 'stairs', 'sand', 'flat'], 'wind_patterns': [ {'time': [20, 25], 'force': [50, 0, 0], 'type': 'gust'}, {'time': [25, 30], 'force': [20, 10, 0], 'type': 'steady'} ], 'light_patterns': [ {'time': [22, 24], 'intensity': 0.2, 'type': 'dim'}, {'time': [24, 26], 'intensity': 0.9, 'type': 'bright'} ] } def _setup_walking_scenario(self): """设置行走演示场景""" self.scenario_timeline = [ [0, 10, "walking", "基础行走"], [10, 20, "walking", "快速行走"], [20, 30, "walking", "慢速行走"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [], 'light_patterns': [] } # 添加缺失的场景设置方法 def _setup_obstacle_scenario(self): """设置避障演示场景""" self.scenario_timeline = [ [0, 10, "obstacle", "静态障碍物"], [10, 20, "obstacle", "动态障碍物"], [20, 30, "obstacle", "复杂障碍物"] ] self.environment_config = { 'obstacles': [ {'position': [1, 0, 0.5], 'radius': 0.3, 'type': 'static'}, {'position': [3, 0, 0.3], 'radius': 0.2, 'type': 'dynamic'}, {'position': [5, 0, 0.4], 'radius': 0.25, 'type': 'moving'} ], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [], 'light_patterns': [] } def _setup_terrain_scenario(self): """设置地形演示场景""" self.scenario_timeline = [ [0, 6, "terrain", "平地"], [6, 12, "terrain", "斜坡"], [12, 18, "terrain", "楼梯"], [18, 24, "terrain", "沙地"], [24, 30, "terrain", "平地"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat', 'slope', 'stairs', 'sand', 'flat'], 'wind_patterns': [], 'light_patterns': [] } def _setup_interference_scenario(self): """设置干扰演示场景""" self.scenario_timeline = [ [0, 10, "walking", "正常行走"], [10, 20, "interference", "风力干扰"], [20, 30, "interference", "光照干扰"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [ {'time': [10, 20], 'force': [80, 0, 0], 'type': 'strong_wind'} ], 'light_patterns': [ {'time': [20, 30], 'intensity': 0.1, 'type': 'low_light'} ] } # 添加 get_current_scenario_state 方法 def get_current_scenario_state(self, current_time: float) -> Dict: """获取当前场景状态""" current_task = "idle" task_description = "待机" # 确定当前任务 for start_time, end_time, task, description in self.scenario_timeline: if start_time <= current_time < end_time: current_task = task task_description = description break # 确定当前地形 terrain_index = min(int(current_time / 6), len(self.environment_config['terrain_sequence']) - 1) current_terrain = self.environment_config['terrain_sequence'][terrain_index] # 计算当前风力 current_wind = np.zeros(3) for wind_pattern in self.environment_config['wind_patterns']: if wind_pattern['time'][0] <= current_time < wind_pattern['time'][1]: current_wind = np.array(wind_pattern['force']) break # 计算当前光照 current_light = 1.0 for light_pattern in self.environment_config['light_patterns']: if light_pattern['time'][0] <= current_time < light_pattern['time'][1]: current_light = light_pattern['intensity'] break return { 'task': current_task, 'description': task_description, 'terrain': current_terrain, 'wind': current_wind, 'light': current_light, 'obstacles': self.environment_config['obstacles'].copy(), 'time': current_time } def run_demo(self): """运行演示""" print(f"🚀 开始演示,持续时间: {self.demo_config['duration']}秒") print("=" * 60) try: start_time = time.time() while time.time() - start_time < self.demo_config['duration']: current_time = time.time() - start_time # 获取当前场景状态 scenario_state = self.get_current_scenario_state(current_time) # 打印状态信息 print(f"⏱️ {current_time:5.1f}s | " f"任务: {scenario_state['description']:8s} | " f"地形: {scenario_state['terrain']:6s}") # 模拟时间步进 time.sleep(0.1) print("\n✅ 演示完成!") except KeyboardInterrupt: print("\n⏹️ 演示被用户中断") def main(): """主函数""" parser = argparse.ArgumentParser(description='人形机器人仿真演示') parser.add_argument('--scenario', type=str, default='comprehensive', choices=['comprehensive', 'walking', 'obstacle', 'terrain', 'interference'], help='演示场景类型') parser.add_argument('--duration', type=float, default=30.0, help='演示持续时间(秒)') args = parser.parse_args() # 创建演示实例 demo = HumanoidDemo() demo.demo_config['duration'] = args.duration # 设置场景 demo.setup_demo_scenario(args.scenario) # 运行演示 demo.run_demo() if __name__ == "__main__": main()
07-29
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 人形机器人仿真比赛系统 符合科目一比赛要求的完整仿真系统 包含:双足行走、动态避障、智能决策、能耗优化 """ import sys import os import time import json import numpy as np import matplotlib.pyplot as plt from typing import Dict, List, Tuple, Optional, Any import threading import argparse import mujoco import pygame from pygame.locals import * import math import cv2 from PIL import Image import io import traceback import subprocess import ctypes import glfw from enum import Enum from dataclasses import dataclass import logging # 设置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # 设置环境变量 os.environ['MUJOCO_GL'] = 'glfw' class TaskType(Enum): """任务类型枚举""" WALKING = "walking" SLOPE_WALKING = "slope_walking" STAIR_CLIMBING = "stair_climbing" OBSTACLE_AVOIDANCE = "obstacle_avoidance" SAND_WALKING = "sand_walking" DYNAMIC_AVOIDANCE = "dynamic_avoidance" INTERFERENCE_RESPONSE = "interference_response" class TerrainType(Enum): """地形类型枚举""" FLAT = "flat" SLOPE = "slope" STAIRS = "stairs" SAND = "sand" OBSTACLE = "obstacle" class InterferenceType(Enum): """干扰类型枚举""" WIND = "wind" BRIGHT_LIGHT = "bright_light" NOISE = "noise" @dataclass class PerformanceMetrics: """性能指标数据类""" task_completion_rate: float = 0.0 energy_efficiency: float = 0.0 stability_score: float = 0.0 response_time: float = 0.0 obstacle_avoidance_rate: float = 0.0 terrain_adaptation_score: float = 0.0 class HumanoidRobot: """人形机器人核心类""" def __init__(self): self.model = None self.data = None self.viewer = None self.joint_names = [] self.sensor_names = [] self.control_gains = { 'kp': 100.0, 'ki': 10.0, 'kd': 20.0 } self.energy_consumption = 0.0 self.stability_metrics = { 'com_height': 0.0, 'com_velocity': 0.0, 'foot_contact': [False, False] } def load_model(self, model_path: str): """加载机器人模型""" try: self.model = mujoco.MjModel.from_xml_path(model_path) self.data = mujoco.MjData(self.model) self.joint_names = [self.model.joint(i).name for i in range(self.model.njnt)] self.sensor_names = [self.model.sensor(i).name for i in range(self.model.nsensor)] logger.info(f"✅ 成功加载模型: {model_path}") logger.info(f"关节数量: {self.model.njnt}") logger.info(f"传感器数量: {self.model.nsensor}") return True except Exception as e: logger.error(f"❌ 模型加载失败: {e}") return False def get_joint_positions(self) -> np.ndarray: """获取关节位置""" return self.data.qpos[:self.model.nq].copy() def get_joint_velocities(self) -> np.ndarray: """获取关节速度""" return self.data.qvel[:self.model.nv].copy() def set_joint_targets(self, targets: np.ndarray): """设置关节目标位置""" if len(targets) == self.model.nu: self.data.ctrl[:] = targets def compute_pid_control(self, target_pos: np.ndarray, current_pos: np.ndarray, current_vel: np.ndarray, dt: float) -> np.ndarray: """PID控制器""" error = target_pos - current_pos integral = getattr(self, '_integral', np.zeros_like(error)) integral += error * dt derivative = (error - getattr(self, '_prev_error', np.zeros_like(error))) / dt control = (self.control_gains['kp'] * error + self.control_gains['ki'] * integral + self.control_gains['kd'] * derivative) self._integral = integral self._prev_error = error return control def update_stability_metrics(self): """更新稳定性指标""" # 计算质心高度 com_pos = self.data.xpos[self.model.body('torso').id] self.stability_metrics['com_height'] = com_pos[2] # 计算质心速度 com_vel = self.data.qvel[:3] self.stability_metrics['com_velocity'] = np.linalg.norm(com_vel) # 检测足底接触 for i, foot_name in enumerate(['left_foot', 'right_foot']): try: foot_id = self.model.body(foot_name).id contact_force = np.linalg.norm(self.data.xfrc_applied[foot_id]) self.stability_metrics['foot_contact'][i] = contact_force > 0.1 except: self.stability_metrics['foot_contact'][i] = False def step(self, dt: float): """仿真步进""" mujoco.mj_step(self.model, self.data) self.update_stability_metrics() # 计算能耗 joint_torques = np.abs(self.data.ctrl) self.energy_consumption += np.sum(joint_torques) * dt class IntelligentDecisionSystem: """智能决策系统""" def __init__(self): self.decision_weights = { 'safety': 0.4, 'efficiency': 0.3, 'energy': 0.2, 'comfort': 0.1 } self.current_task = TaskType.WALKING self.task_priority = { TaskType.INTERFERENCE_RESPONSE: 1, TaskType.DYNAMIC_AVOIDANCE: 2, TaskType.OBSTACLE_AVOIDANCE: 3, TaskType.STAIR_CLIMBING: 4, TaskType.SLOPE_WALKING: 5, TaskType.SAND_WALKING: 6, TaskType.WALKING: 7 } def evaluate_environment(self, robot_state: Dict, env_state: Dict) -> Dict[str, float]: """评估环境状态""" scores = {} # 安全性评估 safety_score = 1.0 if 'obstacles' in env_state: min_distance = min([obs['distance'] for obs in env_state['obstacles']], default=float('inf')) safety_score = min(1.0, min_distance / 2.0) scores['safety'] = safety_score # 效率评估 terrain_type = env_state.get('terrain_type', TerrainType.FLAT) terrain_efficiency = { TerrainType.FLAT: 1.0, TerrainType.SLOPE: 0.8, TerrainType.STAIRS: 0.6, TerrainType.SAND: 0.7, TerrainType.OBSTACLE: 0.5 } scores['efficiency'] = terrain_efficiency.get(terrain_type, 1.0) # 能耗评估 energy_score = 1.0 - (robot_state.get('energy_consumption', 0.0) / 1000.0) scores['energy'] = max(0.0, energy_score) # 舒适度评估 interference_level = env_state.get('interference_level', 0.0) comfort_score = 1.0 - interference_level scores['comfort'] = max(0.0, comfort_score) return scores def make_decision(self, robot_state: Dict, env_state: Dict) -> TaskType: """智能决策""" # 环境评估 env_scores = self.evaluate_environment(robot_state, env_state) # 综合得分计算 total_score = sum(self.decision_weights[key] * env_scores[key] for key in self.decision_weights) # 基于规则的决策 if env_scores['safety'] < 0.3: return TaskType.INTERFERENCE_RESPONSE elif env_state.get('interference_level', 0.0) > 0.7: return TaskType.INTERFERENCE_RESPONSE elif len(env_state.get('obstacles', [])) > 0: return TaskType.DYNAMIC_AVOIDANCE elif env_state.get('terrain_type') == TerrainType.STAIRS: return TaskType.STAIR_CLIMBING elif env_state.get('terrain_type') == TerrainType.SLOPE: return TaskType.SLOPE_WALKING elif env_state.get('terrain_type') == TerrainType.SAND: return TaskType.SAND_WALKING elif total_score > 0.7: return TaskType.WALKING else: return TaskType.WALKING class PathPlanner: """路径规划器""" def __init__(self): self.grid_size = 0.1 self.obstacle_margin = 0.3 def a_star_pathfinding(self, start: np.ndarray, goal: np.ndarray, obstacles: List[Dict], terrain_map: Dict) -> List[np.ndarray]: """A*路径规划算法""" # 简化的A*实现 path = [start] current = start while np.linalg.norm(current - goal) > 0.1: # 计算到目标的方向 direction = (goal - current) / np.linalg.norm(goal - current) # 检查是否有障碍物 next_pos = current + direction * self.grid_size # 避障逻辑 for obstacle in obstacles: if np.linalg.norm(next_pos - obstacle['position']) < obstacle['radius'] + self.obstacle_margin: # 计算避障方向 avoid_direction = self._calculate_avoid_direction(current, obstacle) next_pos = current + avoid_direction * self.grid_size break path.append(next_pos) current = next_pos # 防止无限循环 if len(path) > 1000: break return path def _calculate_avoid_direction(self, robot_pos: np.ndarray, obstacle: Dict) -> np.ndarray: """计算避障方向""" to_obstacle = obstacle['position'] - robot_pos perpendicular = np.array([-to_obstacle[1], to_obstacle[0], 0]) return perpendicular / np.linalg.norm(perpendicular) class EnergyOptimizer: """能耗优化器""" def __init__(self): self.energy_history = [] self.optimization_strategies = { 'gait_optimization': True, 'trajectory_smoothing': True, 'adaptive_control': True } def optimize_gait(self, robot_state: Dict) -> Dict[str, float]: """步态优化""" # 基于当前状态的步态参数优化 com_height = robot_state.get('com_height', 0.8) com_velocity = robot_state.get('com_velocity', 0.0) # 动态调整步长和步频 optimal_step_length = min(0.3, com_velocity * 0.5) optimal_step_frequency = max(1.0, com_velocity * 2.0) return { 'step_length': optimal_step_length, 'step_frequency': optimal_step_frequency, 'com_height': com_height } def smooth_trajectory(self, trajectory: List[np.ndarray]) -> List[np.ndarray]: """轨迹平滑""" if len(trajectory) < 3: return trajectory smoothed = [trajectory[0]] for i in range(1, len(trajectory) - 1): # 简单的移动平均平滑 smoothed_point = (trajectory[i - 1] + trajectory[i] + trajectory[i + 1]) / 3 smoothed.append(smoothed_point) smoothed.append(trajectory[-1]) return smoothed def update_energy_history(self, energy_consumption: float): """更新能耗历史""" self.energy_history.append(energy_consumption) if len(self.energy_history) > 1000: self.energy_history.pop(0) class CompetitionSimulation: """比赛仿真主类""" def __init__(self): self.robot = HumanoidRobot() self.decision_system = IntelligentDecisionSystem() self.path_planner = PathPlanner() self.energy_optimizer = EnergyOptimizer() self.performance_metrics = PerformanceMetrics() # 仿真参数 self.dt = 0.01 self.simulation_time = 0.0 self.max_simulation_time = 60.0 # 60秒仿真 # 场景状态 self.current_scenario = "comprehensive" self.scenario_state = {} self.task_history = [] # 性能记录 self.performance_data = { 'time': [], 'energy': [], 'stability': [], 'task_completion': [] } def setup_scenario(self, scenario_type: str = "comprehensive"): """设置仿真场景""" self.current_scenario = scenario_type if scenario_type == "comprehensive": self._setup_comprehensive_scenario() elif scenario_type == "basic_tasks": self._setup_basic_tasks_scenario() elif scenario_type == "advanced_tasks": self._setup_advanced_tasks_scenario() else: self._setup_comprehensive_scenario() def _setup_comprehensive_scenario(self): """设置综合场景""" self.scenario_state = { 'terrain_sequence': [ {'type': TerrainType.FLAT, 'duration': 10.0}, {'type': TerrainType.SLOPE, 'duration': 15.0}, {'type': TerrainType.STAIRS, 'duration': 20.0}, {'type': TerrainType.SAND, 'duration': 10.0}, {'type': TerrainType.FLAT, 'duration': 5.0} ], 'obstacles': [ {'position': np.array([2.0, 0.0, 0.0]), 'radius': 0.3, 'type': 'static'}, {'position': np.array([4.0, 1.0, 0.0]), 'radius': 0.2, 'type': 'dynamic'}, {'position': np.array([6.0, -1.0, 0.0]), 'radius': 0.4, 'type': 'static'} ], 'interferences': [ {'type': InterferenceType.WIND, 'start_time': 25.0, 'duration': 5.0}, {'type': InterferenceType.BRIGHT_LIGHT, 'start_time': 35.0, 'duration': 3.0} ], 'current_terrain_index': 0, 'current_terrain_time': 0.0 } def _setup_basic_tasks_scenario(self): """设置基础任务场景""" self.scenario_state = { 'terrain_sequence': [ {'type': TerrainType.FLAT, 'duration': 20.0}, {'type': TerrainType.SLOPE, 'duration': 20.0}, {'type': TerrainType.STAIRS, 'duration': 20.0} ], 'obstacles': [], 'interferences': [], 'current_terrain_index': 0, 'current_terrain_time': 0.0 } def _setup_advanced_tasks_scenario(self): """设置进阶任务场景""" self.scenario_state = { 'terrain_sequence': [ {'type': TerrainType.FLAT, 'duration': 10.0}, {'type': TerrainType.SAND, 'duration': 15.0}, {'type': TerrainType.FLAT, 'duration': 10.0} ], 'obstacles': [ {'position': np.array([2.0, 0.0, 0.0]), 'radius': 0.3, 'type': 'static'}, {'position': np.array([4.0, 0.5, 0.0]), 'radius': 0.2, 'type': 'dynamic'}, {'position': np.array([6.0, -0.5, 0.0]), 'radius': 0.3, 'type': 'dynamic'} ], 'interferences': [ {'type': InterferenceType.WIND, 'start_time': 15.0, 'duration': 5.0}, {'type': InterferenceType.BRIGHT_LIGHT, 'start_time': 25.0, 'duration': 5.0} ], 'current_terrain_index': 0, 'current_terrain_time': 0.0 } def update_scenario_state(self): """更新场景状态""" # 更新地形 terrain_info = self.scenario_state['terrain_sequence'][self.scenario_state['current_terrain_index']] self.scenario_state['current_terrain_time'] += self.dt if self.scenario_state['current_terrain_time'] >= terrain_info['duration']: self.scenario_state['current_terrain_index'] += 1 self.scenario_state['current_terrain_time'] = 0.0 if self.scenario_state['current_terrain_index'] >= len(self.scenario_state['terrain_sequence']): self.scenario_state['current_terrain_index'] = 0 # 更新障碍物位置(动态障碍物) for obstacle in self.scenario_state['obstacles']: if obstacle['type'] == 'dynamic': # 简单的圆周运动 angle = self.simulation_time * 0.5 radius = 0.5 obstacle['position'][0] = obstacle['position'][0] + np.cos(angle) * 0.01 obstacle['position'][1] = obstacle['position'][1] + np.sin(angle) * 0.01 # 更新干扰 current_interference_level = 0.0 for interference in self.scenario_state['interferences']: if (interference['start_time'] <= self.simulation_time <= interference['start_time'] + interference['duration']): current_interference_level = 0.8 self.scenario_state['current_terrain'] = terrain_info['type'] self.scenario_state['interference_level'] = current_interference_level def get_robot_state(self) -> Dict: """获取机器人状态""" return { 'joint_positions': self.robot.get_joint_positions(), 'joint_velocities': self.robot.get_joint_velocities(), 'com_height': self.robot.stability_metrics['com_height'], 'com_velocity': self.robot.stability_metrics['com_velocity'], 'foot_contact': self.robot.stability_metrics['foot_contact'], 'energy_consumption': self.robot.energy_consumption } def get_environment_state(self) -> Dict: """获取环境状态""" # 计算机器人到障碍物的距离 robot_pos = self.robot.data.xpos[self.robot.model.body('torso').id] obstacles_with_distance = [] for obstacle in self.scenario_state['obstacles']: distance = np.linalg.norm(robot_pos - obstacle['position']) obstacle_with_distance = obstacle.copy() obstacle_with_distance['distance'] = distance obstacles_with_distance.append(obstacle_with_distance) return { 'terrain_type': self.scenario_state['current_terrain'], 'obstacles': obstacles_with_distance, 'interference_level': self.scenario_state['interference_level'], 'simulation_time': self.simulation_time } def execute_task(self, task_type: TaskType): """执行指定任务""" robot_state = self.get_robot_state() env_state = self.get_environment_state() if task_type == TaskType.WALKING: self._execute_walking_task(robot_state, env_state) elif task_type == TaskType.SLOPE_WALKING: self._execute_slope_walking_task(robot_state, env_state) elif task_type == TaskType.STAIR_CLIMBING: self._execute_stair_climbing_task(robot_state, env_state) elif task_type == TaskType.OBSTACLE_AVOIDANCE: self._execute_obstacle_avoidance_task(robot_state, env_state) elif task_type == TaskType.SAND_WALKING: self._execute_sand_walking_task(robot_state, env_state) elif task_type == TaskType.DYNAMIC_AVOIDANCE: self._execute_dynamic_avoidance_task(robot_state, env_state) elif task_type == TaskType.INTERFERENCE_RESPONSE: self._execute_interference_response_task(robot_state, env_state) def _execute_walking_task(self, robot_state: Dict, env_state: Dict): """执行行走任务""" # 基础双足行走控制 target_positions = self._generate_walking_trajectory(robot_state) current_positions = robot_state['joint_positions'] current_velocities = robot_state['joint_velocities'] control_output = self.robot.compute_pid_control( target_positions, current_positions, current_velocities, self.dt ) self.robot.set_joint_targets(control_output) def _execute_slope_walking_task(self, robot_state: Dict, env_state: Dict): """执行斜坡行走任务""" # 调整步态以适应斜坡 gait_params = self.energy_optimizer.optimize_gait(robot_state) target_positions = self._generate_slope_walking_trajectory(robot_state, gait_params) current_positions = robot_state['joint_positions'] current_velocities = robot_state['joint_velocities'] control_output = self.robot.compute_pid_control( target_positions, current_positions, current_velocities, self.dt ) self.robot.set_joint_targets(control_output) def _execute_stair_climbing_task(self, robot_state: Dict, env_state: Dict): """执行楼梯攀爬任务""" # 楼梯攀爬控制策略 target_positions = self._generate_stair_climbing_trajectory(robot_state) current_positions = robot_state['joint_positions'] current_velocities = robot_state['joint_velocities'] control_output = self.robot.compute_pid_control( target_positions, current_positions, current_velocities, self.dt ) self.robot.set_joint_targets(control_output) def _execute_obstacle_avoidance_task(self, robot_state: Dict, env_state: Dict): """执行障碍物避障任务""" # 路径规划避障 robot_pos = self.robot.data.xpos[self.robot.model.body('torso').id] goal_pos = robot_pos + np.array([1.0, 0.0, 0.0]) # 前进目标 path = self.path_planner.a_star_pathfinding( robot_pos, goal_pos, env_state['obstacles'], env_state ) if len(path) > 1: next_target = path[1] target_positions = self._generate_avoidance_trajectory(robot_state, next_target) current_positions = robot_state['joint_positions'] current_velocities = robot_state['joint_velocities'] control_output = self.robot.compute_pid_control( target_positions, current_positions, current_velocities, self.dt ) self.robot.set_joint_targets(control_output) def _execute_sand_walking_task(self, robot_state: Dict, env_state: Dict): """执行沙地行走任务""" # 沙地行走控制策略 gait_params = self.energy_optimizer.optimize_gait(robot_state) target_positions = self._generate_sand_walking_trajectory(robot_state, gait_params) current_positions = robot_state['joint_positions'] current_velocities = robot_state['joint_velocities'] control_output = self.robot.compute_pid_control( target_positions, current_positions, current_velocities, self.dt ) self.robot.set_joint_targets(control_output) def _execute_dynamic_avoidance_task(self, robot_state: Dict, env_state: Dict): """执行动态避障任务""" # 动态障碍物避障 robot_pos = self.robot.data.xpos[self.robot.model.body('torso').id] # 预测障碍物位置 for obstacle in env_state['obstacles']: if obstacle['type'] == 'dynamic': # 简单的线性预测 predicted_pos = obstacle['position'] + obstacle.get('velocity', np.zeros(3)) * 0.5 if np.linalg.norm(robot_pos - predicted_pos) < 1.0: # 计算避障方向 avoid_direction = self.path_planner._calculate_avoid_direction(robot_pos, obstacle) target_positions = self._generate_dynamic_avoidance_trajectory(robot_state, avoid_direction) current_positions = robot_state['joint_positions'] current_velocities = robot_state['joint_velocities'] control_output = self.robot.compute_pid_control( target_positions, current_positions, current_velocities, self.dt ) self.robot.set_joint_targets(control_output) return # 如果没有动态障碍物,执行普通行走 self._execute_walking_task(robot_state, env_state) def _execute_interference_response_task(self, robot_state: Dict, env_state: Dict): """执行干扰响应任务""" # 根据干扰类型调整控制策略 interference_level = env_state['interference_level'] if interference_level > 0.5: # 高干扰情况下的稳定控制 target_positions = self._generate_stabilization_trajectory(robot_state) else: # 低干扰情况下的正常行走 target_positions = self._generate_walking_trajectory(robot_state) current_positions = robot_state['joint_positions'] current_velocities = robot_state['joint_velocities'] control_output = self.robot.compute_pid_control( target_positions, current_positions, current_velocities, self.dt ) self.robot.set_joint_targets(control_output) def _generate_walking_trajectory(self, robot_state: Dict) -> np.ndarray: """生成行走轨迹""" # 简化的双足行走轨迹生成 time_phase = self.simulation_time * 2.0 # 行走频率 # 基础关节位置 base_positions = np.zeros(self.robot.model.nu) # 腿部摆动 left_leg_swing = 0.2 * np.sin(time_phase) right_leg_swing = 0.2 * np.sin(time_phase + np.pi) # 设置腿部关节 if self.robot.model.nu >= 12: # 假设至少有12个关节 base_positions[0:3] = [left_leg_swing, 0.0, 0.0] # 左腿 base_positions[3:6] = [right_leg_swing, 0.0, 0.0] # 右腿 base_positions[6:9] = [0.0, 0.0, 0.0] # 左臂 base_positions[9:12] = [0.0, 0.0, 0.0] # 右臂 return base_positions def _generate_slope_walking_trajectory(self, robot_state: Dict, gait_params: Dict) -> np.ndarray: """生成斜坡行走轨迹""" # 调整步态以适应斜坡 base_trajectory = self._generate_walking_trajectory(robot_state) # 增加步长和调整重心 step_length = gait_params.get('step_length', 0.3) com_height = gait_params.get('com_height', 0.8) # 调整腿部关节以适应斜坡 slope_adjustment = 0.1 # 斜坡角度调整 base_trajectory[0:3] += slope_adjustment base_trajectory[3:6] += slope_adjustment return base_trajectory def _generate_stair_climbing_trajectory(self, robot_state: Dict) -> np.ndarray: """生成楼梯攀爬轨迹""" # 楼梯攀爬需要更高的抬腿动作 time_phase = self.simulation_time * 1.5 # 较慢的攀爬频率 base_positions = np.zeros(self.robot.model.nu) # 交替抬腿攀爬 left_leg_lift = 0.4 * np.sin(time_phase) right_leg_lift = 0.4 * np.sin(time_phase + np.pi) if self.robot.model.nu >= 12: base_positions[0:3] = [left_leg_lift, 0.0, 0.0] # 左腿 base_positions[3:6] = [right_leg_lift, 0.0, 0.0] # 右腿 base_positions[6:9] = [0.0, 0.0, 0.0] # 左臂 base_positions[9:12] = [0.0, 0.0, 0.0] # 右臂 return base_positions def _generate_avoidance_trajectory(self, robot_state: Dict, target_pos: np.ndarray) -> np.ndarray: """生成避障轨迹""" # 基于目标位置生成避障轨迹 robot_pos = self.robot.data.xpos[self.robot.model.body('torso').id] direction = (target_pos - robot_pos) / np.linalg.norm(target_pos - robot_pos) base_positions = np.zeros(self.robot.model.nu) # 根据方向调整腿部运动 lateral_movement = direction[1] * 0.3 forward_movement = direction[0] * 0.2 if self.robot.model.nu >= 12: base_positions[0:3] = [forward_movement, lateral_movement, 0.0] # 左腿 base_positions[3:6] = [forward_movement, lateral_movement, 0.0] # 右腿 base_positions[6:9] = [0.0, 0.0, 0.0] # 左臂 base_positions[9:12] = [0.0, 0.0, 0.0] # 右臂 return base_positions def _generate_sand_walking_trajectory(self, robot_state: Dict, gait_params: Dict) -> np.ndarray: """生成沙地行走轨迹""" # 沙地行走需要更小的步长和更稳定的重心 base_trajectory = self._generate_walking_trajectory(robot_state) # 减小步长 step_length = gait_params.get('step_length', 0.2) * 0.7 # 沙地减小步长 # 调整重心高度 com_height = gait_params.get('com_height', 0.8) * 0.9 # 沙地降低重心 # 调整腿部关节 base_trajectory[0:3] *= 0.7 # 减小左腿摆动 base_trajectory[3:6] *= 0.7 # 减小右腿摆动 return base_trajectory def _generate_dynamic_avoidance_trajectory(self, robot_state: Dict, avoid_direction: np.ndarray) -> np.ndarray: """生成动态避障轨迹""" # 基于避障方向生成轨迹 base_positions = np.zeros(self.robot.model.nu) lateral_movement = avoid_direction[1] * 0.4 forward_movement = avoid_direction[0] * 0.3 if self.robot.model.nu >= 12: base_positions[0:3] = [forward_movement, lateral_movement, 0.0] # 左腿 base_positions[3:6] = [forward_movement, lateral_movement, 0.0] # 右腿 base_positions[6:9] = [0.0, 0.0, 0.0] # 左臂 base_positions[9:12] = [0.0, 0.0, 0.0] # 右臂 return base_positions def _generate_stabilization_trajectory(self, robot_state: Dict) -> np.ndarray: """生成稳定化轨迹""" # 高干扰情况下的稳定控制 base_positions = np.zeros(self.robot.model.nu) # 保持当前姿态,减小运动幅度 current_positions = robot_state['joint_positions'] if len(current_positions) >= self.robot.model.nu: base_positions = current_positions[:self.robot.model.nu] * 0.8 # 减小运动幅度 return base_positions def update_performance_metrics(self): """更新性能指标""" robot_state = self.get_robot_state() env_state = self.get_environment_state() # 任务完成率 terrain_progress = (self.scenario_state['current_terrain_index'] / len(self.scenario_state['terrain_sequence'])) self.performance_metrics.task_completion_rate = terrain_progress # 能耗效率 energy_efficiency = 1.0 - (robot_state['energy_consumption'] / 1000.0) self.performance_metrics.energy_efficiency = max(0.0, energy_efficiency) # 稳定性评分 com_height = robot_state['com_height'] com_velocity = robot_state['com_velocity'] stability_score = 1.0 - (com_velocity / 2.0) # 速度越小越稳定 self.performance_metrics.stability_score = max(0.0, stability_score) # 响应时间 response_time = 1.0 - (self.simulation_time / self.max_simulation_time) self.performance_metrics.response_time = max(0.0, response_time) # 障碍物避障率 obstacle_avoidance_rate = 1.0 for obstacle in env_state['obstacles']: if obstacle['distance'] < 0.5: # 距离太近 obstacle_avoidance_rate = 0.5 self.performance_metrics.obstacle_avoidance_rate = obstacle_avoidance_rate # 地形适应评分 terrain_adaptation = 1.0 if env_state['terrain_type'] in [TerrainType.SLOPE, TerrainType.STAIRS, TerrainType.SAND]: terrain_adaptation = 0.8 self.performance_metrics.terrain_adaptation_score = terrain_adaptation def record_performance_data(self): """记录性能数据""" self.performance_data['time'].append(self.simulation_time) self.performance_data['energy'].append(self.robot.energy_consumption) self.performance_data['stability'].append(self.performance_metrics.stability_score) self.performance_data['task_completion'].append(self.performance_metrics.task_completion_rate) def run_simulation(self): """运行仿真""" logger.info("🚀 开始人形机器人仿真比赛") # 加载机器人模型 model_path = "models/humanoid.xml" # 需要创建这个模型文件 if not self.robot.load_model(model_path): logger.error("❌ 无法加载机器人模型,使用默认模型") # 这里可以创建一个简单的默认模型 # 设置场景 self.setup_scenario("comprehensive") # 仿真主循环 while self.simulation_time < self.max_simulation_time: # 更新场景状态 self.update_scenario_state() # 获取当前状态 robot_state = self.get_robot_state() env_state = self.get_environment_state() # 智能决策 current_task = self.decision_system.make_decision(robot_state, env_state) self.task_history.append(current_task) # 执行任务 self.execute_task(current_task) # 更新性能指标 self.update_performance_metrics() self.record_performance_data() # 仿真步进 self.robot.step(self.dt) self.simulation_time += self.dt # 输出进度 if int(self.simulation_time) % 10 == 0 and self.simulation_time > 0: logger.info(f"⏱️ 仿真时间: {self.simulation_time:.1f}s") logger.info(f"📊 任务完成率: {self.performance_metrics.task_completion_rate:.2f}") logger.info(f"⚡ 能耗效率: {self.performance_metrics.energy_efficiency:.2f}") logger.info(f"🛡️ 稳定性: {self.performance_metrics.stability_score:.2f}") # 仿真结束 logger.info("✅ 仿真完成") self._print_final_results() def _print_final_results(self): """打印最终结果""" print("\n" + "=" * 50) print("🏆 人形机器人仿真比赛结果") print("=" * 50) print(f"📊 任务完成率: {self.performance_metrics.task_completion_rate:.2f}") print(f"⚡ 能耗效率: {self.performance_metrics.energy_efficiency:.2f}") print(f"🛡️ 稳定性评分: {self.performance_metrics.stability_score:.2f}") print(f"⚡ 响应时间: {self.performance_metrics.response_time:.2f}") print(f"🚧 障碍物避障率: {self.performance_metrics.obstacle_avoidance_rate:.2f}") print(f"🏔️ 地形适应评分: {self.performance_metrics.terrain_adaptation_score:.2f}") # 计算总分 total_score = ( self.performance_metrics.task_completion_rate * 0.3 + self.performance_metrics.energy_efficiency * 0.2 + self.performance_metrics.stability_score * 0.2 + self.performance_metrics.response_time * 0.1 + self.performance_metrics.obstacle_avoidance_rate * 0.1 + self.performance_metrics.terrain_adaptation_score * 0.1 ) print(f"\n🏅 总分: {total_score:.2f}") if total_score >= 0.8: print("🥇 优秀表现!") elif total_score >= 0.6: print("🥈 良好表现!") elif total_score >= 0.4: print("🥉 合格表现!") else: print("📈 需要改进") print("=" * 50) def main(): """主函数""" parser = argparse.ArgumentParser(description="人形机器人仿真比赛系统") parser.add_argument("--scenario", type=str, default="comprehensive", choices=["comprehensive", "basic_tasks", "advanced_tasks"], help="仿真场景类型") parser.add_argument("--duration", type=float, default=60.0, help="仿真持续时间(秒)") args = parser.parse_args() # 创建仿真实例 simulation = CompetitionSimulation() simulation.max_simulation_time = args.duration # 设置场景 simulation.setup_scenario(args.scenario) # 运行仿真 simulation.run_simulation() if __name__ == "__main__": main()修正代码
07-31
在mujoco中进行可视化 ,修正以下代码#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 人形机器人仿真演示 - 优化版本 """ import sys import os import time import json import numpy as np import matplotlib.pyplot as plt from typing import Dict, List, Tuple, Optional import threading import argparse import mujoco import pygame from pygame.locals import * import math import cv2 from PIL import Image import io import traceback import subprocess import ctypes import glfw # 检查OpenGL支持并尝试修复 def fix_opengl_issues(): """尝试解决OpenGL初始化问题""" print("🛠️ 尝试解决OpenGL初始化问题...") # 尝试设置不同的渲染后端 backends = ['glfw', 'osmesa', 'egl'] for backend in backends: glfw_initialized = False try: os.environ['MUJOCO_GL'] = backend print(f" 尝试使用 {backend} 渲染后端...") # 初始化GLFW窗口用于测试 if not glfw.init(): raise RuntimeError("GLFW初始化失败") glfw_initialized = True # 创建隐藏窗口 glfw.window_hint(glfw.VISIBLE, glfw.FALSE) window = glfw.create_window(640, 480, "OpenGL Test", None, None) if not window: raise RuntimeError("GLFW窗口创建失败") glfw.make_context_current(window) print(f"✅ 使用 {backend} 后端成功创建OpenGL上下文!") # 测试OpenGL功能 glClearColor = ctypes.CDLL(None).glClearColor glClearColor(0.2, 0.3, 0.4, 1.0) print("✅ OpenGL基本功能测试通过") glfw.destroy_window(window) glfw.terminate() glfw_initialized = False return True except Exception as e: print(f"⚠️ {backend} 后端失败: {e}") if 'window' in locals() and window: glfw.destroy_window(window) if glfw_initialized: glfw.terminate() # 尝试加载OpenGL库 try: print(" 尝试直接加载OpenGL库...") opengl_libs = [ 'libGL.so.1', # Linux '/usr/lib/x86_64-linux-gnu/libGL.so.1', # Ubuntu 'opengl32.dll', # Windows '/System/Library/Frameworks/OpenGL.framework/OpenGL' # macOS ] for lib in opengl_libs: try: ctypes.CDLL(lib) print(f"✅ 成功加载 {lib}") return True except Exception as e: print(f"⚠️ 加载 {lib} 失败: {e}") except Exception as e: print(f"⚠️ OpenGL库加载失败: {e}") print("💡 建议解决方案:") print(" 1. 更新显卡驱动程序") print(" 2. 安装系统OpenGL库 (Linux: libgl1-mesa-glx, Windows: OpenGL runtime)") print(" 3. 在虚拟环境中使用: conda install -c conda-forge glew glfw") return False # 导入自定义模块 try: from mujoco_simulation import HumanoidRobot from advanced_control import ( IntelligentDecisionSystem, PathPlanner, EnergyOptimizer, AdaptiveController, EnvironmentState, RobotState, TaskType, TerrainType ) except ImportError: # 创建模拟类以避免导入错误 class HumanoidRobot: def __init__(self): self.model = None self.data = None self.position = np.array([0.0, 0.0, 1.0]) self.velocity = np.zeros(3) self.orientation = np.array([1.0, 0.0, 0.0, 0.0]) class IntelligentDecisionSystem: pass class VisualizationSystem: """可视化系统 - 用于2D和3D渲染""" def __init__(self, model: Optional[mujoco.MjModel] = None, width: int = 1200, height: int = 800): """初始化可视化系统""" pygame.init() # 使用标准2D渲染模式,避免OpenGL模式冲突 self.screen = pygame.display.set_mode((width, height)) pygame.display.set_caption("人形机器人仿真演示") self.clock = pygame.time.Clock() self.font = pygame.font.SysFont('SimHei', 20) self.title_font = pygame.font.SysFont('SimHei', 28, bold=True) # 地形颜色配置 self.terrain_colors = { 'flat': (180, 200, 180), 'slope': (160, 180, 200), 'stairs': (200, 180, 160), 'sand': (220, 200, 150), 'grass': (150, 200, 150) } self.obstacle_colors = { 'static': (200, 100, 100), 'dynamic': (100, 150, 200), 'moving': (150, 100, 200) } # 创建机器人图像 self.robot_img = self._create_robot_image() # 地形纹理缓存 self.terrain_textures = { 'flat': self._create_terrain_texture('flat'), 'slope': self._create_terrain_texture('slope'), 'stairs': self._create_terrain_texture('stairs'), 'sand': self._create_terrain_texture('sand'), 'grass': self._create_terrain_texture('grass') } # 尝试修复OpenGL问题 self.opengl_fixed = fix_opengl_issues() self.using_software_rendering = False # 初始化MuJoCo渲染组件 self.camera = mujoco.MjvCamera() self.opt = mujoco.MjvOption() self.scene = None self.context = None if model is not None and self.opengl_fixed: try: # 尝试创建渲染上下文 self.context = mujoco.MjrContext(model, mujoco.mjtFontScale.mjFONTSCALE_150) self.scene = mujoco.MjvScene(model=model, maxgeom=1000) print("✅ 成功初始化渲染上下文") # 设置相机位置 self.camera.distance = 5.0 self.camera.elevation = -20 self.camera.azimuth = 90 except Exception as e: print(f"⚠️ 渲染上下文初始化失败: {e}") self.scene = None self.context = None self.using_software_rendering = True else: print("⚠️ 无法修复OpenGL问题,使用软件渲染") self.using_software_rendering = True def _create_robot_image(self): """创建机器人图像""" surface = pygame.Surface((50, 80), pygame.SRCALPHA) # 绘制头部 pygame.draw.circle(surface, (100, 150, 255), (25, 15), 10) # 绘制身体 pygame.draw.rect(surface, (100, 200, 100), (15, 25, 20, 30)) # 绘制腿部 pygame.draw.line(surface, (0, 0, 0), (20, 55), (15, 75), 3) pygame.draw.line(surface, (0, 0, 0), (30, 55), (35, 75), 3) # 绘制手臂 pygame.draw.line(surface, (0, 0, 0), (15, 35), (5, 50), 3) pygame.draw.line(surface, (0, 0, 0), (35, 35), (45, 50), 3) return surface def _create_terrain_texture(self, terrain_type: str): """创建地形纹理""" size = (350, 100) texture = pygame.Surface(size, pygame.SRCALPHA) base_color = self.terrain_colors[terrain_type] if terrain_type == 'flat': # 平地的简单纹理 for i in range(0, size[0], 10): for j in range(0, size[1], 10): color_variation = np.random.randint(-10, 10) color = ( max(0, min(255, base_color[0] + color_variation)), max(0, min(255, base_color[1] + color_variation)), max(0, min(255, base_color[2] + color_variation)) ) pygame.draw.rect(texture, color, (i, j, 10, 10)) elif terrain_type == 'slope': # 斜坡纹理 for i in range(size[0]): height = int(size[1] * (1 - i / (size[0] * 1.5))) pygame.draw.line(texture, base_color, (i, height), (i, size[1]), 1) if i % 10 == 0: pygame.draw.line(texture, (150, 150, 150), (i, height), (i, size[1]), 1) elif terrain_type == 'stairs': # 楼梯纹理 step_height = 20 step_width = 70 for i in range(5): pygame.draw.rect(texture, (180, 160, 140), (i * step_width, size[1] - (i + 1) * step_height, step_width, step_height)) elif terrain_type == 'sand': # 沙地纹理 texture.fill(base_color) for _ in range(100): x = np.random.randint(0, size[0]) y = np.random.randint(0, size[1]) radius = np.random.randint(2, 5) shade = np.random.randint(-15, 15) color = ( max(0, min(255, base_color[0] + shade)), max(0, min(255, base_color[1] + shade)), max(0, min(255, base_color[2] + shade)) ) pygame.draw.circle(texture, color, (x, y), radius) elif terrain_type == 'grass': # 草地纹理 texture.fill(base_color) for i in range(0, size[0], 5): for j in range(0, size[1], 15): pygame.draw.line(texture, (100, 180, 100), (i, j), (i + np.random.randint(-2, 2), j - np.random.randint(5, 10)), 1) return texture def render_2d(self, demo, current_time: float): """渲染2D可视化界面""" self.screen.fill((240, 240, 245)) # 获取当前场景状态 scenario_state = demo.get_current_scenario_state(current_time) # 绘制标题 title = self.title_font.render("人形机器人仿真演示系统", True, (30, 30, 100)) self.screen.blit(title, (20, 15)) # 绘制状态面板 self._render_status_panel(demo, scenario_state, current_time) # 绘制场景可视化 self._render_scenario_visualization(demo, scenario_state, current_time) # 绘制3D渲染窗口 self._render_3d_view(demo) # 绘制性能图表 self._render_performance_charts(demo) # 绘制控制说明 self._render_instructions() pygame.display.flip() def _render_status_panel(self, demo, scenario_state: Dict, current_time: float): """渲染状态面板""" # 状态面板背景 pygame.draw.rect(self.screen, (250, 250, 255), (20, 70, 450, 180), 0, 10) pygame.draw.rect(self.screen, (200, 200, 220), (20, 70, 450, 180), 2, 10) # 场景信息 scene_text = self.font.render(f"场景: {scenario_state['description']}", True, (30, 30, 30)) self.screen.blit(scene_text, (40, 90)) # 地形信息 terrain_text = self.font.render(f"地形: {scenario_state['terrain']}", True, (30, 30, 30)) self.screen.blit(terrain_text, (40, 120)) # 时间信息 time_text = self.font.render(f"时间: {current_time:.1f}s / {demo.demo_config['duration']:.1f}s", True, (30, 30, 30)) self.screen.blit(time_text, (40, 150)) # 能量消耗 energy_text = self.font.render( f"能量消耗: {demo.energy_consumption[-1] if demo.energy_consumption else 0:.2f} J", True, (30, 30, 30)) self.screen.blit(energy_text, (40, 180)) # 控制模式 mode_text = self.font.render(f"控制模式: {'AI控制' if demo.demo_config['enable_ai'] else '手动控制'}", True, (30, 30, 30)) self.screen.blit(mode_text, (40, 210)) # 渲染状态 render_status = "硬件加速" if not self.using_software_rendering else "软件渲染" render_text = self.font.render(f"渲染模式: {render_status}", True, (30, 30, 30)) self.screen.blit(render_text, (250, 180)) # 状态指示器 status_color = (100, 200, 100) if demo.is_running else (200, 100, 100) pygame.draw.circle(self.screen, status_color, (400, 100), 10) status_text = self.font.render("运行中" if demo.is_running else "已停止", True, (30, 30, 30)) self.screen.blit(status_text, (415, 95)) # 暂停状态 if demo.paused: pause_text = self.font.render("已暂停", True, (200, 100, 50)) self.screen.blit(pause_text, (400, 130)) def _render_scenario_visualization(self, demo, scenario_state: Dict, current_time: float): """渲染场景可视化""" # 场景可视化背景 pygame.draw.rect(self.screen, (250, 250, 255), (20, 270, 450, 300), 0, 10) pygame.draw.rect(self.screen, (200, 200, 220), (20, 270, 450, 300), 2, 10) # 使用预生成的地形纹理 terrain_type = scenario_state['terrain'] if terrain_type in self.terrain_textures: terrain_img = self.terrain_textures[terrain_type] self.screen.blit(terrain_img, (50, 350)) else: # 默认地形 terrain_color = self.terrain_colors.get(terrain_type, (180, 180, 180)) pygame.draw.rect(self.screen, terrain_color, (50, 350, 350, 100)) # 绘制障碍物 for obs in scenario_state['obstacles']: color = self.obstacle_colors.get(obs['type'], (150, 150, 150)) x = 50 + (obs['position'][0] / 10) * 350 y = 400 - (obs['position'][1] / 2) * 50 radius = obs['radius'] * 50 # 绘制障碍物阴影增加深度感 pygame.draw.circle(self.screen, (100, 100, 100), (int(x - 3), int(y + 3)), int(radius)) pygame.draw.circle(self.screen, color, (int(x), int(y)), int(radius)) # 动态障碍物标记 if obs['type'] == 'dynamic': pygame.draw.circle(self.screen, (255, 255, 0), (int(x + radius * 0.6), int(y - radius * 0.6)), int(radius * 0.3)) # 绘制机器人 progress = min(current_time / demo.demo_config['duration'], 1.0) robot_x = 50 + progress * 350 robot_y = 400 - 30 * math.sin(progress * 20) # 添加行走动画效果 self.screen.blit(self.robot_img, (robot_x - 25, robot_y - 40)) # 绘制风力效果 if np.linalg.norm(scenario_state['wind']) > 0.1: wind_dir = scenario_state['wind'] / np.linalg.norm(scenario_state['wind']) for i in range(5): offset = i * 20 pygame.draw.line(self.screen, (100, 150, 255), (robot_x + 30 + offset, robot_y - 20), (robot_x + 50 + offset + wind_dir[0] * 10, robot_y - 20 + wind_dir[1] * 10), 2) pygame.draw.polygon(self.screen, (100, 150, 255), [ (robot_x + 50 + offset + wind_dir[0] * 10, robot_y - 20 + wind_dir[1] * 10), (robot_x + 45 + offset + wind_dir[0] * 15, robot_y - 25 + wind_dir[1] * 15), (robot_x + 45 + offset + wind_dir[0] * 15, robot_y - 15 + wind_dir[1] * 15) ]) # 场景标题 scene_title = self.font.render(f"当前场景: {scenario_state['description']}", True, (30, 30, 100)) self.screen.blit(scene_title, (40, 290)) def _render_3d_view(self, demo): """渲染3D视图""" # 3D视图背景 pygame.draw.rect(self.screen, (250, 250, 255), (500, 70, 680, 300), 0, 10) pygame.draw.rect(self.screen, (200, 200, 220), (500, 70, 680, 300), 2, 10) # 添加标题 title = self.font.render("机器人3D视图", True, (30, 30, 100)) self.screen.blit(title, (510, 80)) # 检查渲染组件是否可用 if self.scene is None or self.context is None or demo.robot.model is None or self.using_software_rendering: error_text = self.font.render("3D渲染不可用: 使用软件渲染模式", True, (100, 100, 200)) self.screen.blit(error_text, (520, 150)) # 显示替代图像 pygame.draw.rect(self.screen, (200, 220, 240), (550, 150, 580, 200)) pygame.draw.circle(self.screen, (100, 150, 255), (700, 250), 60) pygame.draw.rect(self.screen, (100, 200, 100), (660, 200, 80, 100)) pygame.draw.line(self.screen, (0, 0, 0), (670, 300), (650, 350), 4) pygame.draw.line(self.screen, (0, 0, 0), (730, 300), (750, 350), 4) pygame.draw.line(self.screen, (0, 0, 0), (660, 230), (600, 250), 4) pygame.draw.line(self.screen, (0, 0, 0), (740, 230), (780, 250), 4) return try: # 更新3D场景 mujoco.mjv_updateScene( demo.robot.model, demo.robot.data, self.opt, None, self.camera, mujoco.mjtCatBit.mjCAT_ALL, self.scene) # 渲染到内存缓冲区 width, height = 680, 300 buffer = np.zeros((height, width, 3), dtype=np.uint8) viewport = mujoco.MjrRect(0, 0, width, height) mujoco.mjr_render(viewport, self.scene, self.context) # 获取渲染图像 mujoco.mjr_readPixels(buffer, None, viewport, self.context) # 转换为Pygame表面 img = Image.fromarray(buffer, 'RGB') img = img.transpose(Image.FLIP_TOP_BOTTOM) img_bytes = img.tobytes() py_image = pygame.image.fromstring(img_bytes, (width, height), 'RGB') # 绘制到屏幕 self.screen.blit(py_image, (500, 70)) except Exception as e: # 显示错误信息 error_text = self.font.render(f"3D渲染错误: {str(e)}", True, (255, 0, 0)) self.screen.blit(error_text, (510, 150)) # 记录详细错误日志 print(f"⚠️ 3D渲染错误详情: {traceback.format_exc()}") def _render_performance_charts(self, demo): """渲染性能图表""" # 性能面板背景 pygame.draw.rect(self.screen, (250, 250, 255), (500, 390, 680, 180), 0, 10) pygame.draw.rect(self.screen, (200, 200, 220), (500, 390, 680, 180), 2, 10) # 标题 title = self.font.render("性能指标", True, (30, 30, 100)) self.screen.blit(title, (510, 400)) # 绘制能量消耗图表 if len(demo.energy_consumption) > 1: points = [] max_energy = max(demo.energy_consumption) if max(demo.energy_consumption) > 0 else 1 for i, val in enumerate(demo.energy_consumption): x = 520 + (i / (len(demo.energy_consumption) - 1)) * 300 y = 550 - (val / max_energy) * 100 points.append((x, y)) if len(points) > 1: pygame.draw.lines(self.screen, (100, 150, 255), False, points, 2) # 绘制最后一个点 pygame.draw.circle(self.screen, (100, 150, 255), (int(points[-1][0]), int(points[-1][1])), 4) # 添加当前值标签 value_text = self.font.render(f"{val:.1f}J", True, (100, 150, 255)) self.screen.blit(value_text, (int(points[-1][0]) + 5, int(points[-1][1]) - 10)) # 绘制稳定性图表 if len(demo.performance_metrics) > 1: points = [] max_stability = max([m['stability'] for m in demo.performance_metrics]) or 1 for i, metric in enumerate(demo.performance_metrics): x = 850 + (i / (len(demo.performance_metrics) - 1)) * 300 y = 550 - (metric['stability'] / max_stability) * 100 points.append((x, y)) if len(points) > 1: pygame.draw.lines(self.screen, (255, 150, 100), False, points, 2) # 绘制最后一个点 pygame.draw.circle(self.screen, (255, 150, 100), (int(points[-1][0]), int(points[-1][1])), 4) # 添加当前值标签 value_text = self.font.render(f"{metric['stability']:.2f}", True, (255, 150, 100)) self.screen.blit(value_text, (int(points[-1][0]) + 5, int(points[-1][1]) - 10)) # 图表标签 energy_label = self.font.render("能量消耗", True, (100, 150, 255)) self.screen.blit(energy_label, (520, 560)) stability_label = self.font.render("稳定性指标", True, (255, 150, 100)) self.screen.blit(stability_label, (850, 560)) # 添加图表标题 pygame.draw.line(self.screen, (100, 150, 255), (520, 530), (540, 530), 3) pygame.draw.line(self.screen, (255, 150, 100), (850, 530), (870, 530), 3) def _render_instructions(self): """渲染控制说明""" # 控制说明背景 pygame.draw.rect(self.screen, (250, 250, 255), (20, 580, 1160, 100), 0, 10) pygame.draw.rect(self.screen, (200, 200, 220), (20, 580, 1160, 100), 2, 10) # 控制说明 instructions = [ "ESC: 退出程序", "空格键: 暂停/继续", "R键: 重置演示", "↑↓←→: 控制机器人移动", "C键: 切换摄像头视角", "S键: 保存性能数据" ] for i, text in enumerate(instructions): inst_text = self.font.render(text, True, (80, 80, 180)) self.screen.blit(inst_text, (40 + (i % 3) * 380, 600 + (i // 3) * 30)) def handle_events(self): """处理Pygame事件""" for event in pygame.event.get(): if event.type == QUIT: return False elif event.type == KEYDOWN: if event.key == K_ESCAPE: return False if event.key == K_SPACE: return "pause" elif event.key == K_r: return "reset" elif event.key == K_UP: return "move_forward" elif event.key == K_DOWN: return "move_backward" elif event.key == K_LEFT: return "move_left" elif event.key == K_RIGHT: return "move_right" elif event.key == K_c: return "change_camera" elif event.key == K_s: return "save_data" return True class HumanoidDemo: """人形机器人仿真演示类""" def __init__(self): """初始化演示系统""" print("🤖 人形机器人仿真演示系统") print("=" * 60) # 创建人形机器人 self.robot = self._create_robot() # 创建高级控制模块 self.decision_system = IntelligentDecisionSystem() self.path_planner = PathPlanner() self.energy_optimizer = EnergyOptimizer() self.adaptive_controller = AdaptiveController() # 创建可视化系统 - 传递机器人模型 self.visualization = VisualizationSystem( self.robot.model if hasattr(self.robot, 'model') else None ) # 演示配置 self.demo_config = { 'duration': 30.0, 'enable_ai': True, 'enable_optimization': True, 'enable_adaptation': True, 'record_data': True, 'save_video': False } # 演示数据 self.demo_data = { 'timestamps': [], 'robot_states': [], 'environment_states': [], 'decisions': [], 'energy_consumption': [0.0], 'performance_metrics': [{'stability': 1.0, 'efficiency': 1.0}] } # 运行状态 self.is_running = False self.current_time = 0.0 self.paused = False self.camera_mode = 0 # 0: 默认, 1: 跟随, 2: 第一人称 print("✅ 演示系统初始化完成") def _create_robot(self): """创建机器人实例,处理可能的错误""" try: return HumanoidRobot() except Exception as e: print(f"⚠️ 创建机器人时出错: {e}") print("⚠️ 使用模拟机器人替代") return HumanoidRobot() # 使用之前定义的模拟类 @property def energy_consumption(self): return self.demo_data['energy_consumption'] @property def performance_metrics(self): return self.demo_data['performance_metrics'] def setup_demo_scenario(self, scenario_type: str = "comprehensive"): """设置演示场景""" scenarios = { "comprehensive": self._setup_comprehensive_scenario, "walking": self._setup_walking_scenario, "obstacle": self._setup_obstacle_scenario, "terrain": self._setup_terrain_scenario, "interference": self._setup_interference_scenario } if scenario_type in scenarios: print(f"🎬 设置 {scenario_type} 演示场景...") scenarios[scenario_type]() else: print(f"⚠️ 未知场景类型: {scenario_type},使用综合场景") self._setup_comprehensive_scenario() def _setup_comprehensive_scenario(self): """设置综合演示场景""" self.scenario_timeline = [ [0, 5, "walking", "平地行走"], [5, 10, "obstacle", "动态避障"], [10, 15, "terrain", "斜坡行走"], [15, 20, "terrain", "楼梯攀爬"], [20, 25, "interference", "风力干扰"], [25, 30, "walking", "恢复行走"] ] self.environment_config = { 'obstacles': [ {'position': [2, 0, 0.5], 'radius': 0.3, 'type': 'static'}, {'position': [4, 1, 0.3], 'radius': 0.3, 'type': 'dynamic'}, {'position': [6, -1, 0.4], 'radius': 0.2, 'type': 'moving'} ], 'terrain_sequence': ['flat', 'slope', 'stairs', 'sand', 'flat'], 'wind_patterns': [ {'time': [20, 25], 'force': [50, 0, 0], 'type': 'gust'}, {'time': [25, 30], 'force': [20, 10, 0], 'type': 'steady'} ], 'light_patterns': [ {'time': [22, 24], 'intensity': 0.2, 'type': 'dim'}, {'time': [24, 26], 'intensity': 0.9, 'type': 'bright'} ] } def _setup_walking_scenario(self): """设置行走演示场景""" self.scenario_t极line = [ [0, 10, "walking", "基础行走"], [10, 20, "walking", "快速行走"], [20, 30, "walking", "慢速行走"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [], 'light_patterns': [] } def _setup_obstacle_scenario(self): """设置避障演示场景""" self.scenario_timeline = [ [0, 10, "obstacle", "静态障碍物"], [10, 20, "obstacle", "动态障碍物"], [20, 30, "obstacle", "复杂障碍物"] ] self.environment_config = { 'obstacles': [ {'position': [1, 0, 0.5], 'radius': 0.3, 'type': 'static'}, {'position': [3, 0, 0.3], 'radius': 0.2, 'type': 'dynamic'}, {'position': [5, 0, 0.4], 'radius': 0.25, 'type': 'moving'} ], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [], 'light_patterns': [] } def _setup_terrain_scenario(self): """设置地形演示场景""" self.scenario_timeline = [ [0, 6, "terrain", "平地"], [6, 12, "terrain", "斜坡"], [12, 18, "terrain", "楼梯"], [极8, 24, "terrain", "沙地"], [24, 30, "terrain", "平地"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat', 'slope', 'stairs', 'sand', 'flat'], 'wind_patterns': [], 'light_patterns': [] } def _setup_interference_scenario(self): """设置干扰演示场景""" self.scenario_timeline = [ [0, 10, "walking", "正常行走"], [10, 20, "interference", "风力干扰"], [20, 30, "interference", "光照干扰"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [ {'time': [10, 20], 'force': [80, 0, 0], 'type': 'strong_wind'} ], 'light_patterns': [ {'time': [20, 30], 'intensity': 0.1, 'type': 'low_light'} ] } def get_current_scenario_state(self, current_time: float) -> Dict: """获取当前场景状态""" current_task = "idle" task_description = "待机" # 确定当前任务 for start_time, end_time, task, description in self.scenario_timeline: if start_time <= current_time < end_time: current_task = task task_description = description break # 确定当前地形 terrain_index = min(int(current_time / 6), len(self.environment_config['terrain_sequence']) - 1) current_terrain = self.environment_config['terrain_sequence'][terrain_index] # 计算当前风力 current_wind = np.zeros(3) for wind_pattern in self.environment_config['wind_patterns']: if wind_pattern['time'][0] <= current_time < wind_pattern['time'][1]: current_wind = np.array(wind_pattern['force']) break # 计算当前光照 current_light = 1.0 for light_pattern in self.environment_config['light_patterns']: if light_pattern['time'][0] <= current_time < light_pattern['time'][1]: current_light = light_pattern['intensity'] break return { 'task': current_task, 'description': task_description, 'terrain': current_terrain, 'wind': current_wind, 'light': current_light, 'obstacles': self.environment_config['obstacles'].copy(), 'time': current_time } def update_robot_state(self): """更新机器人状态""" # 模拟机器人控制逻辑 # 这里应该调用实际的机器人控制模块 pass def change_camera_mode(self): """切换摄像头视角""" self.camera_mode = (self.camera_mode + 1) % 3 if self.visualization.camera: if self.camera_mode == 0: # 默认视角 self.visualization.camera.distance = 5.0 self.visualization.camera.elevation = -20 self.visualization.camera.azimuth = 90 elif self.camera_mode == 1: # 跟随视角 self.visualization.camera.distance = 3.0 self.visualization.camera.elevation = -10 self.visualization.camera.azimuth = 45 elif self.camera_mode == 2: # 第一人称视角 self.visualization.camera.distance = 1.5 self.visualization.camera.elevation = 0 self.visualization.camera.azimuth = 0 def record_data(self, current_time): """记录演示数据""" self.demo_data['timestamps'].append(current_time) # 模拟能量消耗 - 根据地形和任务类型变化 energy_factor = 1.0 if self.get_current_scenario_state(current_time)['terrain'] == 'slope': energy_factor = 1.5 elif self.get_current_scenario_state(current_time)['terrain'] == 'stairs': energy_factor = 1.8 elif self.get_current_scenario_state(current_time)['terrain'] == 'sand': energy_factor = 2.0 new_energy = self.energy_consumption[-1] + 0.1 * energy_factor self.energy_consumption.append(new_energy) # 模拟性能指标 stability = 1.0 - np.random.uniform(0, 0.1) efficiency = 1.0 - np.random.uniform(0, 0.05) self.performance_metrics.append({ 'stability': max(0.1, stability), 'efficiency': max(0.1, efficiency) }) def save_performance_data(self): """保存性能数据""" filename = f"performance_data_{time.strftime('%Y%m%d_%H%M%S')}.json" try: with open(filename, 'w') as f: json.dump({ 'timestamps': self.demo_data['timestamps'], 'energy_consumption': self.demo_data['energy_consumption'], 'performance_metrics': self.demo_data['performance_metrics'] }, f, indent=2) print(f"✅ 性能数据已保存到 {filename}") return True except Exception as e: print(f"⚠️ 保存性能数据失败: {e}") return False def run_demo(self): """运行演示""" print(f"🚀 开始演示,持续时间: {self.demo_config['duration']}秒") print("=" * 60) self.is_running = True start_time = time.time() try: while self.current_time < self.demo_config['duration']: # 处理事件 event_result = self.visualization.handle_events() if event_result == False: break elif event_result == "pause": self.paused = not self.paused elif event_result == "reset": start_time = time.time() self.current_time = 0.0 self.demo_data = { 'timestamps': [], 'energy_consumption': [0.0], 'performance_metrics': [{'stability': 1.0, 'efficiency': 1.0}] } elif event_result == "change_camera": self.change_camera_mode() elif event_result == "save_data": self.save_performance_data() if self.paused: time.sleep(0.1) continue # 更新当前时间 self.current_time = time.time() - start_time # 更新机器人状态 self.update_robot_state() # 记录数据 if self.demo_config['record_data']: self.record_data(self.current_time) # 渲染可视化界面 self.visualization.render_2d(self, self.current_time) # 控制帧率 self.visualization.clock.tick(30) self.is_running = False print("\n✅ 演示完成!") # 自动保存性能数据 if self.demo_config['record_data']: self.save_performance_data() except Exception as e: self.is_running = False print(f"\n⛔ 演示出错: {e}") traceback.print_exc() # 出错时保存当前数据 if self.demo_config['record_data']: print("⚠️ 尝试保存当前性能数据...") self.save_performance_data() finally: pygame.quit() def main(): """主函数""" parser = argparse.ArgumentParser(description='人形机器人仿真演示') parser.add_argument('--scenario', type=str, default='comprehensive', choices=['comprehensive', 'walking', 'obstacle', 'terrain', 'interference'], help='演示场景类型') parser.add_argument('--duration', type=float, default=30.0, help='演示持续时间(秒)') parser.add_argument('--no-opengl', action='store_true', help='强制禁用OpenGL加速') args = parser.parse_args() # 创建演示实例 demo = HumanoidDemo() demo.demo_config['duration'] = args.duration # 如果指定禁用OpenGL if args.no_opengl: os.environ['MUJOCO_GL'] = 'osmesa' print("⚠️ 已禁用OpenGL硬件加速") # 设置场景 demo.setup_demo_scenario(args.scenario) # 运行演示 demo.run_demo() if __name__ == "__main__": main()
07-29
修正代码#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 人形机器人仿真演示 - MuJoCo原生可视化 """ import sys import os import time import json import numpy as np import matplotlib.pyplot as plt from typing import Dict, List, Tuple, Optional import threading import argparse import mujoco import glfw from mujoco import viewer import imageio from datetime import datetime # 导入自定义模块 try: from mujoco_simulation import HumanoidRobot from advanced_control import ( IntelligentDecisionSystem, PathPlanner, EnergyOptimizer, AdaptiveController, EnvironmentState, RobotState, TaskType, TerrainType ) except ImportError: # 创建模拟类以避免导入错误 class HumanoidRobot: def __init__(self): self.model = mujoco.MjModel.from_xml_string(""" <mujoco> <worldbody> <light diffuse=".5 .5 .5" pos="0 0 3" dir="0 0 -1"/> <camera name="fixed" pos="0 -3 1" xyaxes="1 0 0 0 1 2"/> <body name="floor" pos="0 0 0"> <geom size="10 10 0.1" type="box" rgba=".8 .9 .8 1"/> </body> <body name="torso" pos="0 0 1.2"> <joint type="free"/> <geom size="0.2" type="sphere" rgba="1 0 0 1"/> <body name="head" pos="0 0 0.2"> <geom size="0.15" type="sphere" rgba="0 0 1 1"/> </body> <body name="left_arm" pos="0.3 0 0"> <joint type="hinge" axis="0 1 0"/> <geom size="0.08" fromto="0 0 0 0.4 0 0" type="capsule" rgba="0 1 0 1"/> </body> <body name="right_arm" pos="-0.3 0 0"> <joint type="hinge" axis="0 1 0"/> <geom size="0.08" fromto="0 0 0 -0.4 0 0" type="capsule" rgba="0 1 0 1"/> </body> <body name="left_leg" pos="0.15 0 -0.3"> <joint type="hinge" axis="0 1 0"/> <geom size="0.08" fromto="0 0 0 0 -0.4 0" type="capsule" rgba="0 1 0 1"/> </body> <body name="right_leg" pos="-0.15 0 -0.3"> <joint type="hinge" axis="0 1 0"/> <geom size="0.08" fromto="0 0 0 0 -0.4 0" type="capsule" rgba="0 1 0 1"/> </body> </body> </worldbody> </mujoco> """) self.data = mujoco.MjData(self.model) self.position = np.array([0.0, 0.0, 1.0]) self.velocity = np.zeros(3) self.orientation = np.array([1.0, 0.0, 0.0, 0.0]) # 设置初始状态 mujoco.mj_resetData(self.model, self.data) self.data.qpos[3:7] = [1, 0, 0, 0] # 四元数方向 class IntelligentDecisionSystem: pass class MuJoCoVisualizer: """MuJoCo原生可视化系统""" def __init__(self, model, data, width=1200, height=800): self.model = model self.data = data self.width = width self.height = height self.viewer = None self.camera = "fixed" # 默认摄像头 self.camera_modes = ["fixed", "track", "free"] self.current_camera_mode = 0 self.recording = False self.video_writer = None self.video_frames = [] self.scene_state = {} # 初始化摄像头位置 self.cameras = { "fixed": {"type": "fixed", "pos": [0, -3, 1], "xyaxes": [1, 0, 0, 0, 1, 2]}, "track": {"type": "track", "distance": 3.0, "elevation": -20, "azimuth": 45}, "free": {"type": "free", "distance": 5.0, "lookat": [0, 0, 1.2], "elevation": -20, "azimuth": 90} } def init_viewer(self): def __init__(self, model, data, width=1200, height=800): self.model = model self.data = data self.width = width self.height = height self.viewer = None self.camera = "fixed" # 默认摄像头 self.camera_modes = ["fixed", "track", "free"] self.current_camera_mode = 0 self.recording = False self.video_writer = None self.video_frames = [] self.scene_state = {} # 初始化摄像头位置 self.cameras = { "fixed": {"type": "fixed", "pos": [0, -3, 1], "xyaxes": [1, 0, 0, 0, 1, 2]}, "track": {"type": "track", "distance": 3.0, "elevation": -20, "azimuth": 45}, "free": {"type": "free", "distance": 5.0, "lookat": [0, 0, 1.2], "elevation": -20, "azimuth": 90} } def init_viewer(self): """初始化MuJoCo查看器""" # 创建必要的选项对象 opt = mujoco.MjvOption() pert = mujoco.MjvPerturb() scn = mujoco.MjvScene(self.model, maxgeom=1000) # 正确初始化查看器 self.viewer = viewer.Handle( width=self.width, height=self.height, opt=opt, pert=pert, user_scn=scn ) # 设置模型和数据 self.viewer.model = self.model self.viewer.data = self.data # 设置初始摄像头 self._update_camera() # 设置可视化选项 self.viewer.vopt.flags = [ mujoco.mjtVisFlag.mjVIS_JOINT, mujoco.mjtVisFlag.mjVIS_CONTACTPOINT, mujoco.mjtVisFlag.mjVIS_CONTACTFORCE ] # 设置初始视图 self._update_camera() def _update_camera(self): """更新摄像头设置""" mode = self.camera_modes[self.current_camera_mode] cam_settings = self.cameras[mode] if mode == "fixed": self.viewer.cam.type = mujoco.mjtCamera.mjCAMERA_FIXED self.viewer.cam.fixedcamid = mujoco.mj_name2id(self.model, mujoco.mjtObj.mjOBJ_CAMERA, "fixed") elif mode == "track": self.viewer.cam.type = mujoco.mjtCamera.mjCAMERA_TRACKING self.viewer.cam.trackbodyid = mujoco.mj_name2id(self.model, mujoco.mjtObj.mjOBJ_BODY, "torso") self.viewer.cam.distance = cam_settings["distance"] self.viewer.cam.elevation = cam_settings["elevation"] self.viewer.cam.azimuth = cam_settings["azimuth"] elif mode == "free": self.viewer.cam.type = mujoco.mjtCamera.mjCAMERA_FREE self.viewer.cam.lookat[:] = cam_settings["lookat"] self.viewer.cam.distance = cam_settings["distance"] self.viewer.cam.elevation = cam_settings["elevation"] self.viewer.cam.azimuth = cam_settings["azimuth"] def toggle_camera(self): """切换摄像头模式""" self.current_camera_mode = (self.current_camera_mode + 1) % len(self.camera_modes) self._update_camera() print(f"摄像头模式切换为: {self.camera_modes[self.current_camera_mode]}") def render(self, render_state=True): """渲染当前帧""" if not self.viewer: return # 更新场景状态 self.scene_state.update({ 'task': render_state.get('task', 'idle'), 'description': render_state.get('description', '待机'), 'terrain': render_state.get('terrain', 'flat'), 'time': render_state.get('time', 0.0), 'energy': render_state.get('energy', 0.0) }) # 渲染场景 self.viewer.render() # 录制视频 if self.recording: frame = np.empty((self.height, self.width, 3), dtype=np.uint8) self.viewer.read_pixels(frame, depth=None) self.video_frames.append(frame.copy()) def start_recording(self): """开始录制视频""" self.recording = True self.video_frames = [] print("⏺️ 开始录制视频...") def stop_recording(self): """停止录制并保存视频""" if not self.recording or len(self.video_frames) == 0: return False self.recording = False timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"simulation_{timestamp}.mp4" try: with imageio.get_writer(filename, fps=30) as writer: for frame in self.video_frames: writer.append_data(frame) print(f"✅ 视频已保存到: {filename}") self.video_frames = [] return True except Exception as e: print(f"⚠️ 保存视频失败: {e}") return False def close(self): """关闭查看器""" if self.viewer: self.viewer.close() self.viewer = None class HumanoidDemo: """人形机器人仿真演示类""" def __init__(self): """初始化演示系统""" print("🤖 人形机器人仿真演示系统") print("=" * 60) # 创建人形机器人 self.robot = self._create_robot() # 创建高级控制模块 self.decision_system = IntelligentDecisionSystem() self.path_planner = PathPlanner() self.energy_optimizer = EnergyOptimizer() self.adaptive_controller = AdaptiveController() # 创建MuJoCo可视化系统 self.visualizer = MuJoCoVisualizer(self.robot.model, self.robot.data) self.visualizer.init_viewer() # 演示配置 self.demo_config = { 'duration': 30.0, 'enable_ai': True, 'enable_optimization': True, 'enable_adaptation': True, 'record_data': True, 'save_video': False } # 演示数据 self.demo_data = { 'timestamps': [], 'robot_states': [], 'environment_states': [], 'decisions': [], 'energy_consumption': [0.0], 'performance_metrics': [{'stability': 1.0, 'efficiency': 1.0}] } # 运行状态 self.is_running = False self.current_time = 0.0 self.paused = False self.key_actions = { glfw.KEY_SPACE: 'pause', glfw.KEY_R: 'reset', glfw.KEY_C: 'change_camera', glfw.KEY_S: 'save_data', glfw.KEY_V: 'toggle_recording' } print("✅ 演示系统初始化完成") def _create_robot(self): """创建机器人实例""" try: return HumanoidRobot() except Exception as e: print(f"⚠️ 创建机器人时出错: {e}") print("⚠️ 使用模拟机器人替代") return HumanoidRobot() @property def energy_consumption(self): return self.demo_data['energy_consumption'] @property def performance_metrics(self): return self.demo_data['performance_metrics'] def setup_demo_scenario(self, scenario_type: str = "comprehensive"): """设置演示场景""" scenarios = { "comprehensive": self._setup_comprehensive_scenario, "walking": self._setup_walking_scenario, "obstacle": self._setup_obstacle_scenario, "terrain": self._setup_terrain_scenario, "interference": self._setup_interference_scenario } if scenario_type in scenarios: print(f"🎬 设置 {scenario_type} 演示场景...") scenarios[scenario_type]() else: print(f"⚠️ 未知场景类型: {scenario_type},使用综合场景") self._setup_comprehensive_scenario() def _setup_comprehensive_scenario(self): """设置综合演示场景""" self.scenario_timeline = [ [0, 5, "walking", "平地行走"], [5, 10, "obstacle", "动态避障"], [10, 15, "terrain", "斜坡行走"], [15, 20, "terrain", "楼梯攀爬"], [20, 25, "interference", "风力干扰"], [25, 30, "walking", "恢复行走"] ] self.environment_config = { 'obstacles': [ {'position': [2, 0, 0.5], 'radius': 0.3, 'type': 'static'}, {'position': [4, 1, 0.3], 'radius': 0.3, 'type': 'dynamic'}, {'position': [6, -1, 0.4], 'radius': 0.2, 'type': 'moving'} ], 'terrain_sequence': ['flat', 'slope', 'stairs', 'sand', 'flat'], 'wind_patterns': [ {'time': [20, 25], 'force': [50, 0, 0], 'type': 'gust'}, {'time': [25, 30], 'force': [20, 10, 0], 'type': 'steady'} ], 'light_patterns': [ {'time': [22, 24], 'intensity': 0.2, 'type': 'dim'}, {'time': [24, 26], 'intensity': 0.9, 'type': 'bright'} ] } # 添加地形几何体 self._add_terrain_geoms() def _add_terrain_geoms(self): """根据场景添加地形几何体""" # 添加斜坡 slope_height = 0.5 self.robot.model.geom('floor').size = [10, 10, 0.1] # 重置地板 # 添加斜坡几何体 slope_pos = [5, 0, slope_height / 2] slope_size = [5, 10, slope_height / 2] slope_quat = [1, 0, 0, 0] # 四元数 self.robot.model.body_add('world', name='slope') self.robot.model.geom_add( body='slope', name='slope_geom', type='box', size=slope_size, pos=slope_pos, quat=slope_quat, rgba=[0.7, 0.7, 0.9, 1] ) # 添加楼梯 stair_positions = [ [7.0, 0, 0.1], [7.5, 0, 0.3], [8.0, 0, 0.5], [8.5, 0, 0.7], [9.0, 0, 0.9] ] for i, pos in enumerate(stair_positions): self.robot.model.body_add('world', name=f'stair_{i}') self.robot.model.geom_add( body=f'stair_{i}', name=f'stair_geom_{i}', type='box', size=[0.25, 2.0, 0.1], pos=pos, rgba=[0.8, 0.7, 0.6, 1] ) # 重新初始化数据 mujoco.mj_resetData(self.robot.model, self.robot.data) def _setup_walking_scenario(self): """设置行走演示场景""" self.scenario_timeline = [ [0, 10, "walking", "基础行走"], [10, 20, "walking", "快速行走"], [20, 30, "walking", "慢速行走"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [], 'light_patterns': [] } def _setup_obstacle_scenario(self): """设置避障演示场景""" self.scenario_timeline = [ [0, 10, "obstacle", "静态障碍物"], [10, 20, "obstacle", "动态障碍物"], [20, 30, "obstacle", "复杂障碍物"] ] self.environment_config = { 'obstacles': [ {'position': [1, 0, 0.5], 'radius': 0.3, 'type': 'static'}, {'position': [3, 0, 0.3], 'radius': 0.2, 'type': 'dynamic'}, {'position': [5, 0, 0.4], 'radius': 0.25, 'type': 'moving'} ], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [], 'light_patterns': [] } # 添加障碍物几何体 for i, obs in enumerate(self.environment_config['obstacles']): self.robot.model.body_add('world', name=f'obstacle_{i}') self.robot.model.geom_add( body=f'obstacle_{i}', name=f'obs_geom_{i}', type='sphere', size=[obs['radius']], pos=obs['position'], rgba=[0.9, 0.5, 0.5, 1] if obs['type'] == 'static' else [0.5, 0.7, 0.9, 1] if obs['type'] == 'dynamic' else [0.7, 0.5, 0.9, 1] ) mujoco.mj_resetData(self.robot.model, self.robot.data) def _setup_terrain_scenario(self): """设置地形演示场景""" self.scenario_timeline = [ [0, 6, "terrain", "平地"], [6, 12, "terrain", "斜坡"], [12, 18, "terrain", "楼梯"], [18, 24, "terrain", "沙地"], [24, 30, "terrain", "平地"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat', 'slope', 'stairs', 'sand', 'flat'], 'wind_patterns': [], 'light_patterns': [] } self._add_terrain_geoms() def _setup_interference_scenario(self): """设置干扰演示场景""" self.scenario_timeline = [ [0, 10, "walking", "正常行走"], [10, 20, "interference", "风力干扰"], [20, 30, "interference", "光照干扰"] ] self.environment_config = { 'obstacles': [], 'terrain_sequence': ['flat'] * 3, 'wind_patterns': [ {'time': [10, 20], 'force': [80, 0, 0], 'type': 'strong_wind'} ], 'light_patterns': [ {'time': [20, 30], 'intensity': 0.1, 'type': 'low_light'} ] } def get_current_scenario_state(self, current_time: float) -> Dict: """获取当前场景状态""" current_task = "idle" task_description = "待机" # 确定当前任务 for start_time, end_time, task, description in self.scenario_timeline: if start_time <= current_time < end_time: current_task = task task_description = description break # 确定当前地形 terrain_index = min(int(current_time / 6), len(self.environment_config['terrain_sequence']) - 1) current_terrain = self.environment_config['terrain_sequence'][terrain_index] # 计算当前风力 current_wind = np.zeros(3) for wind_pattern in self.environment_config['wind_patterns']: if wind_pattern['time'][0] <= current_time < wind_pattern['time'][1]: current_wind = np.array(wind_pattern['force']) break # 计算当前光照 current_light = 1.0 for light_pattern in self.environment_config['light_patterns']: if light_pattern['time'][0] <= current_time < light_pattern['time'][1]: current_light = light_pattern['intensity'] break return { 'task': current_task, 'description': task_description, 'terrain': current_terrain, 'wind': current_wind, 'light': current_light, 'obstacles': self.environment_config['obstacles'].copy(), 'time': current_time } def update_robot_state(self): """更新机器人状态""" # 模拟机器人行走 if self.get_current_scenario_state(self.current_time)['task'] == 'walking': # 简单的前进运动 self.robot.data.qpos[0] = self.current_time * 0.5 # x位置 self.robot.data.qvel[0] = 0.5 # x速度 # 添加腿部摆动动画 leg_angle = 30 * np.sin(self.current_time * 5) arm_angle = 20 * np.sin(self.current_time * 3) # 左腿关节 left_leg_joint = mujoco.mj_name2id(self.robot.model, mujoco.mjtObj.mjOBJ_JOINT, "left_leg_joint") if left_leg_joint != -1: self.robot.data.qpos[left_leg_joint] = np.deg2rad(leg_angle) # 右腿关节 right_leg_joint = mujoco.mj_name2id(self.robot.model, mujoco.mjtObj.mjOBJ_JOINT, "right_leg_joint") if right_leg_joint != -1: self.robot.data.qpos[right_leg_joint] = np.deg2rad(-leg_angle) # 左臂关节 left_arm_joint = mujoco.mj_name2id(self.robot.model, mujoco.mjtObj.mjOBJ_JOINT, "left_arm_joint") if left_arm_joint != -1: self.robot.data.qpos[left_arm_joint] = np.deg2rad(arm_angle) # 右臂关节 right_arm_joint = mujoco.mj_name2id(self.robot.model, mujoco.mjtObj.mjOBJ_JOINT, "right_arm_joint") if right_arm_joint != -1: self.robot.data.qpos[right_arm_joint] = np.deg2rad(-arm_angle) # 应用风力 wind_force = self.get_current_scenario_state(self.current_time)['wind'] if np.linalg.norm(wind_force) > 0.1: torso_id = mujoco.mj_name2id(self.robot.model, mujoco.mjtObj.mjOBJ_BODY, "torso") if torso_id != -1: self.robot.data.xfrc_applied[torso_id, 0] = wind_force[0] self.robot.data.xfrc_applied[torso_id, 1] = wind_force[1] self.robot.data.xfrc_applied[torso_id, 2] = wind_force[2] # 前向动力学计算 mujoco.mj_forward(self.robot.model, self.robot.data) def change_camera_mode(self): """切换摄像头视角""" self.visualizer.toggle_camera() def record_data(self, current_time): """记录演示数据""" self.demo_data['timestamps'].append(current_time) # 模拟能量消耗 - 根据地形和任务类型变化 energy_factor = 1.0 terrain = self.get_current_scenario_state(current_time)['terrain'] if terrain == 'slope': energy_factor = 1.5 elif terrain == 'stairs': energy_factor = 1.8 elif terrain == 'sand': energy_factor = 2.0 new_energy = self.energy_consumption[-1] + 0.1 * energy_factor self.energy_consumption.append(new_energy) # 模拟性能指标 stability = 1.0 - np.random.uniform(0, 0.1) efficiency = 1.0 - np.random.uniform(0, 0.05) self.performance_metrics.append({ 'stability': max(0.1, stability), 'efficiency': max(0.1, efficiency) }) def save_performance_data(self): """保存性能数据""" filename = f"performance_data_{time.strftime('%Y%m%d_%H%M%S')}.json" try: with open(filename, 'w') as f: json.dump({ 'timestamps': self.demo_data['timestamps'], 'energy_consumption': self.demo_data['energy_consumption'], 'performance_metrics': self.demo_data['performance_metrics'] }, f, indent=2) print(f"✅ 性能数据已保存到 {filename}") return True except Exception as e: print(f"⚠️ 保存性能数据失败: {e}") return False def handle_events(self): """处理GLFW事件""" if not self.visualizer.viewer: return True # 检查窗口是否关闭 if glfw.window_should_close(self.visualizer.viewer.window): return False # 处理键盘事件 for key, action in self.key_actions.items(): if glfw.get_key(self.visualizer.viewer.window, key) == glfw.PRESS: return action return True def run_demo(self): """运行演示""" print(f"🚀 开始演示,持续时间: {self.demo_config['duration']}秒") print("=" * 60) print("控制说明:") print(" 空格键: 暂停/继续") print(" R键: 重置演示") print(" C键: 切换摄像头视角") print(" S键: 保存性能数据") print(" V键: 开始/停止录制视频") print(" ESC: 退出程序") self.is_running = True start_time = time.time() last_frame_time = start_time try: while self.current_time < self.demo_config['duration']: # 处理事件 event_result = self.handle_events() if event_result == False: # 窗口关闭 break elif event_result == "pause": self.paused = not self.paused print(f"⏸️ {'已暂停' if self.paused else '继续运行'}") elif event_result == "reset": start_time = time.time() self.current_time = 0.0 self.demo_data = { 'timestamps': [], 'energy_consumption': [0.0], 'performance_metrics': [{'stability': 1.0, 'efficiency': 1.0}] } print("🔄 演示已重置") elif event_result == "change_camera": self.change_camera_mode() elif event_result == "save_data": self.save_performance_data() elif event_result == "toggle_recording": if self.visualizer.recording: self.visualizer.stop_recording() else: self.visualizer.start_recording() if self.paused: time.sleep(0.1) continue # 更新当前时间 current_real_time = time.time() self.current_time = current_real_time - start_time # 控制帧率 (约30FPS) if current_real_time - last_frame_time < 0.033: continue last_frame_time = current_real_time # 更新机器人状态 self.update_robot_state() # 记录数据 if self.demo_config['record_data']: self.record_data(self.current_time) # 获取当前场景状态 scenario_state = self.get_current_scenario_state(self.current_time) render_state = { 'task': scenario_state['task'], 'description': scenario_state['description'], 'terrain': scenario_state['terrain'], 'time': self.current_time, 'energy': self.energy_consumption[-1] } # 渲染可视化界面 self.visualizer.render(render_state) # 添加场景信息覆盖 self._add_info_overlay(scenario_state) self.is_running = False print("\n✅ 演示完成!") # 自动保存性能数据 if self.demo_config['record_data']: self.save_performance_data() # 停止录制 if self.visualizer.recording: self.visualizer.stop_recording() except Exception as e: self.is_running = False print(f"\n⛔ 演示出错: {e}") traceback.print_exc() # 出错时保存当前数据 if self.demo_config['record_data']: print("⚠️ 尝试保存当前性能数据...") self.save_performance_data() finally: self.visualizer.close() def _add_info_overlay(self, scenario_state): """添加信息覆盖层""" if not self.visualizer.viewer: return # 左上角信息 self.visualizer.viewer.add_overlay( mujoco.mjtGridPos.mjGRID_TOPLEFT, "场景", f"{scenario_state['description']}" ) self.visualizer.viewer.add_overlay( mujoco.mjtGridPos.mjGRID_TOPLEFT, "地形", f"{scenario_state['terrain']}" ) self.visualizer.viewer.add_overlay( mujoco.mjtGridPos.mjGRID_TOPLEFT, "时间", f"{self.current_time:.1f}s / {self.demo_config['duration']:.1f}s" ) self.visualizer.viewer.add_overlay( mujoco.mjtGridPos.mjGRID_TOPLEFT, "能量消耗", f"{self.energy_consumption[-1]:.2f} J" ) self.visualizer.viewer.add_overlay( mujoco.mjtGridPos.mjGRID_TOPLEFT, "控制模式", f"{'AI控制' if self.demo_config['enable_ai'] else '手动控制'}" ) # 右上角状态 status = "运行中" if self.is_running else "已停止" self.visualizer.viewer.add_overlay( mujoco.mjtGridPos.mjGRID_TOPRIGHT, "状态", f"{status}{' (已暂停)' if self.paused else ''}" ) # 录制状态 if self.visualizer.recording: self.visualizer.viewer.add_overlay( mujoco.mjtGridPos.mjGRID_TOPRIGHT, "录制", "⏺️ 录制中..." ) def main(): """主函数""" parser = argparse.ArgumentParser(description='人形机器人仿真演示') parser.add_argument('--scenario', type=str, default='comprehensive', choices=['comprehensive', 'walking', 'obstacle', 'terrain', 'interference'], help='演示场景类型') parser.add_argument('--duration', type=float, default=30.0, help='演示持续时间(秒)') args = parser.parse_args() # 创建演示实例 demo = HumanoidDemo() demo.demo_config['duration'] = args.duration # 设置场景 demo.setup_demo_scenario(args.scenario) # 运行演示 demo.run_demo() if __name__ == "__main__": main()
07-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值