File size: 6,555 Bytes
700dd75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
FROM nvgear/ros-2:latest

# Accept build argument for username
ARG USERNAME
ARG USERID
ARG HOME_DIR
ARG WORKTREE_NAME

# Create user with the same name as host
RUN if [ "$USERID" != "0" ]; then \
        useradd -m -u ${USERID} -s /bin/bash ${USERNAME} && \
        echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
        # Add user to video and render groups for GPU access
        usermod -a -G video,render ${USERNAME} || true; \
    fi

# Copy .bashrc with color settings before switching user
COPY --chown=${USERNAME}:${USERNAME} decoupled_wbc/docker/.bashrc ${HOME_DIR}/.bashrc

# Install Manus udev rules
COPY --chown=${USERNAME}:${USERNAME} decoupled_wbc/docker/70-manus-hid.rules /etc/udev/rules.d/70-manus-hid.rules

# Copy tmux configuration
COPY --chown=${USERNAME}:${USERNAME} decoupled_wbc/docker/.tmux.conf ${HOME_DIR}/.tmux.conf

# Switch to user
USER ${USERNAME}

# Install tmux plugin manager and uv in parallel
RUN git clone https://github.com/tmux-plugins/tpm ${HOME_DIR}/.tmux/plugins/tpm & \
    curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=${HOME_DIR}/.cargo/bin sh & \
    wait

# Install tmux plugins automatically
RUN ${HOME_DIR}/.tmux/plugins/tpm/bin/install_plugins || true

# Add uv to PATH
ENV PATH="${HOME_DIR}/.cargo/bin:$PATH"
ENV UV_PYTHON=${HOME_DIR}/venv/bin/python

# Create venv
RUN uv venv --python 3.10 ${HOME_DIR}/venv

# Install hardware-specific packages (x86 only - not available on ARM64/Orin)
USER root
COPY --chown=${USERNAME}:${USERNAME} decoupled_wbc/control/teleop/device/pico/XRoboToolkit_PC_Service_1.0.0_ubuntu_22.04_amd64.deb ${HOME_DIR}/XRoboToolkit_PC_Service_1.0.0_ubuntu_22.04_amd64.deb
COPY --chown=${USERNAME}:${USERNAME} decoupled_wbc/control/teleop/device/pico/roboticsservice_1.0.0.0_arm64.deb ${HOME_DIR}/roboticsservice_1.0.0.0_arm64.deb

RUN if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
        # Ultra Leap setup
        wget -qO - https://repo.ultraleap.com/keys/apt/gpg | gpg --dearmor | tee /etc/apt/trusted.gpg.d/ultraleap.gpg && \
        echo 'deb [arch=amd64] https://repo.ultraleap.com/apt stable main' | tee /etc/apt/sources.list.d/ultraleap.list && \
        apt-get update && \
        echo "yes" | DEBIAN_FRONTEND=noninteractive apt-get install -y ultraleap-hand-tracking libhidapi-dev && \
        # Space Mouse udev rules
        echo 'KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"' > /etc/udev/rules.d/99-hidraw-permissions.rules && \
        usermod -aG plugdev ${USERNAME}; \
        # Pico setup
        apt-get install -y xdg-utils && \
        dpkg -i ${HOME_DIR}/XRoboToolkit_PC_Service_1.0.0_ubuntu_22.04_amd64.deb; \
    else \
        echo "Skipping x86-only hardware packages on $(dpkg --print-architecture)"; \
    fi

USER ${USERNAME}
# Install hardware Python packages (x86 only) with caching
RUN --mount=type=cache,target=${HOME_DIR}/.cache/uv,uid=${USERID},gid=${USERID} \
    if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
        # Ultra Leap Python bindings
        git clone https://github.com/ultraleap/leapc-python-bindings ${HOME_DIR}/leapc-python-bindings && \
        cd ${HOME_DIR}/leapc-python-bindings && \
        UV_CONCURRENT_DOWNLOADS=8 uv pip install -r requirements.txt && \
        MAKEFLAGS="-j$(nproc)" ${HOME_DIR}/venv/bin/python -m build leapc-cffi && \
        uv pip install leapc-cffi/dist/leapc_cffi-0.0.1.tar.gz && \
        uv pip install -e leapc-python-api && \
        # Space Mouse Python package
        uv pip install pyspacemouse && \
        # Pico Python bindings
        git clone https://github.com/XR-Robotics/XRoboToolkit-PC-Service-Pybind.git ${HOME_DIR}/XRoboToolkit-PC-Service-Pybind && \
        cd ${HOME_DIR}/XRoboToolkit-PC-Service-Pybind && \
        uv pip install setuptools pybind11 && \
        sed -i "s|pip install|uv pip install|g" setup_ubuntu.sh && \
        sed -i "s|pip uninstall|uv pip uninstall|g" setup_ubuntu.sh && \
        sed -i "s|python setup.py install|${HOME_DIR}/venv/bin/python setup.py install|g" setup_ubuntu.sh && \
        bash setup_ubuntu.sh; \
    fi

# Install Python dependencies using uv with caching
RUN --mount=type=cache,target=${HOME_DIR}/.cache/uv,uid=${USERID},gid=${USERID} \
    UV_CONCURRENT_DOWNLOADS=8 uv pip install --upgrade pip ipython jupyter notebook debugpy


# Copy entire project to the workspace directory where it will be mounted at runtime
# NOTE: The build context must be the project root for this to work
# Use dynamic worktree name to match runtime mount path
COPY --chown=${USERNAME}:${USERNAME} . ${HOME_DIR}/Projects/${WORKTREE_NAME}

# Install Python dependencies inside the venv with caching - split into separate commands
RUN --mount=type=cache,target=${HOME_DIR}/.cache/uv,uid=${USERID},gid=${USERID} \
    UV_CONCURRENT_DOWNLOADS=8 uv pip install \
    -e ${HOME_DIR}/Projects/${WORKTREE_NAME}/external_dependencies/unitree_sdk2_python

# Unlike pip, uv downloads LFS files by default. There's a bug in uv that causes LFS files
# to fail to download (https://github.com/astral-sh/uv/issues/3312). So we need to set
# UV_GIT_LFS=1 to prevent uv from downloading LFS files.
# Install project packages (decoupled_wbc + gear_sonic) with caching
RUN --mount=type=cache,target=${HOME_DIR}/.cache/uv,uid=${USERID},gid=${USERID} \
    GIT_LFS_SKIP_SMUDGE=1 UV_CONCURRENT_DOWNLOADS=8 uv pip install \
    -e "${HOME_DIR}/Projects/${WORKTREE_NAME}/decoupled_wbc[full,dev]" \
    -e "${HOME_DIR}/Projects/${WORKTREE_NAME}/gear_sonic[sim]"

# Clone and install robosuite with specific branch
RUN --mount=type=cache,target=${HOME_DIR}/.cache/uv,uid=${USERID},gid=${USERID} \
    git clone https://github.com/xieleo5/robosuite.git ${HOME_DIR}/robosuite && \
    cd ${HOME_DIR}/robosuite && \
    git checkout leo/support_g1_locomanip && \
    UV_CONCURRENT_DOWNLOADS=8 uv pip install -e .

# Install gr00trobocasa
RUN --mount=type=cache,target=${HOME_DIR}/.cache/uv,uid=${USERID},gid=${USERID} \
    UV_CONCURRENT_DOWNLOADS=8 uv pip install -e ${HOME_DIR}/Projects/${WORKTREE_NAME}/decoupled_wbc/dexmg/gr00trobocasa

# Configure bash environment with virtual environment and ROS2 setup
RUN echo "source ${HOME_DIR}/venv/bin/activate" >> ${HOME_DIR}/.bashrc && \
    echo "source /opt/ros/humble/setup.bash" >> ${HOME_DIR}/.bashrc && \
    echo "export ROS_LOCALHOST_ONLY=1" >> ${HOME_DIR}/.bashrc && \
    echo "export PYTHONPATH=${HOME_DIR}/Projects/${WORKTREE_NAME}:\${PYTHONPATH}" >> ${HOME_DIR}/.bashrc

# Default command (can be overridden at runtime)
CMD ["/bin/bash"]