diff --git a/moveit2/Dockerfile b/moveit2/Dockerfile index 11ff916..a320ef9 100644 --- a/moveit2/Dockerfile +++ b/moveit2/Dockerfile @@ -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 @@ -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 @@ -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 diff --git a/moveit2/build.sh b/moveit2/build.sh index 04cc00d..69aeec0 100755 --- a/moveit2/build.sh +++ b/moveit2/build.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash -ORG=openrobotics +#ORG=openrobotics +ORG=moveit IMAGE=moveit2 TAG=latest diff --git a/moveit2/run.sh b/moveit2/run.sh index 9381852..34c3374 100755 --- a/moveit2/run.sh +++ b/moveit2/run.sh @@ -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` diff --git a/space_robots/Dockerfile b/space_robots/Dockerfile index 561802c..f6cd24c 100644 --- a/space_robots/Dockerfile +++ b/space_robots/Dockerfile @@ -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 @@ -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 @@ -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"] diff --git a/space_robots/README.md b/space_robots/README.md index c9bd284..958c0de 100644 --- a/space_robots/README.md +++ b/space_robots/README.md @@ -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 diff --git a/space_robots/build.sh b/space_robots/build.sh index 94770d8..b99e782 100755 --- a/space_robots/build.sh +++ b/space_robots/build.sh @@ -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="" diff --git a/space_robots/config.json b/space_robots/config.json new file mode 100644 index 0000000..370d9dc --- /dev/null +++ b/space_robots/config.json @@ -0,0 +1,5 @@ +{ + "openai_api_key": "SK-xxxxx", + "openai_model": "gpt-4o-2024-08-06" +} + diff --git a/space_robots/config_dummy.json b/space_robots/config_dummy.json new file mode 100644 index 0000000..3743ed8 --- /dev/null +++ b/space_robots/config_dummy.json @@ -0,0 +1,5 @@ +{ + "openai_api_key": "sk-XXXXX", + "openai_model": "gpt-4o-2024-08-06" +} + diff --git a/space_robots/generate_src.py b/space_robots/generate_src.py new file mode 100644 index 0000000..74cb70c --- /dev/null +++ b/space_robots/generate_src.py @@ -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() + diff --git a/space_robots/prompt.txt b/space_robots/prompt.txt new file mode 100644 index 0000000..8c13be4 --- /dev/null +++ b/space_robots/prompt.txt @@ -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 diff --git a/space_robots/run.sh b/space_robots/run.sh index 39c9993..f9b318d 100755 --- a/space_robots/run.sh +++ b/space_robots/run.sh @@ -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 \ diff --git a/space_robots/sample_code_by_gpt.py b/space_robots/sample_code_by_gpt.py new file mode 100644 index 0000000..58a32fb --- /dev/null +++ b/space_robots/sample_code_by_gpt.py @@ -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() diff --git a/space_robots/sample_code_turn_left_by_gpt.py b/space_robots/sample_code_turn_left_by_gpt.py new file mode 100644 index 0000000..d549e26 --- /dev/null +++ b/space_robots/sample_code_turn_left_by_gpt.py @@ -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() +