Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NASA Challenge_[mikami235]_[Adding explanation of how to use and modifying Dokcerfile for "Natural language controls Rover by generative AI"] #179

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion moveit2/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# VERSION - The version of Space ROS (default: "preview")

FROM osrf/space-ros:latest
#FROM moveit/moveit2:humble-release

# Define arguments used in the metadata definition
ARG VCS_REF
Expand All @@ -44,6 +45,7 @@ RUN mkdir ${SPACEROS_DIR}/src \

# Define key locations
ENV MOVEIT2_DIR=${HOME_DIR}/moveit2
ENV ROSDISTRO=humble

# Make sure the latest versions of packages are installed
# Using Docker BuildKit cache mounts for /var/cache/apt and /var/lib/apt ensures that
Expand Down Expand Up @@ -125,11 +127,12 @@ RUN vcs import src < /tmp/moveit2_tutorials.repos
# a possible inherited 'insteadof' from the host that forces use of ssh
RUN sudo chown -R ${USERNAME}:${USERNAME} ${MOVEIT2_DIR}


# Install system dependencies
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
/bin/bash -c 'source ${SPACEROS_DIR}/install/setup.bash' \
&& rosdep install --from-paths ../spaceros/src src --ignore-src --rosdistro ${ROSDISTRO} -r -y --skip-keys "console_bridge generate_parameter_library fastcdr fastrtps rti-connext-dds-5.3.1 urdfdom_headers rmw_connextdds ros_testing rmw_connextdds rmw_fastrtps_cpp rmw_fastrtps_dynamic_cpp composition demo_nodes_py lifecycle rosidl_typesupport_fastrtps_cpp rosidl_typesupport_fastrtps_c ikos diagnostic_aggregator diagnostic_updater joy qt_gui rqt_gui rqt_gui_py"
&& rosdep install --from-paths ${SPACEROS_DIR}/src src --ignore-src --rosdistro ${ROSDISTRO} -r -y --skip-keys "console_bridge generate_parameter_library fastcdr fastrtps rti-connext-dds-5.3.1 urdfdom_headers rmw_connextdds ros_testing rmw_connextdds rmw_fastrtps_cpp rmw_fastrtps_dynamic_cpp composition demo_nodes_py lifecycle rosidl_typesupport_fastrtps_cpp rosidl_typesupport_fastrtps_c ikos diagnostic_aggregator diagnostic_updater joy qt_gui rqt_gui rqt_gui_py"

# Apply a patch to octomap_msgs to work around a build issue
COPY --chown=${USERNAME}:${USERNAME} octomap_fix.diff ./src/octomap_msgs
Expand Down
3 changes: 2 additions & 1 deletion moveit2/build.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env bash

ORG=openrobotics
#ORG=openrobotics
ORG=moveit
IMAGE=moveit2
TAG=latest

Expand Down
3 changes: 2 additions & 1 deletion moveit2/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# docker
# an X server

IMG_NAME=openrobotics/moveit2
#IMG_NAME=openrobotics/moveit2
IMG_NAME=moveit/moveit2

# Replace `/` with `_` to comply with docker container naming
# And append `_runtime`
Expand Down
54 changes: 47 additions & 7 deletions space_robots/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
# VCS_REF - The git revision of the Space ROS source code (no default value).
# VERSION - The version of Space ROS (default: "preview")

FROM openrobotics/moveit2:latest
#FROM openrobotics/moveit2:latest
FROM moveit/moveit2:humble-source

# Define arguments used in the metadata definition
ARG VCS_REF
Expand All @@ -39,6 +40,7 @@ LABEL org.label-schema.vcs-ref=${VCS_REF}
ENV DEMO_DIR=${HOME_DIR}/demos_ws
ENV IGNITION_VERSION fortress
ENV GZ_VERSION fortress
#ENV SPACEROS_DIR=/opt/spaceros

# Disable prompting during package installation
ARG DEBIAN_FRONTEND=noninteractive
Expand Down Expand Up @@ -75,30 +77,68 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
# Compile mongo cxx driver https://mongocxx.org/mongocxx-v3/installation/linux/
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
sudo apt-get install libssl-dev build-essential devscripts debian-keyring fakeroot debhelper cmake libboost-dev libsasl2-dev libicu-dev libzstd-dev doxygen -y
sudo apt-get install libssl-dev build-essential devscripts debian-keyring fakeroot debhelper cmake libboost-dev libsasl2-dev libicu-dev libzstd-dev doxygen wget -y

RUN wget https://github.com/mongodb/mongo-cxx-driver/releases/download/r3.6.7/mongo-cxx-driver-r3.6.7.tar.gz
RUN tar -xzf mongo-cxx-driver-r3.6.7.tar.gz
RUN cd mongo-cxx-driver-r3.6.7/build && cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local && sudo cmake --build . --target EP_mnmlstc_core && cmake --build . && sudo cmake --build . --target install

# Get the source for the dependencies
# RUN vcs import src < /tmp/demo_generated_pkgs.repos
ENV SPACEROS_DIR=/root/ws_moveit
ENV MOVEIT2_DIR=${SPACEROS_DIR}

RUN echo "SPACEROS_DIR is set to: ${SPACEROS_DIR}"

COPY --chown=${USERNAME}:${USERNAME} demo_manual_pkgs.repos /tmp/
RUN vcs import src < /tmp/demo_manual_pkgs.repos && /bin/bash -c 'source "${SPACEROS_DIR}/install/setup.bash"'
RUN vcs import src < /tmp/demo_manual_pkgs.repos
RUN /bin/bash -c 'source "${SPACEROS_DIR}/install/setup.bash"'

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
sudo apt-get update -y \
&& /bin/bash -c 'source "${SPACEROS_DIR}/install/setup.bash"' \
&& /bin/bash -c 'source "${MOVEIT2_DIR}/install/setup.bash"' \
&& rosdep install --from-paths src --ignore-src -r -y --rosdistro ${ROSDISTRO}
sudo apt-get update -y

RUN echo "MOVEIT2_DIR is set to: ${MOVEIT2_DIR}"

RUN /bin/bash -c 'source "${SPACEROS_DIR}/install/setup.bash"'
RUN /bin/bash -c 'source "${MOVEIT2_DIR}/install/setup.bash"'

RUN sudo apt-get update && sudo apt-get install -y curl gnupg2 lsb-release \
&& curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.key | sudo apt-key add - \
&& sudo sh -c 'echo "deb http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list' \
&& sudo apt-get update

RUN sudo apt-get update && sudo apt-get install -y vim python3-pip


ENV ROSDISTRO=humble
RUN rosdep install --from-paths src --ignore-src -r -y --rosdistro ${ROSDISTRO}

# Build the demo
RUN /bin/bash -c 'source ${SPACEROS_DIR}/install/setup.bash && source ${MOVEIT2_DIR}/install/setup.bash \
&& colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release'

ENV USERNAME=root

RUN echo "USERNAME is set to: $USERNAME"


# Add the user to the render group so that the user can access /dev/dri/renderD128
RUN sudo usermod -aG render $USERNAME

# Create /demo_ws/ directory and copy new files
RUN mkdir -p /demos_ws/
COPY generate_src.py /demos_ws/
COPY sample_code_by_gpt.py /demos_ws/
COPY sample_code_turn_left_by_gpt.py /demos_ws/
COPY config.json /demos_ws/
COPY prompt.txt /demos_ws/

# Grant execute permissions to Python scripts (if needed)
RUN chmod +x /demos_ws/generate_src.py /demos_ws/sample_code_by_gpt.py /demos_ws/sample_code_turn_left_by_gpt.py

RUN pip install openai

# Setup the entrypoint
COPY ./entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
Expand Down
20 changes: 20 additions & 0 deletions space_robots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@ Close the mast (camera arm)
ros2 service call /mast_close std_srvs/srv/Empty
```

##### Generate codes for moving rover by OpenAI API

Step.1 Initial settingsi

Check the config.json for input your API-Key and the LLM model you want to

Step.2 After run the launch demo command, run the code

```bash
python3 generate_src.py
```
("openai" of python module is verified in the version 1.44.0)


Step.3 Automatically saving the generated code by LLM

```bash
gen_script_20240907_0835.py
```

#### Canadarm demo

```bash
Expand Down
4 changes: 3 additions & 1 deletion space_robots/build.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#!/usr/bin/env bash

ORG=openrobotics
#ORG=openrobotics
ORG=osrf
IMAGE=space_robots_demo
#IMAGE=space-ros
TAG=latest

VCS_REF=""
Expand Down
5 changes: 5 additions & 0 deletions space_robots/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"openai_api_key": "SK-xxxxx",
"openai_model": "gpt-4o-2024-08-06"
}

5 changes: 5 additions & 0 deletions space_robots/config_dummy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"openai_api_key": "sk-XXXXX",
"openai_model": "gpt-4o-2024-08-06"
}

79 changes: 79 additions & 0 deletions space_robots/generate_src.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import json
from openai import OpenAI
import subprocess
import os
import sys
from datetime import datetime

def load_config(file_path):
try:
with open(file_path, 'r') as file:
return json.load(file)
except FileNotFoundError:
print(f"Error: {file_path} not found.")
sys.exit(1)
except json.JSONDecodeError:
print(f"Error: {file_path} is not a valid JSON file.")
sys.exit(1)

def load_prompt(file_path):
try:
with open(file_path, "r") as f:
return f.read()
except FileNotFoundError:
print(f"Error: {file_path} not found.")
sys.exit(1)

def get_chat_response(client, prompt, model):
try:
response = client.chat.completions.create(
model=model,
messages=[
{"role": "user", "content": prompt},
]
)
return response.choices[0].message.content.strip()
except Exception as e:
print(f"Error getting response from GPT: {e}")
sys.exit(1)

def remove_backticks(code_str):
if code_str.startswith("```python"):
code_str = code_str[len("```python"):].strip()
if code_str.endswith("```"):
code_str = code_str[:-len("```")].strip()
return code_str

def generate_python_script(res):
python_code = remove_backticks(res)
current_time = datetime.now().strftime("%Y%m%d_%H%M")
filename = f"gen_script_{current_time}.py"
with open(filename, "w") as f:
f.write(python_code)
return filename

def run_python_script(filename):
result = subprocess.run(["python3", filename], capture_output=True, text=True)
if result.returncode != 0:
print(f"Error executing script: {result.stderr}")
else:
print(f"Script output: {result.stdout}")

def main():
config = load_config('config.json')
client = OpenAI(api_key=config['openai_api_key'])

pre_prompt = load_prompt("prompt.txt")
print("Pre-prompt loaded successfully")

print("Please input command like 'Go forward 10 seconds' and push enter-key")
user_input = input("")
prompt = pre_prompt + user_input

res = get_chat_response(client, prompt, config['openai_model'])
filename = generate_python_script(res)
run_python_script(filename)

if __name__ == "__main__":
main()

5 changes: 5 additions & 0 deletions space_robots/prompt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
I need rclpy code to run a differential rover robot.
Publish /cmd_vel every 0.1 seconds.
Please only write Python code in your replies.
Reply by. import rclpy Please start with
QoS is not set
6 changes: 4 additions & 2 deletions space_robots/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
# docker
# an X server

IMG_NAME=openrobotics/space_robots_demo
#IMG_NAME=openrobotics/space_robots_demo
IMG_NAME=osrf/space_robots_demo

# Replace `/` with `_` to comply with docker container naming
# And append `_runtime`
CONTAINER_NAME="$(tr '/' '_' <<< "$IMG_NAME")"
CONTAINER_NAME="my_test_1"
#"$(tr '/' '_' <<< "$IMG_NAME")"

# Start the container
docker run --rm -it --name $CONTAINER_NAME --network host \
Expand Down
45 changes: 45 additions & 0 deletions space_robots/sample_code_by_gpt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#This code is generated by inputting "Rover goes forward 10m/s during 20 seconds"
#after 'python3 generate_src.py'

import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from time import sleep

class RoverController(Node):

def __init__(self):
super().__init__('rover_controller')
self.publisher_ = self.create_publisher(Twist, '/cmd_vel', 10)
self.timer = self.create_timer(0.1, self.publish_cmd_vel)
self.start_time = self.get_clock().now()

def publish_cmd_vel(self):
current_time = self.get_clock().now()
elapsed_time = (current_time - self.start_time).nanoseconds / 1e9

if elapsed_time > 20:
self.timer.cancel() # Stop publishing after 20 seconds
self.get_logger().info('Stopped sending velocity commands.')
return

cmd_vel = Twist()
cmd_vel.linear.x = 10.0 # Forward speed in m/s
cmd_vel.angular.z = 0.0 # No rotation

self.publisher_.publish(cmd_vel)
self.get_logger().info('Publishing: Linear X: %f, Angular Z: %f' %
(cmd_vel.linear.x, cmd_vel.angular.z))


def main(args=None):
rclpy.init(args=args)
rover_controller = RoverController()
rclpy.spin(rover_controller)

rover_controller.destroy_node()
rclpy.shutdown()


if __name__ == '__main__':
main()
37 changes: 37 additions & 0 deletions space_robots/sample_code_turn_left_by_gpt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
import time

class RoverController(Node):
def __init__(self):
super().__init__('rover_controller')
self.publisher_ = self.create_publisher(Twist, 'cmd_vel', 10)

def publish_cmd_vel(self):
twist = Twist()
# Set linear velocity to move forward
twist.linear.x = 5.0
# Set angular velocity for turning left
twist.angular.z = 1.0

# Publish the velocity command for 10 seconds
end_time = time.time() + 10
while time.time() < end_time:
self.publisher_.publish(twist)
time.sleep(0.1)

def main(args=None):
rclpy.init(args=args)
rover_controller = RoverController()

try:
rover_controller.publish_cmd_vel()
finally:
# Destroy the node explicitly
rover_controller.destroy_node()
rclpy.shutdown()

if __name__ == '__main__':
main()

Loading