devcontainer docker support and DDS network interfcace configuraion settings are added
This commit is contained in:
parent
d4b8412dc0
commit
99f8eb3a6a
|
@ -0,0 +1,9 @@
|
|||
<CycloneDDS>
|
||||
<Domain>
|
||||
<General>
|
||||
<Interfaces>
|
||||
<NetworkInterface name="enx00e04c006390" priority="default" multicast="default" />
|
||||
</Interfaces>
|
||||
</General>
|
||||
</Domain>
|
||||
</CycloneDDS>
|
Binary file not shown.
|
@ -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"
|
||||
try:
|
||||
self.participant = DomainParticipant()
|
||||
except:
|
||||
raise Exception('Could not initialize the DDS communication. Is the interface name provided correctly?')
|
||||
|
||||
self.participant = DomainParticipant()
|
||||
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()
|
||||
|
|
|
@ -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"""<CycloneDDS>
|
||||
<Domain>
|
||||
<General>
|
||||
<Interfaces>
|
||||
<NetworkInterface name="{interface_name}" priority="default" multicast="default" />
|
||||
</Interfaces>
|
||||
</General>
|
||||
</Domain>
|
||||
</CycloneDDS>"""
|
||||
|
||||
# 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}'
|
|
@ -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
|
9
Makefile
9
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:
|
||||
|
|
|
@ -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='<CycloneDDS><Domain><General><Interfaces>
|
||||
<NetworkInterface name="eth0" priority="default" multicast="default" />
|
||||
<NetworkInterface name="enx00e04c006390" priority="default" multicast="default" />
|
||||
</Interfaces></General></Domain></CycloneDDS>'
|
||||
source /bridge_ws/install/setup.bash && ros2 launch /root/launch/bridge.launch.py
|
|
@ -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.
|
|
@ -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()
|
|
@ -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
|
|
@ -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()
|
Loading…
Reference in New Issue