# Parnassus - 圆柱倒立摆仿真系统

一个基于PyBullet和gRPC的圆柱倒立摆仿真服务及客户端系统，专为强化学习和控制算法研究设计。

## 概述

Parnassus是一个分布式的机械臂仿真环境，主要特性包括：

- **基于PyBullet的物理仿真**：提供真实的物理动力学模拟
- **gRPC双向流通信**：支持高效的客户端-服务器通信
- **Gymnasium兼容接口**：遵循标准的强化学习环境API
- **可配置的机械臂模型**：支持自定义URDF机械臂配置
- **实时渲染支持**：提供可视化调试和演示功能

## 系统架构

```
┌─────────────────┐    gRPC Stream    ┌─────────────────┐
│                 │ ◄──────────────── │                 │
│   gRPC Client   │                   │   gRPC Server   │
│                 │ ──────────────► │                 │
└─────────────────┘                   └─────────────────┘
                                              │
                                              ▼
                                    ┌─────────────────┐
                                    │  PyBullet Env   │
                                    │ (Gymnasium API) │
                                    └─────────────────┘
```

## 环境说明

### 圆柱倒立摆模型

- **关节0**：基座关节，力矩控制（动作范围：[-1, 1]，映射到[-max_torque, +max_torque]）
- **关节1**：肘部关节，被动关节（仅受URDF阻尼/摩擦/重力影响）
- **观测空间**：[q0, q1, dq0, dq1] （关节位置和速度）
- **动作空间**：标量力矩控制 [-1.0, 1.0]

### 物理参数

- 时间步长：0.01s (100Hz)
- 最大力矩：50.0 N⋅m
- 最大回合步数：2500步
- 重力：-9.8 m/s²

## 安装

### 环境要求

- Python >= 3.10, < 3.13
- Poetry (推荐) 或 pip

### 使用Poetry安装

```bash
# 克隆仓库
git clone <repository-url>
cd parnassus

# 安装依赖
poetry install

# 激活虚拟环境
poetry shell
```

### 使用pip安装

```bash
pip install -e .
```

## 快速开始

### 1. 启动gRPC服务器

```bash
# 使用默认配置启动服务器
python -m parnassus.commands.app serve

# 或指定端口和日志级别
python -m parnassus.commands.app serve --port 50051 --log-level INFO
```

### 2. 客户端连接示例

```python
import numpy as np
from parnassus.clients.arm_stream.client import StreamClient

# 连接到服务器
with StreamClient('localhost:50051') as client:
    client.connect()
    
    # 重置环境
    reset_obs = client.reset(seed=42)
    print(f"初始观测: {reset_obs}")
    
    # 执行动作
    for step in range(100):
        # 生成正弦波控制信号
        action = np.array([np.sin(step * 0.1)], dtype=np.float32)
        
        # 执行一步
        step_reply = client.step(action)
        
        obs = step_reply.observation
        reward = step_reply.reward
        terminated = step_reply.terminated
        truncated = step_reply.truncated
        
        print(f"步骤 {step}: 奖励={reward:.3f}, 结束={terminated}")
        
        if terminated or truncated:
            break
    
    # 关闭环境
    client.close()
```

### 3. 渲染客户端

```python
from parnassus.clients.arm_stream.render_client import RenderClient

# 带渲染的客户端
with RenderClient('localhost:50051') as client:
    client.connect()
    # ... 执行仿真逻辑
```

## API参考

### 服务器API

#### 启动服务器

```bash
python -m parnassus.commands.app serve [OPTIONS]
```

**选项：**
- `--port INTEGER`: 监听端口 (默认: 50051)
- `--max-workers INTEGER`: 最大工作线程数 (默认: 10)
- `--log-level TEXT`: 日志级别 (默认: INFO)

### 客户端API

#### StreamClient

```python
class StreamClient:
    def __init__(self, server_address: str = "localhost:50051")
    def connect(self) -> None
    def reset(self, seed: Optional[int] = None) -> np.ndarray
    def step(self, action: np.ndarray) -> StepReply
    def close(self) -> None
    def shutdown(self) -> None
```

#### RenderClient

```python
class RenderClient(StreamClient):
    def __init__(self, server_address: str = "localhost:50051", 
                 save_video: bool = False, video_path: str = "output.mp4")
```

### 环境配置

#### GymEnv参数

```python
class GymEnv:
    def __init__(self,
        urdf_path: str = "urdfs/simple_arm.urdf",
        max_torque: float = 50.0,
        time_step: float = 1.0 / 100.0,
        frame_skip: int = 1,
        max_episode_steps: int = 2500,
        anchor_position: Tuple[float, float, float] = (0.0, 0.0, 1.05)
    )
```

## 项目结构

```
parnassus/
├── src/parnassus/
│   ├── clients/              # gRPC客户端
│   │   └── arm_stream/
│   │       ├── client.py     # 基础流客户端
│   │       └── render_client.py  # 渲染客户端
│   ├── commands/             # CLI命令
│   │   └── app.py           # 服务器启动命令
│   ├── envs/                # 仿真环境
│   │   ├── arm/
│   │   │   └── gym_env.py       # Gymnasium环境实现
│   ├── protos/              # Protocol Buffers定义
│   │   └── arm_stream/
│   ├── servers/             # gRPC服务器
│   │   └── arm_stream/
│   │       └── servicer.py  # 服务器实现
│   └── utils/               # 工具函数
│       └── tensor.py        # 张量转换工具
├── tests/                   # 测试文件
├── urdfs/                   # URDF机械臂模型
└── pyproject.toml          # 项目配置
```

## 测试

运行所有测试：

```bash
poetry run pytest tests/
```

运行特定测试：

```bash
# 测试服务器
poetry run python tests/test_stream/test_server.py

# 测试客户端
poetry run python tests/test_stream/test_client.py

# 测试渲染客户端
poetry run python tests/test_stream/test_render_client.py
```

## 配置

### 环境变量

创建 `.env` 文件来配置环境变量：

```bash
# gRPC服务器配置
GRPC_PORT=50051
MAX_WORKERS=10
LOG_LEVEL=INFO

# 仿真参数
MAX_TORQUE=50.0
TIME_STEP=0.01
MAX_EPISODE_STEPS=2500
```

### URDF模型

项目包含多个URDF模型文件：

- `simple_arm.urdf`: 标准二关节机械臂
- `simple_arm_copy.urdf`: 备用配置
- `revolute_joint.urdf`: 旋转关节模型
- `cube.urdf`: 简单立方体模型

## 开发指南

### Protocol Buffers

修改gRPC接口定义后，需要重新生成Python代码：

```bash
cd tmp-workspace
./run_grpc_tools.sh
```

### 添加新功能

1. **扩展环境**：修改 `src/parnassus/envs/arm/gym_env.py`
2. **更新协议**：修改 `src/parnassus/protos/arm_stream/arm_stream.proto`
3. **实现服务**：更新 `src/parnassus/servers/arm_stream/servicer.py`
4. **客户端支持**：扩展客户端类功能

### 代码风格

项目使用以下工具保证代码质量：

- **类型检查**：mypy
- **代码格式化**：black
- **导入排序**：isort
- **静态分析**：flake8

## 故障排除

### 常见问题

1. **连接失败**
   ```
   grpc.RpcError: Connection refused
   ```
   解决方案：确保gRPC服务器已启动并监听正确端口

2. **URDF文件未找到**
   ```
   FileNotFoundError: URDF not found
   ```
   解决方案：检查URDF文件路径或使用绝对路径

3. **PyBullet显示问题**
   ```
   pybullet build_time: ...
   ```
   解决方案：安装图形驱动或使用DIRECT模式

### 调试模式

启用详细日志：

```bash
python -m parnassus.commands.app serve --log-level DEBUG
```

## 性能优化

- **并发处理**：调整 `--max-workers` 参数
- **帧跳跃**：修改 `frame_skip` 参数减少计算负载
- **渲染开销**：生产环境下禁用可视化渲染

## 许可证

本项目采用MIT许可证。详见LICENSE文件。

## 贡献

欢迎提交Issue和Pull Request！

1. Fork项目
2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 创建Pull Request

## 联系方式

- 作者：MigoXV
- 邮箱：1695587905@qq.com

## 致谢

- [PyBullet](https://pybullet.org/) - 物理仿真引擎
- [gRPC](https://grpc.io/) - 高性能RPC框架
- [Gymnasium](https://gymnasium.farama.org/) - 强化学习环境标准
