diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..da4f67c --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,25 @@ +name: build checks + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + name: build + runs-on: ubuntu-latest + container: + image: ros:noetic + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Install dependencies + run: | + sudo apt-get update + rosdep update + DEBIAN_FRONTEND=noninteractive rosdep install --from-paths src -qr --ignore-src --default-yes + - name: Build packages + run: /opt/ros/noetic/env.sh catkin_make diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 77631aa..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: AMP_ASSv2 CI - -on: - workflow_dispatch: - pull_request: - push: - branches: - - master - -jobs: - build: - strategy: - fail-fast: false - name: build - runs-on: ubuntu-latest - env: - DESKTOP_DOCKER: ./docker/desktop.Dockerfile - DESKTOP_TAG: amp-devel:noetic-desktop - FRAME_DOCKER: ./docker/frame.Dockerfile - FRAME_TAG: amp-devel:frame-desktop - MESA_DOCKER: ./docker/mesa.Dockerfile - MESA_TAG: amp-devel:mesa-desktop - steps: - - name: Check Out Repo - uses: actions/checkout@v3 - - name: Disable zed - run: ./toggle_zed.sh - - name: Build noetic-desktop - run: docker build --file $DESKTOP_DOCKER --tag $DESKTOP_TAG . - - name: Build frame-desktop - run: docker build --file $FRAME_DOCKER --tag $FRAME_TAG . - - name: Build mesa-build - run: docker build --file $MESA_DOCKER --tag $MESA_TAG . diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml deleted file mode 100644 index 5b12f3e..0000000 --- a/.github/workflows/cli.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: AMP-CLI CI - -on: - workflow_dispatch: - pull_request: - push: - branches: - - master - -jobs: - build: - strategy: - fail-fast: false - name: build - runs-on: ubuntu-latest - steps: - - name: Check Out Repo - uses: actions/checkout@v3 - - name: Build amp-cli - run: pip install . diff --git a/.github/workflows/format.yaml b/.github/workflows/format.yaml deleted file mode 100644 index 1b1b780..0000000 --- a/.github/workflows/format.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Again, sourced from: -# https://github.com/ros-planning/moveit2/blob/main/.github/workflows/format.yaml -# Thank you to moveit for the source code - -name: Formatting (pre-commit) - -on: - workflow_dispatch: - pull_request: - push: - branches: - - master - -jobs: - pre-commit: - name: Format - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - - name: Install clang-format-12 - run: "sudo apt-get install clang-format-12" - - uses: pre-commit/action@v3.0.0 - id: precommit diff --git a/.github/workflows/rosserial.yaml b/.github/workflows/rosserial.yaml new file mode 100644 index 0000000..241f54b --- /dev/null +++ b/.github/workflows/rosserial.yaml @@ -0,0 +1,46 @@ +name: rosserial CI + +on: + workflow_dispatch: + push: + branches: + - master + +jobs: + build-and-upload: + name: build-and-upload-ros-lib + runs-on: ubuntu-latest + container: + image: ros:noetic + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Install dependencies + run: | + sudo apt-get update + rosdep update + DEBIAN_FRONTEND=noninteractive rosdep install --from-paths src -qr --ignore-src --default-yes + - name: Build packages + run: /opt/ros/noetic/env.sh catkin_make + - name: Build rosserial_arduino library + run: | + DEBIAN_FRONTEND=noninteractive sudo apt-get install --no-install-recommends --quiet --yes ros-noetic-rosserial-arduino git + devel/env.sh rosrun rosserial_arduino make_libraries.py dest + - name: Checkout ros_lib + uses: actions/checkout@v3 + with: + token: ${{ secrets.GH_TOKEN }} + repository: Autonomous-Motorsports-Purdue/ros_lib + path: ros_lib + - name: Move changes + run: | + rm -rf ros_lib/* + mv dest/ros_lib/* ros_lib/ + - name: Commit changes to repo + run: | + cd ros_lib + git config --global user.name alanssitis + git config --global user.email AMP-Purdue@users.noreply.github.com + git add -A + git commit -m "Automated update (${{ github.sha }})" + git push diff --git a/.gitignore b/.gitignore index 5f210b4..2e0228d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,12 @@ +# Editor stuff +.ccls-cache/ + # ROS build directories build/ devel/ - -# Devel directory -amp-devel/ - -# AMP-CLI files -*.egg-info -__pycache__ -logs/ +install/ +log/ +__pycache__/ # Catkin ignore files CATKIN_IGNORE diff --git a/README.md b/README.md index 4631c9e..bdbb1d0 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,35 @@ # AMP Autonomous Software Stack v2 -[![AMP_ASSv2 CI](https://github.com/Autonomous-Motorsports-Purdue/AMP_ASSv2/actions/workflows/ci.yml/badge.svg)](https://github.com/Autonomous-Motorsports-Purdue/AMP_ASSv2/actions/workflows/ci.yml) -[![AMP-CLI CI](https://github.com/Autonomous-Motorsports-Purdue/AMP_ASSv2/actions/workflows/cli.yml/badge.svg)](https://github.com/Autonomous-Motorsports-Purdue/AMP_ASSv2/actions/workflows/cli.yml) +[![build checks](https://github.com/Autonomous-Motorsports-Purdue/AMP_ASSv2/actions/workflows/ci.yaml/badge.svg)](https://github.com/Autonomous-Motorsports-Purdue/AMP_ASSv2/actions/workflows/ci.yaml) +[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/Autonomous-Motorsports-Purdue/AMP_ASSv2/master.svg)](https://results.pre-commit.ci/latest/github/Autonomous-Motorsports-Purdue/AMP_ASSv2/master) Second iteration of the Autonomous Software Stack (ASS) for the AMP go-kart. Go to the [wiki](https://github.com/Autonomous-Motorsports-Purdue/AMP_ASSv2/wiki) to learn more about this repo and code standards. +It is dependent on [ROS Noetic](http://wiki.ros.org/noetic/Installation/Ubuntu). + ## Developing -The best way to work with the codebase is within a Ubuntu 20.04 VM. To do so, -clone this repo, install all the dependencies and build the project. +The best way to work with the codebase is within a Ubuntu 20.04 environment, be +it on baremetal or on a VM. To do so, clone this repo and install all the +dependencies and build the project. + +An alternate build system, +`[colcon](https://colcon.readthedocs.io/en/released/user/installation.html)` +can also be used. ```bash +# Install dependencies rosdep update rosdep install --from-paths src -iry -catkin_make -``` -For people unable to work in a Ubuntu 20.04 VM, it is recommended to work on -the code base within a virtual ROS environment in a docker container. To do so, -the `amp-cli` will help you set up all you'll need. - -- To build the amp-cli tool, run: +# Build the packages +catkin_make +# If using colcon, use the line below +# colcon build ``` -sudo pip install . -``` - -- Run `amp-cli` to view the available options. - Run the `devel` option in order to have a good consistent environment. ## Formatting diff --git a/amp_cli.py b/amp_cli.py deleted file mode 100644 index 9981b21..0000000 --- a/amp_cli.py +++ /dev/null @@ -1,290 +0,0 @@ -import docker -import os -import subprocess - -import click - - -def write_log_to_file(file_name, log_generator): - with open(file_name, "w") as f: - for log in log_generator: - try: - f.write(log["stream"]) - except: - pass - - -@click.group() -def cli(): - """This is the official AMP Software Sub-Team CLI Tool that helps you - develop on AMP_ASSv2 using docker containers in your current environment. - - In order to run some of the functions, you must be in the root directory - of the AMP_ASSv2 repo. If there are any features you would like to see, - or bugs that need to be fixed, feel free to open an issue or PR! - """ - pass - - -@cli.command() -@click.option("-b", - "--build", - is_flag=True, - help="Build the frame container, if not up-to-date.") -@click.option( - "--display", - default="mesa", - type=click.Choice(["mesa", "nvidia"], case_sensitive=False), - help="Choose display driver option.", -) -def devel(build: bool, display: str): - """Develop with current directory mounted on the container.""" - # Initialize docker client environment - try: - client = docker.from_env() - except Exception as exception: - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu.") - cwd = os.getcwd() - tag = "amp-devel:frame-desktop" - - # Make sure current directory is AMP_ASSv2 - if cwd.split("/")[-1] != "AMP_ASSv2": - raise click.ClickException( - click.style( - "Devel only works when executed from the root directory of the AMP_ASSv2 local repo.", - fg="red", - )) - - if build: - subprocess.run(["bash", "-c", "mkdir -p logs"]) - click.echo("Building containers...") - - click.echo("Step 1/2: Building amp-devel:noetic-desktop.") - try: - _, logs = client.images.build( - path=cwd, - tag="amp-devel:noetic-desktop", - dockerfile=(cwd + "/docker/desktop.Dockerfile"), - ) - click.secho(" ---> Finished building amp-devel:noetic-desktop.", - fg="yellow") - except Exception as exception: - write_log_to_file("logs/devel-build-desktop.log", logs) - click.secho(" ---> Finished saving logs.", fg="red") - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu." - ) - write_log_to_file("logs/devel-build-desktop.log", logs) - click.secho(" ---> Finished saving logs.", fg="yellow") - - click.echo(f"Step 2/2: Building {tag}.") - try: - _, logs = client.images.build( - path=cwd, - tag=tag, - dockerfile=(cwd + "/docker/frame.Dockerfile")) - click.secho(f" ---> Finished building {tag}.", fg="yellow") - except Exception as exception: - write_log_to_file("logs/devel-build-frame.log", logs) - click.secho(" ---> Finished saving logs.", fg="red") - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu." - ) - write_log_to_file("logs/devel-build-frame.log", logs) - click.secho(" ---> Finished saving logs.", fg="yellow") - - try: - subprocess.run(["bash", "-c", "mkdir -p amp-devel/build"]) - subprocess.run(["bash", "-c", "mkdir -p amp-devel/devel"]) - # Run the container - click.echo(f"Running {tag}...") - if display == "mesa": - container = client.containers.run( - tag, - stdin_open=True, - tty=True, - auto_remove=True, - name="amp-assv2-scratch", - environment={ - "DISPLAY": os.getenv("DISPLAY"), - "QT_X11_NO_MITSHM": 1, - }, - devices=["/dev/dri:/dev/dri"], - volumes={ - "/tmp/.X11-unix": { - "bind": "/tmp/.X11-unix", - "mode": "rw", - }, - cwd + "/src": { - "bind": "/amp_ws/src", - "mode": "rw", - }, - cwd + "/amp-devel/build": { - "bind": "/amp_ws/build", - "mode": "rw", - }, - cwd + "/amp-devel/devel": { - "bind": "/amp_ws/devel", - "mode": "rw", - }, - }, - privileged=True, - detach=True, - ) - # TODO: NVidia settings - else: - raise click.ClickException("NVidia config WIP") - # Attach to the container - click.echo("Use [ + D] to stop and exit the container.") - click.secho("Note: Rosdep packages are not installed in devel", - fg="yellow") - click.secho('Run "apt update && rosdep install --from-paths src -iry"', - fg="yellow") - click.secho( - f"Entering container {container.name}:{container.short_id}.", - fg="blue") - subprocess.run(["bash", "-c", "xhost +"]) - subprocess.run(["bash", "-c", f"docker attach {container.id}"]) - subprocess.run(["bash", "-c", "xhost -"]) - click.secho("Successfully exited and stopped container.", fg="green") - except docker.errors.ImageNotFound: - raise click.ClickException( - f'Unable to find {tag}, maybe try running with "--build" flag?') - except Exception as exception: - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu.") - - -@cli.command() -@click.option("-b", - "--build", - is_flag=True, - help="Build the corresponding containers.") -@click.option( - "--display", - default="mesa", - show_default=True, - type=click.Choice(["mesa", "nvidia"], case_sensitive=False), - help="Choose display driver option.", -) -def scratch(build: bool, display: str): - """Develop on a fully isolated container.""" - # Initialize docker client environment - try: - client = docker.from_env() - except Exception as exception: - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu.") - cwd = os.getcwd() - - tag = f"amp-devel:{display}-build" - dockerfile = cwd + f"/docker/{display}.Dockerfile" - - # Build container - if build: - # Make sure current directory is AMP_ASSv2 - if cwd.split("/")[-1] != "AMP_ASSv2": - raise click.ClickException( - click.style( - "Build only works inside root directory of the AMP_ASSv2 local repository.", - fg="red", - )) - - subprocess.run(["bash", "-c", "mkdir -p logs"]) - click.echo("Building containers...") - - click.echo("Step 1/3: Building amp-devel:noetic-desktop.") - try: - _, logs = client.images.build( - path=cwd, - tag="amp-devel:noetic-desktop", - dockerfile=(cwd + "/docker/desktop.Dockerfile"), - ) - click.secho(" ---> Finished building amp-devel:noetic-desktop.", - fg="yellow") - except Exception as exception: - write_log_to_file("logs/scratch-build-desktop.log", logs) - click.secho(" ---> Finished saving logs.", fg="red") - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu." - ) - write_log_to_file("logs/scratch-build-desktop.log", logs) - click.secho(" ---> Finished saving logs.", fg="yellow") - - click.echo("Step 2/3: Building amp-devel:frame-desktop.") - try: - _, logs = client.images.build( - path=cwd, - tag="amp-devel:frame-desktop", - dockerfile=(cwd + "/docker/frame.Dockerfile"), - ) - click.secho(" ---> Finished building amp-devel:frame-desktop.", - fg="yellow") - except Exception as exception: - write_log_to_file("logs/scratch-build-frame.log", logs) - click.secho(" ---> Finished saving logs.", fg="red") - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu." - ) - write_log_to_file("logs/scratch-build-frame.log", logs) - click.secho(" ---> Finished saving logs.", fg="yellow") - - click.echo(f"Step 3/3: Building {tag}.") - try: - _, logs = client.images.build(path=cwd, - tag=tag, - dockerfile=dockerfile) - click.secho(f" ---> Finished building {tag}.", fg="yellow") - except Exception as exception: - write_log_to_file(f"logs/scratch-build-{display}.log", logs) - click.secho(" ---> Finished saving logs.", fg="red") - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu." - ) - write_log_to_file(f"logs/scratch-build-{display}.log", logs) - click.secho(" ---> Finished saving logs.", fg="yellow") - - try: - # Run the container - click.echo(f"Running {tag}...") - if display == "mesa": - container = client.containers.run( - tag, - stdin_open=True, - tty=True, - auto_remove=True, - name="amp-assv2-scratch", - environment={ - "DISPLAY": os.getenv("DISPLAY"), - "QT_X11_NO_MITSHM": 1, - }, - devices=["/dev/dri:/dev/dri"], - volumes={ - "/tmp/.X11-unix": { - "bind": "/tmp/.X11-unix", - "mode": "rw", - }, - }, - privileged=True, - detach=True, - ) - # TODO: NVidia settings - else: - raise click.ClickException("NVidia config WIP") - # Attach to the container - click.echo("Use [ + D] to stop and exit the container.") - click.secho( - f"Entering container {container.name}:{container.short_id}.", - fg="blue") - subprocess.run(["bash", "-c", "xhost +"]) - subprocess.run(["bash", "-c", f"docker attach {container.id}"]) - subprocess.run(["bash", "-c", "xhost -"]) - click.secho("Successfully exited and stopped container.", fg="green") - - except docker.errors.ImageNotFound: - raise click.ClickException( - f'Unable to find {tag}, maybe try running with "--build" flag?') - except Exception as exception: - raise click.ClickException( - f"Error: {exception}\nRan into an error, look at the help menu.") diff --git a/docker/desktop.Dockerfile b/docker/desktop.Dockerfile deleted file mode 100644 index 312f2b6..0000000 --- a/docker/desktop.Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ros:noetic-ros-base - -RUN apt-get update && apt-get install -y --no-install-recommends \ - ros-noetic-desktop \ - && rm -rf /var/lib/apt/lists/* diff --git a/docker/frame.Dockerfile b/docker/frame.Dockerfile deleted file mode 100644 index 9df3ed0..0000000 --- a/docker/frame.Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM amp-devel:noetic-desktop -SHELL ["/bin/bash", "-c"] -WORKDIR /amp_ws - -COPY .catkin_workspace . - -RUN apt-get update && apt-get install -q -y --no-install-recommends \ - tmux \ - curl \ - wget \ - vim \ - libgl1-mesa-glx \ - libgl1-mesa-dri \ - mesa-utils \ - unzip \ - && rm -rf /var/lib/apt/list/* \ - -ENTRYPOINT ["/ros_entrypoint.sh"] -CMD ["bash"] diff --git a/docker/mesa.Dockerfile b/docker/mesa.Dockerfile deleted file mode 100644 index 9fccdcc..0000000 --- a/docker/mesa.Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM amp-devel:frame-desktop -SHELL ["/bin/bash", "-c"] -WORKDIR /amp_ws - -COPY src ./src - -RUN apt-get update && \ - rosdep update && \ - . /opt/ros/noetic/setup.bash && \ - rosdep install --from-paths src -iry && \ - rm -rf /var/lib/apt/list/* && \ - catkin_make -RUN echo "source /amp_ws/devel/setup.bash" >> ~/.bashrc - -ENTRYPOINT ["/ros_entrypoint.sh"] -CMD ["bash"] diff --git a/setup.py b/setup.py deleted file mode 100644 index 794718b..0000000 --- a/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -from setuptools import setup - -setup( - name="AMP-CLI", - version="0.2", - py_modules=["amp_cli"], - install_requires=[ - "click", - "docker", - "wheel", - ], - entry_points={ - "console_scripts": [ - "amp-cli = amp_cli:cli", - ], - }, -) diff --git a/src/amp_msgs/CMakeLists.txt b/src/amp_msgs/CMakeLists.txt index a820565..9946932 100644 --- a/src/amp_msgs/CMakeLists.txt +++ b/src/amp_msgs/CMakeLists.txt @@ -47,6 +47,7 @@ add_message_files( DIRECTORY msg FILES ConeList.msg + SerialPacket.msg ) ## Generate services in the 'srv' folder diff --git a/src/amp_msgs/msg/SerialPacket.msg b/src/amp_msgs/msg/SerialPacket.msg new file mode 100644 index 0000000..91bb637 --- /dev/null +++ b/src/amp_msgs/msg/SerialPacket.msg @@ -0,0 +1,3 @@ +int32 throttle +int32 steering +int32 direction diff --git a/src/serial_packet/CMakeLists.txt b/src/serial_packet/CMakeLists.txt new file mode 100644 index 0000000..86800e0 --- /dev/null +++ b/src/serial_packet/CMakeLists.txt @@ -0,0 +1,206 @@ +cmake_minimum_required(VERSION 3.0.2) +project(serial_packet) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + amp_msgs + geometry_msgs + rospy +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# amp_msgs# geometry_msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES serial_packet +# CATKIN_DEPENDS amp_msgs geometry_msgs rospy +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/serial_packet.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/serial_packet_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +catkin_install_python(PROGRAMS + nodes/packet_node.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +install(FILES + launch/keyboard_control.launch + launch/rqt_control.launch + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_serial_packet.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/src/serial_packet/README.md b/src/serial_packet/README.md new file mode 100644 index 0000000..f3f0fab --- /dev/null +++ b/src/serial_packet/README.md @@ -0,0 +1,24 @@ +# serial_packet + +This package contains the node in charge of translating a +`[Twist](http://docs.ros.org/en/noetic/api/geometry_msgs/html/msg/Twist.html)` +topic to a custom message `SerialPacket` under `amp_msgs`. + +## Nodes + +#### packet_node.py + +Translates a `Twist` topic denoted as `twist_topic` to a `SerialPacket` denoted +as `packet_topic`. + +In its current state, the node is just scaling the linear velocity by 100 and +scaling the angular steering by 1000 and offsetting it by 3000. + +**TODO**: Adequate scaling from `Twist` to `SerialPacket` will need to be tuned +and there may be a need to implement a feedback control mechanism to have the +kart correct to the values in `/cmd_vel`. + +Params: + +- `twist_topic` (string): Subscribed `Twist` topic. +- `packet_topic` (string): Subscribed `SerialPacket` topic. diff --git a/src/serial_packet/launch/keyboard_control.launch b/src/serial_packet/launch/keyboard_control.launch new file mode 100644 index 0000000..b466926 --- /dev/null +++ b/src/serial_packet/launch/keyboard_control.launch @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + diff --git a/src/serial_packet/launch/rqt_control.launch b/src/serial_packet/launch/rqt_control.launch new file mode 100644 index 0000000..d251991 --- /dev/null +++ b/src/serial_packet/launch/rqt_control.launch @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + diff --git a/src/serial_packet/nodes/packet_node.py b/src/serial_packet/nodes/packet_node.py new file mode 100644 index 0000000..94b2cc3 --- /dev/null +++ b/src/serial_packet/nodes/packet_node.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import rospy +from serial_packet import PacketClient + +import sys +from time import sleep + +if __name__ == "__main__": + rospy.init_node("serial_node") + rospy.loginfo("Autonomous Motorsports Purdue ROS Serial Node") + + twist_topic = rospy.get_param("~twist_topic", "/cmd_vel") + packet_topic = rospy.get_param("~packet_topic", "/serial_packet") + + while not rospy.is_shutdown(): + rospy.loginfo("Running AMP ROS Serial Node") + try: + client = PacketClient(twist_topic=twist_topic, + packet_topic=packet_topic) + client.run() + except KeyboardInterrupt: + break + except OSError: + sleep(1.0) + continue + except: + rospy.logwarn("Unexpected Error: %s", sys.exc_info()[0]) + sleep(1.0) + continue diff --git a/src/serial_packet/package.xml b/src/serial_packet/package.xml new file mode 100644 index 0000000..a193e82 --- /dev/null +++ b/src/serial_packet/package.xml @@ -0,0 +1,65 @@ + + + serial_packet + 0.0.0 + The serial_packet package + + + + + achungma + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + amp_msgs + geometry_msgs + rospy + rosserial + rqt_robot_steering + teleop_twist_keyboard + + + + + + + + diff --git a/src/serial_packet/setup.py b/src/serial_packet/setup.py new file mode 100644 index 0000000..15249ba --- /dev/null +++ b/src/serial_packet/setup.py @@ -0,0 +1,9 @@ +from distutils.core import setup +from catkin_pkg.python_setup import generate_distutils_setup + +d = generate_distutils_setup( + packages=['serial_packet'], + package_dir={'': 'src'}, +) + +setup(**d) diff --git a/src/serial_packet/src/serial_packet/PacketClient.py b/src/serial_packet/src/serial_packet/PacketClient.py new file mode 100644 index 0000000..01d7e8f --- /dev/null +++ b/src/serial_packet/src/serial_packet/PacketClient.py @@ -0,0 +1,36 @@ +import rospy +from geometry_msgs.msg import Twist +from amp_msgs.msg import SerialPacket + +max_speed = 10 + + +def get_throttle_params(linear): + if linear >= 0: + return int(linear * 100), 1 + else: + return int(-linear * 100), -1 + + +def get_steering_params(angular): + return int(angular * 1000 + 3000) + + +class PacketClient(object): + + def __init__(self, twist_topic="/cmd_vel", packet_topic="/serial_packet"): + self.twist_sub = rospy.Subscriber(twist_topic, Twist, + self.update_packet) + self.packet_pub = rospy.Publisher(packet_topic, + SerialPacket, + queue_size=1000) + + def update_packet(self, msg): + packet = SerialPacket() + packet.throttle, packet.direction = get_throttle_params(msg.linear.x) + packet.steering = get_steering_params(msg.angular.z) + + self.packet_pub.publish(packet) + + def run(self): + rospy.spin() diff --git a/src/serial_packet/src/serial_packet/__init__.py b/src/serial_packet/src/serial_packet/__init__.py new file mode 100644 index 0000000..924cee6 --- /dev/null +++ b/src/serial_packet/src/serial_packet/__init__.py @@ -0,0 +1 @@ +from .PacketClient import *