This repository includes the code to visualize and interact with the robot in Viser and PyBullet.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
⚠️ These PyBullet recordings were taken in a previous version, now the robot is colored
For a complete overview of the project, refer to the main Hexapod repository.
The simulation runs the real firmware core in-process. The Hexapod-Firmware C++ code is compiled into a shared library, and a small ctypes bridge lets Python call it. The same Pi-side Hexapod-Controller that talks to the real board drives this library instead of a serial port, and the Hexapod-Hardware URDF and meshes are rendered on top.
The three repositories are pulled in as submodules at the repo root:
Hexapod-Controller # Pi-side hexapod client package, installed editable
Hexapod-Firmware # C++ core, compiled into bridge/libhexapod_fw.so
Hexapod-Hardware # URDF + STL meshes the renderers use
bridge/ # sim_bridge.cpp + build.sh, the ctypes glue
simulation/ # the sim package, with the viser and bullet front-ends
Two versions of the robot currently exist. Each branch pins its own commits of the submodules.
| Branch | What differs |
|---|---|
main |
Original version |
new-tibia |
Tibia redesigned, bigger range of motion. The attachment point is unchanged, so the URDF's joints are identical between the two. What differs is the mesh and the config that describes it to the kinematic model. |
⚠️ ️A submodule is pinned by commit, not by branch, so checking out a branch here does not move the submodules with it. Always follow the checkout with an update, or you get one version's meshes driven by the other version's config:
git checkout new-tibia && git submodule update --init --recursivegit checkout main && git submodule update --init --recursiveThat leaves each submodule on a detached HEAD at the pinned commit, which is normal here — attach to a branch only when you intend to commit something.
Rerun ./bridge/build.sh whenever the Hexapod-Firmware pointer moves. A libhexapod_fw.so older than the firmware's protocol rejects provisioning (mismatch in args size), and the core falls back to its baked-in defaults: the robot then ignores config.yml entirely, which looks like a kinematics bug but is a stale build. The warning is printed at startup.
You need a C++ compiler (g++) to build the firmware core and mamba (or conda) for the Python environment.
-
Clone the repository with its submodules:
git clone --recursive https://github.com/ggldnl/Hexapod-Simulation.git cd Hexapod-SimulationIf you already cloned without
--recursive, pull the submodules in:git submodule update --init --recursive
To bump the submodules to their latest upstream commit later:
git submodule update --recursive --remote
Hexapod-Firmware and Hexapod-Controller being submodules means we can edit them locally, recompile and immediately test the change in simulation.
-
Build the firmware core into a shared library:
./bridge/build.sh
This compiles the Hexapod-Firmware C++ core into
bridge/libhexapod_fw.so. Rerun it whenever the firmware submodule changes. -
Create the environment:
mamba env create -f environment.yml mamba activate hexapod-sim
This installs the dependencies and the Hexapod-Controller submodule in editable mode, so
import hexapodworks inside the environment.
The front-ends run as modules from the repository root, with the hexapod-sim environment active.
-
Viser browser demo:
python -m simulation.viser.main
Open the printed URL (default http://localhost:8080). Viser has no physics, so the body stays put and the legs cycle in place while you drive the gait from the control panel.
The Kinematic model panel draws the model from
config.ymlover the mesh: the leg chains, the ground plane the firmware thinks it is standing on, the foot contacts and their support polygon, and the stance the config asks for. Turn the meshes off to read the skeleton on its own. The board is provisioned from that sameconfig.ymlat startup (--config PATH, or--no-provisionto keep the firmware's baked defaults). -
PyBullet physics demo, showing how the robot behaves once physics is involved. It uses the stall torque the servos are rated for to model the motors and uses accurate body mass (as if the parts were printed in ABS):
python -m simulation.bullet.main
-
PyBullet teleop, driving the robot live with a game controller (PS3/Xbox-style) or the keyboard:
python -m simulation.bullet.teleop # joystick if present, else keyboard python -m simulation.bullet.teleop --calibrate # print live axis/button indices for your pad
Left stick translates, right stick turns and tilts the body, hold R1 as a deadman. Keyboard fallback:
WASDto move,Q/Eto turn,R/Ffor height,1/2/3to switch gait. See the module docstring for the full mapping.
Feel free to contribute by opening issues or submitting pull requests. For further information, check out the main Hexapod repository. Give a ⭐️ to this project if you liked the content.





