Robosuite Joycon Web Control System
The browser-based Nintendo Switch Joy-Con remote control solution utilizes WebSocket and Robosuite simulation environments for real-time interaction, supporting single-arm / dual-arm, multiple robots, and local area network remote operation.
🌟 Key Highlights
- ✅ Browser as remote control: Gamepad API reads Joy-Con input, front-end 60 Hz sampling
- ✅ Real-time bidirectional communication: Low-latency WebSocket push to Python backend
- ✅ Full Robosuite compatibility: Reuses official
Deviceinterface, supports OSC / Whole Body controllers - ✅ Single / dual Joy-Con: Default single arm, can also control dual-armed tasks with one on each side
- ✅ Graphical interface monitoring: Real-time display of button states, joystick status, and connection information
- ✅ Cross-platform: Supports Linux, Windows (including WSL2), and macOS; Joy-Con can be connected via Bluetooth only
🧠 System Architecture
┌─────────────┐ WebSocket ┌──────────────┐
│ 浏览器 │ ←────────────────────────→ │ Python 服务器 │
│ (前端界面) │ 60Hz 手柄数据 │ (Robosuite) │
└─────────────┘ └──────────────┘
↑ ↓
│ │
Gamepad API Robosuite 仿真
(Joy-Con) (机器人控制)
⚡ Quick 5-minute experience
Requires Python ≥3.8, Bun/Node.js, and Bluetooth Joy-Con. (Recommended)
-
Obtain the code & install dependencies
bashcd /home/kewei/17robo/robosuite-joycon-web bun install pip install -r requirements.txt # 安装 robosuite(首次运行需要) cd /home/kewei/17robo/robosuite-joycon pip install -e . cd /home/kewei/17robo/robosuite-joycon-web -
Run a no-render self-check (suitable for WSL/server)
bash
python test_server_no_render.py
The appearance of ✅ 所有测试通过! indicates that the backend logic is functioning properly.
-
Bluetooth connection to Joy-Con
- Long-press the side sync button of Joy-Con, and the indicator light flashes
- Select
Joy-Con (R)/Joy-Con (L)in the system Bluetooth settings for connection
-
Start the backend & frontend
bash# 终端 1: 单手柄默认环境(Lift + Panda) ./start_single.sh # 终端 2: React 前端 bun run devBrowser access prompt address (default: http://localhost:5173 ).
-
Start remote control
- Click “Connect to Server” in the web page
- Press any Joy-Con button to activate the Gamepad
- Then you can control the robot in real time
No monitor / WSL environment: If it is not convenient to enable rendering, replace
has_rendererinserver.pywithFalsefor operation.
🚀 Details of the startup method
1. Backend server
| Mode | Command | Description |
|---|---|---|
| Default single handle | ./start_single.sh |
Lift + Panda, port 8765 |
| Custom single handle | ./start_single.sh [环境] [机器人] [端口] |
e.g. ./start_single.sh PickPlaceCan Sawyer 9000 |
| Default dual handles | ./start_bimanual.sh |
TwoArmLift + Panda×2, parallel configuration |
| Custom dual handles | ./start_bimanual.sh [环境] [机器人1] [机器人2] [配置] [端口] |
Configuration can be parallel or opposed |
| Core function test | python test_server_no_render.py |
Must run in no rendering environment, used for CI/diagnostics |
2. Front-end Interface
bashcd /home/kewei/17robo/robosuite-joycon-web
bun run dev
Browser access terminal prompts for address (default http://localhost:5173),界面实时展示连接状态、按钮/摇杆读数。)
🎮 Control Mapping (Joy-Con Default Layout)
| Input | Function |
|---|---|
| Left joystick X / Y | End point X / Y translation |
| R (right handle) / L (left handle) | End point upward (Z+) |
| Joystick press | End point downward (Z−) |
| Right joystick X | Yaw rotation |
| Right joystick Y | Pitch rotation |
| SL / SR | Roll fine-tuning (right handle forward/backward, left handle reverse) |
| ZR / ZL | Graver on/off switch (toggle state with a press) |
| + (Plus) | Trigger environment reset |
| HOME | Pose return to initial offset |
| A / Y | Reserved event flag (consistent with the original JoyConController interface) |
All inputs are debounced and normalized in JoyconWebController. The backend output remains a 6+1-dimensional action vector, fully compatible with the Robosuite official controller.
ℹ️ By default, the browser can only read button/joystick inputs through the Gamepad API. Therefore, you need to use the right joystick and SL/SR for posture adjustment. After enabling the WebHID experimental feature below, you can directly control the end-effector posture by rotating the Joy-Con, just like with a native controller.
WebHID Version IMU Support (Experimental Feature)
- In Chrome/Edge (requires HTTPS or
localhost), click the “Connect Joy-Con IMU” button to access the Joy-Con sensors via WebHID. - After successful connection, the web page will display Roll/Pitch/Yaw in real time and send them back to the server, enabling a “rotating Joy-Con control posture” experience.
- Currently, each browser session supports connecting only to 1 Joy-Con; to switch, please refresh the page and reconnect.
- Browsers that do not support WebHID will maintain the original “joystick + SL/SR” control mode.
🧪 Test List
It is recommended to run it fully after going live or making major changes. Check the box to indicate approval.
Basic Environment
- [ ] Python dependency installation successful
- [ ] Bun frontend dependency installation successful
- [ ] Joy-Con Bluetooth connection stable
Core Functions
- [ ]
python test_server_no_render.pyis enabled - [ ] Single handle mode can initiate and execute actions
- [ ] Dual handle mode allows separate control of left and right arms
- [ ] Grasper switching and activation are timely
- [ ] 20 Hz control cycles are stable
Interface and Communication
- [ ] Browser can recognize Joy-Con (button highlighted)
- [ ] WebSocket status shows “Connected”
- [ ] Control is restored after disconnection/reconnect
Performance
- [ ] Control latency < 100 ms
- [ ] No significant drift during long-term operation (>30 min)
For more detailed steps, see the output and historical test records of test_server_no_render.py.
🛠️ Common Issues & Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
Action vector ... got 12 |
Incorrect action dimension | Fixed. Ensure using the current version server.py |
| Server gets stuck in WSL | GUI rendering blocking | Turn off rendering: has_renderer=False, or configure X11 / VNC |
| Frontend cannot recognize Joy-Con | Gamepad not activated | Press any button in the browser; refresh the page; check Bluetooth connection |
| WebSocket connection fails | Port occupied or service not running | Check backend logs; lsof -i :8765; pkill -f "python server.py" |
| Large control latency | Network or CPU busy | Recommended: run locally; close irrelevant programs; remote only within a local network |
Tips for beginners: First, run
python test_server_no_render.py, and ensure the core control is correct before integrating rendering and front-end components.
📊 Project Status Overview
- Release Date: 2025-10-05
- Version: v1.0.0
- Completion Level: ✅ Fully functional
- Features Included: Gamepad API, WebSocket service, single/double Joy-Con, front-end monitoring, scripted startup, automated testing
- Performance Metrics:
- Control frequency ~20 Hz
- Controller sampling 60 Hz
- WebSocket latency <5 ms (local)
- No rendering, CPU usage <30%
🔍 Technical Implementation & Fix Key Points
- Fully reuse the
robosuite.devices.Devicelogic:input2action,get_arm_action, and the pose and coordinate system conversion remain consistent - The output action dimension is fixed at 6 (end pose) + 1 (grasper), compatible with OSC and Whole Body IK controllers
- Use button edge detection to eliminate keystroke noise, and ZR/ZL for switching the grasper state
test_server_no_render.pyis used to verify action vectors, reward returns, and continuous control- The Start scripts
start_single.sh/start_bimanual.shencapsulate common parameters for easy deployment
📂 Overview of Directory and Scripts
| Path | Description |
|---|---|
server.py |
WebSocket server & JoyconWebController core implementation |
src/App.tsx |
React front-end UI, real-time controller visualization |
start_single.sh / start_bimanual.sh |
Launch scripts (single-arm / dual-arm) |
test_server_no_render.py |
No-render automated testing scripts |
package.json / bun.lock |
Front-end dependency definitions |
requirements.txt |
Python dependency list |
🧭 What can be done next?
- 🚗 Connect to the mobile base or custom robot to expand action mappings in
server.py. - 🌐 Deploy on a local network server, combined with HTTPS / WebRTC remote control.
- 🧪 Integrate with CI: run
python test_server_no_render.pyin the pipeline. - 🧩 If additional sensors (IMU/camera) are required, the WebSocket message format can be further extended.
If you need to add or modify documents, simply update this README to ensure all information is synchronized. Good luck with your operations! 🎉