diff --git a/Go2Py/assets/cyclonedds.xml b/Go2Py/assets/cyclonedds.xml
new file mode 100644
index 0000000..795aec6
--- /dev/null
+++ b/Go2Py/assets/cyclonedds.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Go2Py/assets/mujoco/go2/go2.usd b/Go2Py/assets/mujoco/go2/go2.usd
deleted file mode 100644
index 5a1ff4d..0000000
Binary files a/Go2Py/assets/mujoco/go2/go2.usd and /dev/null differ
diff --git a/Go2Py/robot/interface.py b/Go2Py/robot/interface.py
index 7aff3ea..d630938 100644
--- a/Go2Py/robot/interface.py
+++ b/Go2Py/robot/interface.py
@@ -18,17 +18,22 @@ from cyclonedds.util import duration
from threading import Thread
from scipy.spatial.transform import Rotation
from Go2Py.joy import xKeySwitch, xRockerBtn
+from Go2Py.utils import set_cyclonedds_config
class GO2Real():
def __init__(
self,
+ interface_name=None,
mode='lowlevel', # 'highlevel' or 'lowlevel'
vx_max=0.5,
vy_max=0.4,
ωz_max=0.5,
):
assert mode in ['highlevel', 'lowlevel'], "mode should be either 'highlevel' or 'lowlevel'"
+ if interface_name is not None:
+ set_cyclonedds_config(interface_name)
+
self.mode = mode
self.simulated = False
self.prestanding_q = np.array([0.0, 1.26186061, -2.5,
@@ -50,8 +55,11 @@ class GO2Real():
self.lowcmd_topic_name = "rt/go2py/low_cmd"
self.highcmd_topic_name = "rt/go2py/high_cmd"
self.lowstate_topic_name = "rt/go2py/state"
-
- self.participant = DomainParticipant()
+ try:
+ self.participant = DomainParticipant()
+ except:
+ raise Exception('Could not initialize the DDS communication. Is the interface name provided correctly?')
+
self.lowstate_topic = Topic(self.participant, self.lowstate_topic_name, Go2pyState_)
self.state_reader = DataReader(self.participant, self.lowstate_topic)
@@ -69,6 +77,7 @@ class GO2Real():
self.state = None
self.setCommands = {'lowlevel': self.setCommandsLow,
'highlevel': self.setCommandsHigh}[self.mode]
+ self.state = Go2pyState_
self.state_thread = Thread(target=self.state_update)
self.running = True
self.state_thread.start()
diff --git a/Go2Py/utils/__init__.py b/Go2Py/utils/__init__.py
index e69de29..5a712e6 100644
--- a/Go2Py/utils/__init__.py
+++ b/Go2Py/utils/__init__.py
@@ -0,0 +1,22 @@
+import os
+import tempfile
+from Go2Py import ASSETS_PATH
+def set_cyclonedds_config(interface_name):
+ # Generate the XML configuration
+ xml_content = f"""
+
+
+
+
+
+
+
+"""
+
+ # Create a temporary XML file
+ cfg_file_path = os.path.join(ASSETS_PATH, 'cyclonedds.xml')
+ with open(cfg_file_path, 'w') as f:
+ f.write(xml_content)
+
+ # Set the environment variable
+ os.environ['CYCLONEDDS_URI'] = f'file://{cfg_file_path}'
\ No newline at end of file
diff --git a/MANIFEST.in b/MANIFEST.in
index e69de29..0a0dde4 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -0,0 +1,8 @@
+include Go2Py/assets/*.xml
+include Go2Py/assets/urdf/*.urdf
+include Go2Py/assets/mujoco/*.xml
+include Go2Py/mujoco/assets/*.obj
+include Go2Py/mujoco/dae/*.dae
+include Go2Py/assets/checkpoints/walk_these_ways/checkpoints/*.jit
+include Go2Py/assets/checkpoints/walk_these_ways/checkpoints/*.pt
+include Go2Py/assets/checkpoints/walk_these_ways/*.pkl
\ No newline at end of file
diff --git a/Makefile b/Makefile
index fda612d..29957b1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,16 @@
+INTERFACE = enx00e04c006390 # interface name used to talk with the robot
+
+# Target to run the script with the specified interface
+ddscfg:
+ python3 scripts/set_cyclonedds_config.py $(INTERFACE) && /bin/bash scripts/ros_env_setup.bash
+
frontcam:
@cd deploy && docker build --no-cache --tag go2py_frontcam_publisher:latest -f docker/Dockerfile.frontcam .
docker_start:
+ @cd .devcontainer && docker compose up go2py
+
+isaac_ros_start:
@./scripts/run_dev.sh
nav2:
diff --git a/deploy/docker/scripts/bridge_start.sh b/deploy/docker/scripts/bridge_start.sh
index 5823081..54d710c 100644
--- a/deploy/docker/scripts/bridge_start.sh
+++ b/deploy/docker/scripts/bridge_start.sh
@@ -2,6 +2,6 @@ source /opt/ros/humble/setup.bash
source /unitree_ros2/cyclonedds_ws/install/setup.bash
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
export CYCLONEDDS_URI='
-
+
'
source /bridge_ws/install/setup.bash && ros2 launch /root/launch/bridge.launch.py
\ No newline at end of file
diff --git a/docs/setup.md b/docs/setup.md
index ff23da2..9a9edcb 100644
--- a/docs/setup.md
+++ b/docs/setup.md
@@ -47,6 +47,8 @@ If everything has been successful, you should be able to access the internet on
## Installing the Docker
All the deployed services in Go2Py are based on docker so make sure that docker and Nvidia runtime is installed. For this, you can follow through the Isaac-ROS installation instructions [here](https://nvidia-isaac-ros.github.io/getting_started/hardware_setup/compute/jetson_storage.html).
+**Note:** For the LiDAR node, the `nvidia contaner toolkit` should also be installed on the robot.
+
## Installing the Go2Py
Go2Py has two main components. A set of services running on the robot and a Python package that can run anywhere and is used to communicate with the robot in Python.
@@ -70,11 +72,15 @@ sudo make bridge_install
# For the robot description service
make robot_description
sudo make robot_description_install
+```
+The first command for each service makes the corresponding docker image and the second command, copies the service file that runs those images into the appropriate locations of the system and enables them as autorun services. You can check for the success of this installation by checking the output of the `systemctl status service_name.service` command where the `service_name` is replaced with the name of the service you want to check.
+
+**Note**: At the moment, the implemented LiDAR driver service only supports the XT16 sensor. If you have this sensor on your robot run:
+```bash
# For the LiDAR driver
make hesai
sudo make hesai_install
```
-The first command for each service makes the corresponding docker image and the second command, copies the service file that runs those images into the appropriate locations of the system and enables them as autorun services. You can check for the success of this installation by checking the output of the `systemctl status service_name.service` command where the `service_name` is replaced with the name of the service you want to check.
### Installing the GoPy
#### Local Installation
@@ -82,15 +88,20 @@ Finally, we need to install the Go2Py Python library on a computer located on th
```bash
pip install -e .
```
+
+After successful installation, open the `Makefile` in the root directory and set the `INTERFACE` variable at the top of the file to the network interface name connected to the robot's network. Then, simply run `make ddscfg` to configure CycloneDDS for proper communication with the robot.
+
To check the installation, run the interface example [here](../examples/00-robot-interface.ipynb) to make sure you can read the state of the robot.
#### Using Docker
-In addition to local installation, you can use the provided docker support. To do so, run `make docker_start` in the root directory of the repository:
-```bash
-cd ~/Go2Py
-make docker_start
-```
+In addition to local installation, you can use the provided docker support:
+##### VSCode Devcontainers
+Simply install the devcontainer extension in your VSCode and press `SHIFT+Ctrl+P` and run `Rebuild and Reopen in Container` while you're in the root directory of the project.
+#### Direct
-With this, a docker container with all the required dependencies will be launched and the Go2Py repository will be mounted into `/workspaces/Go2Py` and installed in editable mode. Since our docker support is based on the Nvida Isaac-ROS images, you should be able to use the Iasaac-ROS packages within this environment.
+Runing `make docker_start` launces a container with all the requirements installed. Attach to this container and follow the local installation instructions inside the docker.
+
+#### Installation With Isaac-ROS Docker
+Running `make isaac_ros_start` starts a docker container with all the required dependencies. The Go2Py repository will be mounted into `/workspaces/Go2Py` and installed in editable mode. Inside this docker environment, you can use the Iasaac-ROS packages.
Note that our docker image may be extended in a similar way to the Isaac-ROS images (as explained [here](https://nvidia-isaac-ros.github.io/repositories_and_packages/isaac_ros_common/index.html)). Simply append the `CONFIG_IMAGE_KEY="ros2_humble.go2py"` [here](../scripts/.isaac_ros_common-config) with the key to your custom Dockerfile name (e.g. `CONFIG_IMAGE_KEY="ros2_humble.go2py.custom"` for `Dockerfile.custom`) and place your docker file under `docker` directory [here](../docker) and append its name with the key you used (e.g. `Dockerfile.custom`). Your custom Dockerfile should start with:
```docker
@@ -98,3 +109,6 @@ ARG BASE_IMAGE
FROM ${BASE_IMAGE}
```
In addition to this added docker image layer, you can add your own post execution commands that are excuted each time you start the docker container. These commands should be appended to the end of `workspace-entrypoint.sh` script [here](../docker/scripts/workspace-entrypoint.sh).
+
+#### Enabling GUI Access
+In case you're interested in running the simulations inside the docker with GUI support, you need to run `xhost +` on your host terminal to allow X11 requests from the applications inside the Docker.
\ No newline at end of file
diff --git a/multicast_config.py b/multicast_config.py
new file mode 100644
index 0000000..bc46f7d
--- /dev/null
+++ b/multicast_config.py
@@ -0,0 +1,63 @@
+import argparse
+import subprocess
+
+
+def configure_multicast(device_name):
+ """
+ Configures multicast settings for a given network device.
+
+ @param device_name: The name of the network device to configure.
+ @type device_name: str
+
+ @raises subprocess.CalledProcessError: If the execution of any command fails.
+
+ @note:
+ This function requires administrative privileges to execute commands like 'route' and 'ifconfig'.
+ Run the Python script as a superuser or provide the necessary credentials.
+
+ @example:
+ device = 'eth0'
+ configure_multicast(device)
+ """
+
+ add_route_command = [
+ "route",
+ "add",
+ "-net",
+ "224.0.0.0",
+ "netmask",
+ "240.0.0.0",
+ "dev",
+ device_name,
+ ]
+ enable_multicast_command = ["sudo", "ifconfig", device_name, "multicast"]
+
+ subprocess.run(add_route_command, check=True)
+ subprocess.run(enable_multicast_command, check=True)
+
+
+def main():
+ """
+ Main entry point of the script.
+ Parses the command-line arguments and invokes the configuration function.
+ """
+
+ # Create an argument parser
+ parser = argparse.ArgumentParser(
+ description="Configure multicast settings for a network interface."
+ )
+
+ # Add the interface name argument
+ parser.add_argument(
+ "interface", type=str, help="The name of the network interface to configure."
+ )
+
+ # Parse the command-line arguments
+ args = parser.parse_args()
+
+ # Invoke the configuration function
+ configure_multicast(args.interface)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/ros_env_setup.bash b/scripts/ros_env_setup.bash
new file mode 100755
index 0000000..23df53f
--- /dev/null
+++ b/scripts/ros_env_setup.bash
@@ -0,0 +1,4 @@
+source /opt/ros/humble/setup.bash
+source /unitree_ros2/cyclonedds_ws/install/setup.bash
+export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
+export CYCLONEDDS_URI=file://$(pwd)/Go2Py/assets/cyclonedds.xml
\ No newline at end of file
diff --git a/scripts/set_cyclonedds_config.py b/scripts/set_cyclonedds_config.py
new file mode 100644
index 0000000..d4aed89
--- /dev/null
+++ b/scripts/set_cyclonedds_config.py
@@ -0,0 +1,14 @@
+from Go2Py.utils import set_cyclonedds_config
+import argparse
+
+def main():
+ # Set up argument parsing
+ parser = argparse.ArgumentParser(description="Set CycloneDDS configuration.")
+ parser.add_argument("network_interface", help="The name of the network interface used to communicate with the robot.")
+ # Parse the arguments
+ args = parser.parse_args()
+ # Set the CycloneDDS configuration
+ set_cyclonedds_config(args.network_interface)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file