diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..da10e9b --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,39 @@ +// See https://aka.ms/vscode-remote/devcontainer.json for format details. +{ + "image": "georgno/fhtw-ros:iron-desktop-ros_terminal-standard", + "remoteUser": "fhtw_user", + "initializeCommand": "xhost +", + "onCreateCommand": "sudo bash /entrypoint.sh &", + "workspaceMount": "source=${localWorkspaceFolder},target=/home/fhtw_user/sim_ws/src/sjtu_drone,type=bind,consistency=cached", + "workspaceFolder": "/home/fhtw_user/sim_ws", + // mount Jupyter/src/ros2 to ~/ros2_ws/src + "runArgs": [ + "--shm-size=512m", + "--privileged", + "--gpus=all", + "--volume=/tmp/.X11-unix:/tmp/.X11-unix" + ], + "containerEnv": { + "DISPLAY": "${localEnv:DISPLAY}", + // "LIBGL_ALWAYS_SOFTWARE": "1" // Needed for software rendering of opengl + }, + // Set *default* container specific settings.json values on container create. + "customizations": { + "vscode": { + "extensions": [ + "althack.ament-task-provider", + "DotJoshJohnson.xml", + "ms-azuretools.vscode-docker", + "ms-python.python", + "ms-vscode.cpptools", + "redhat.vscode-yaml", + "smilerobotics.urdf", + "twxs.cmake", + "yzhang.markdown-all-in-one", + "zachflower.uncrustify", + "ms-iot.vscode-ros", + "ms-vscode.cpptools-extension-pack" + ] + } + } +} \ No newline at end of file diff --git a/.github/workflows/CI_CD.yml b/.github/workflows/CI_CD.yml index d8423ff..f3b7c18 100644 --- a/.github/workflows/CI_CD.yml +++ b/.github/workflows/CI_CD.yml @@ -11,10 +11,10 @@ jobs: strategy: matrix: include: - # - os: ubuntu-20.04 - # ros_distribution: "galactic" - os: ubuntu-22.04 ros_distribution: "humble" + - os: ubuntu-22.04 + ros_distribution: "iron" - os: ubuntu-22.04 ros_distribution: "rolling" fail-fast: false @@ -67,7 +67,17 @@ jobs: if: always() deploy: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-22.04 + ros_distribution: "humble" + - os: ubuntu-22.04 + ros_distribution: "iron" + - os: ubuntu-22.04 + ros_distribution: "rolling" + fail-fast: false needs: build if: needs.build.outputs.build_step_outcome == 'success' steps: @@ -90,4 +100,5 @@ jobs: uses: docker/build-push-action@v5 with: push: true - tags: ${{ secrets.DOCKERHUB_USERNAME }}/sjtu_drone:ros2 + tags: ${{ secrets.DOCKERHUB_USERNAME }}/sjtu_drone:ros2-${{ matrix.ros_distribution }} + args: --build-arg ROS_DISTRO=${{ matrix.ros_distribution}} diff --git a/.gitignore b/.gitignore index 002a15d..472c197 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ plugins/ bin/ - +__pycache__/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index de864d4..9465ece 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM ros:humble-ros-core-jammy +ARG ROS_DISTRO +FROM ros:${ROS_DISTRO}-ros-core-jammy RUN apt-get update \ && apt-get install -y \ @@ -14,7 +15,7 @@ RUN echo "deb http://packages.osrfoundation.org/gazebo/ubuntu `lsb_release -cs` && apt-get update \ && apt-get install -y \ gazebo \ - ros-humble-gazebo-ros-pkgs \ + ros-${ROS_DISTRO}-gazebo-ros-pkgs \ python3-colcon-common-extensions python3-rosdep --no-install-recommends \ && apt-get clean RUN rosdep init && rosdep update @@ -22,6 +23,7 @@ RUN rosdep init && rosdep update RUN mkdir -p /ros2_ws/src COPY ./sjtu_drone_description /ros2_ws/src/sjtu_drone_description COPY ./sjtu_drone_bringup /ros2_ws/src/sjtu_drone_bringup +COPY ./sjtu_drone_control /ros2_ws/src/sjtu_drone_control RUN curl -L https://github.com/osrf/gazebo_models/archive/refs/heads/master.zip -o /tmp/gazebo_models.zip \ && unzip /tmp/gazebo_models.zip -d /tmp && mkdir -p ~/.gazebo/models/ && mv /tmp/gazebo_models-master/* ~/.gazebo/models/ \ @@ -29,8 +31,8 @@ RUN curl -L https://github.com/osrf/gazebo_models/archive/refs/heads/master.zip WORKDIR /ros2_ws RUN /bin/bash -c 'cd /ros2_ws/ \ - && source /opt/ros/humble/setup.bash \ + && source /opt/ros/${ROS_DISTRO}/setup.bash \ && rosdep install --from-paths src --ignore-src -r -y \ && colcon build' -CMD ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash && source /ros2_ws/install/setup.bash && ros2 launch sjtu_drone_bringup sjtu_drone_bringup.launch.py"] +CMD ["/bin/bash", "-c", "source /opt/ros/${ROS_DISTRO}/setup.bash && source /ros2_ws/install/setup.bash && ros2 launch sjtu_drone_bringup sjtu_drone_bringup.launch.py"] diff --git a/README.md b/README.md index 2c9f715..aae1287 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # sjtu_drone -[![Humble](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/NovoG93/589e4b4dc8d92861e4b92defff6d56c0/raw/_humble_build.json)](https://github.com/NovoG93/sjtu_drone/actions/workflows/build.yml) [![Rolling](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/NovoG93/589e4b4dc8d92861e4b92defff6d56c0/raw/_rolling_build.json)](https://github.com/NovoG93/sjtu_drone/actions/workflows/build.yml) +[![Iron](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/NovoG93/589e4b4dc8d92861e4b92defff6d56c0/raw/_iron_build.json)](https://github.com/NovoG93/sjtu_drone/actions/workflows/build.yml) [![Humble](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/NovoG93/589e4b4dc8d92861e4b92defff6d56c0/raw/_humble_build.json)](https://github.com/NovoG93/sjtu_drone/actions/workflows/build.yml) [![Rolling](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/NovoG93/589e4b4dc8d92861e4b92defff6d56c0/raw/_rolling_build.json)](https://github.com/NovoG93/sjtu_drone/actions/workflows/build.yml) sjtu_drone is a quadrotor simulation program forked from [tum_simulator](http://wiki.ros.org/tum_simulator), developed using ROS + Gazebo. @@ -8,7 +8,7 @@ The acronym 'sjtu' stands for Shanghai Jiao Tong University. This package has be # Requirements -This package is tested with ROS 2 Humble version (Ubuntu 22.04) and Gazebo 11. +This package is tested with ROS 2 (Ubuntu 22.04) and Gazebo 11. # Downloading and building diff --git a/run_docker.sh b/run_docker.sh index 46bc94f..7f6abcf 100644 --- a/run_docker.sh +++ b/run_docker.sh @@ -1,9 +1,32 @@ #!/bin/bash + +usage(){ + echo "Usage: $0 [-r ]" + exit 1 +} + +ROS_DISTRO=${ROS_DISTRO:-"iron"} # [humble, iron, rolling] +while getopts "r:" opt; do + case $opt in + r) + if [ $OPTARG != "humble" ] && [ $OPTARG != "iron" ] && [ $OPTARG != "rolling" ]; then + echo "Invalid ROS distro: $OPTARG" >&2 + usage + fi + ROS_DISTRO=$OPTARG + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + usage + ;; + esac +done + XSOCK=/tmp/.X11-unix XAUTH=$HOME/.Xauthority -# docker build -t georgno/sjtu_drone:$(git rev-parse --abbrev-ref HEAD) . -docker pull georgno/sjtu_drone:$(git rev-parse --abbrev-ref HEAD) +# docker build -t georgno/sjtu_drone:${ROS_DISTRO} . +docker pull georgno/sjtu_drone:${ROS_DISTRO} if [ $? -ne 0 ]; then exit 1 @@ -22,5 +45,5 @@ docker run \ --privileged \ --net=host \ --name="sjtu_drone" \ - georgno/sjtu_drone:$(git rev-parse --abbrev-ref HEAD) + georgno/sjtu_drone:${ROS_DISTRO} xhost -local:docker diff --git a/sjtu_drone_bringup/launch/sjtu_drone_bringup.launch.py b/sjtu_drone_bringup/launch/sjtu_drone_bringup.launch.py index f0f885d..50bb1b8 100755 --- a/sjtu_drone_bringup/launch/sjtu_drone_bringup.launch.py +++ b/sjtu_drone_bringup/launch/sjtu_drone_bringup.launch.py @@ -1,18 +1,29 @@ #!/usr/bin/env python3 +# Copyright 2023 Georg Novotny +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import IncludeLaunchDescription -from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from launch.launch_description_sources import PythonLaunchDescriptionSource def generate_launch_description(): - use_sim_time = LaunchConfiguration("use_sim_time", default="false") sjtu_drone_bringup_path = get_package_share_directory('sjtu_drone_bringup') rviz_path = os.path.join( @@ -37,8 +48,8 @@ def generate_launch_description(): ), Node( - package="teleop_twist_keyboard", - executable="teleop_twist_keyboard", + package="sjtu_drone_control", + executable="teleop", namespace="drone", output="screen", prefix="xterm -e" diff --git a/sjtu_drone_bringup/launch/sjtu_drone_gazebo.launch.py b/sjtu_drone_bringup/launch/sjtu_drone_gazebo.launch.py index d429aa9..3ec311c 100755 --- a/sjtu_drone_bringup/launch/sjtu_drone_gazebo.launch.py +++ b/sjtu_drone_bringup/launch/sjtu_drone_gazebo.launch.py @@ -1,19 +1,33 @@ #!/usr/bin/env python3 +# Copyright 2023 Georg Novotny +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription -from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription +from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, OpaqueFunction from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from launch.launch_description_sources import PythonLaunchDescriptionSource import xacro -def generate_launch_description(): - use_sim_time = LaunchConfiguration("use_sim_time", default="false") +def generate_launch_description(): + use_sim_time = LaunchConfiguration("use_sim_time", default="true") + use_gui = DeclareLaunchArgument("use_gui", default_value="true", choices=["true", "false"], description="Whether to execute gzclient") xacro_file_name = "sjtu_drone.urdf.xacro" pkg_gazebo_ros = get_package_share_directory('gazebo_ros') xacro_file = os.path.join( @@ -29,7 +43,18 @@ def generate_launch_description(): "worlds", "playground.world" ) + def launch_gzclient(context, *args, **kwargs): + if context.launch_configurations.get('use_gui') == 'true': + return [IncludeLaunchDescription( + PythonLaunchDescriptionSource( + os.path.join(pkg_gazebo_ros, 'launch', 'gzclient.launch.py') + ), + launch_arguments={'verbose': 'true'}.items() + )] + return [] + return LaunchDescription([ + use_gui, Node( package="robot_state_publisher", executable="robot_state_publisher", @@ -57,12 +82,7 @@ def generate_launch_description(): 'extra_gazebo_args': 'verbose'}.items() ), - IncludeLaunchDescription( - PythonLaunchDescriptionSource( - os.path.join(pkg_gazebo_ros, 'launch', 'gzclient.launch.py') - ), - launch_arguments={'verbose': "true"}.items() - ), + OpaqueFunction(function=launch_gzclient), Node( package="sjtu_drone_bringup", diff --git a/sjtu_drone_bringup/package.xml b/sjtu_drone_bringup/package.xml index ed5fb93..4b960c9 100644 --- a/sjtu_drone_bringup/package.xml +++ b/sjtu_drone_bringup/package.xml @@ -4,7 +4,7 @@ sjtu_drone_bringup 0.0.0 TODO: Package description - ubuntu + Georg Novotny TODO: License declaration rclpy diff --git a/sjtu_drone_bringup/sjtu_drone_bringup/spawn_drone.py b/sjtu_drone_bringup/sjtu_drone_bringup/spawn_drone.py index b4ae7fe..892de9d 100755 --- a/sjtu_drone_bringup/sjtu_drone_bringup/spawn_drone.py +++ b/sjtu_drone_bringup/sjtu_drone_bringup/spawn_drone.py @@ -1,6 +1,19 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 +# Copyright 2023 Georg Novotny +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # -*- coding: utf-8 -*- -import os import sys import rclpy from gazebo_msgs.srv import SpawnEntity diff --git a/sjtu_drone_control/package.xml b/sjtu_drone_control/package.xml new file mode 100644 index 0000000..ac4f913 --- /dev/null +++ b/sjtu_drone_control/package.xml @@ -0,0 +1,24 @@ + + + + sjtu_drone_control + 0.0.0 + TODO: Package description + Georg Novotny + TODO: License declaration + + sensor_msgs + geometry_msgs + rclpy + std_msgs + + ament_copyright + ament_flake8 + ament_pep257 ubuntu + + python3-pytest + + + ament_python + + diff --git a/sjtu_drone_control/resource/sjtu_drone_control b/sjtu_drone_control/resource/sjtu_drone_control new file mode 100644 index 0000000..e69de29 diff --git a/sjtu_drone_control/setup.cfg b/sjtu_drone_control/setup.cfg new file mode 100644 index 0000000..d4159c7 --- /dev/null +++ b/sjtu_drone_control/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/sjtu_drone_control +[install] +install_scripts=$base/lib/sjtu_drone_control diff --git a/sjtu_drone_control/setup.py b/sjtu_drone_control/setup.py new file mode 100644 index 0000000..33a5a3e --- /dev/null +++ b/sjtu_drone_control/setup.py @@ -0,0 +1,26 @@ +from setuptools import setup + +package_name = 'sjtu_drone_control' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='ubuntu', + maintainer_email='georg.novtony@aon.at', + description='TODO: Package description', + license='TODO: License declaration', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'teleop = sjtu_drone_control.teleop:main' + ], + }, +) diff --git a/sjtu_drone_control/sjtu_drone_control/__init__.py b/sjtu_drone_control/sjtu_drone_control/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sjtu_drone_control/sjtu_drone_control/teleop.py b/sjtu_drone_control/sjtu_drone_control/teleop.py new file mode 100644 index 0000000..9fa2be4 --- /dev/null +++ b/sjtu_drone_control/sjtu_drone_control/teleop.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +# Copyright 2023 Georg Novotny +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import rclpy +from rclpy.node import Node +from geometry_msgs.msg import Twist, Vector3 +from std_msgs.msg import Empty, Bool +import threading +import sys +import termios +import tty + +MSG=""" +Control Your Drone! +--------------------------- +Moving around: + w + a s d + x + +q/e : increase/decrease linear and angular velocity +A/D: rotate left/right +t/l: takeoff/land +--------------------------- +CTRL-C to quit +--------------------------- + +""" + +class TeleopNode(Node): + def __init__(self) -> None: + super().__init__('teleop_node') + + # Publishers + self.cmd_vel_publisher = self.create_publisher(Twist, 'cmd_vel', 10) + self.takeoff_publisher = self.create_publisher(Empty, 'takeoff', 10) + self.land_publisher = self.create_publisher(Empty, 'land', 10) + + # Velocity parameters + self.linear_velocity = 0.0 + self.angular_velocity = 0.0 + self.linear_increment = 0.05 + self.angular_increment = 0.05 + self.max_linear_velocity = 1.0 + self.max_angular_velocity = 1.0 + + # Start a separate thread to listen to keyboard inputs + self.input_thread = threading.Thread(target=self.read_keyboard_input) + self.input_thread.daemon = True + self.input_thread.start() + + def get_velocity_msg(self) -> str: + return "Linear Velocity: " + str(self.linear_velocity) + "\nAngular Velocity: " + str(self.angular_velocity) + "\n" + + def read_keyboard_input(self) -> None: + """ + Read keyboard inputs and publish corresponding commands + """ + while rclpy.ok(): + # Print the instructions + print(MSG+self.get_velocity_msg()) + # Implement a non-blocking keyboard read + key = self.get_key() + # Handle velocity changes + if key == 'q': + self.linear_velocity = min(self.linear_velocity + self.linear_increment, self.max_linear_velocity) + self.angular_velocity = min(self.angular_velocity + self.angular_increment, self.max_angular_velocity) + elif key == 'e': + self.linear_velocity = max(self.linear_velocity - self.linear_increment, -self.max_linear_velocity) + self.angular_velocity = max(self.angular_velocity - self.angular_increment, -self.max_angular_velocity) + elif key.lower() == 'w': + # Move forward + linear_vec = Vector3() + linear_vec.x = self.linear_velocity + self.publish_cmd_vel(linear_vec) + elif key.lower() == 's': + # Hover + self.publish_cmd_vel() + elif key.lower() == 'x': + # Move backward + linear_vec = Vector3() + linear_vec.x = -self.linear_velocity + self.publish_cmd_vel(linear_vec) + elif key == 'a': + # Move Left + linear_vec = Vector3() + linear_vec.y = self.linear_velocity + self.publish_cmd_vel(linear_vec) + elif key == 'd': + # Move right + linear_vec = Vector3() + linear_vec.y = -self.linear_velocity + self.publish_cmd_vel(linear_vec) + elif key == 'A': + # Move Left + angular_vec = Vector3() + angular_vec.z = self.angular_velocity + self.publish_cmd_vel(angular_vec=angular_vec) + elif key == 'D': + # Move right + angular_vec = Vector3() + angular_vec.z = -self.angular_velocity + self.publish_cmd_vel(angular_vec=angular_vec) + elif key.lower() == 'r': + # Rise + linear_vec = Vector3() + linear_vec.z = self.linear_velocity + self.publish_cmd_vel(linear_vec) + elif key.lower() == 'f': + # Fall + linear_vec = Vector3() + linear_vec.z = -self.angular_velocity + self.publish_cmd_vel(linear_vec) + # Handle other keys for different movements + elif key == 't': + # Takeoff + self.takeoff_publisher.publish(Empty()) + elif key == 'l': + # Land + self.publish_cmd_vel() + self.land_publisher.publish(Empty()) + + def get_key(self) -> str: + """ + Function to capture keyboard input + """ + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch + + def publish_cmd_vel(self, linear_vec: Vector3=Vector3(), angular_vec: Vector3=Vector3()) -> None: + """ + Publish a Twist message to cmd_vel topic + """ + twist = Twist(linear=linear_vec, angular=angular_vec) + self.cmd_vel_publisher.publish(twist) + +def main(args=None): + rclpy.init(args=args) + teleop_node = TeleopNode() + rclpy.spin(teleop_node) + teleop_node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/sjtu_drone_control/test/test_copyright.py b/sjtu_drone_control/test/test_copyright.py new file mode 100644 index 0000000..97a3919 --- /dev/null +++ b/sjtu_drone_control/test/test_copyright.py @@ -0,0 +1,25 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_copyright.main import main +import pytest + + +# Remove the `skip` decorator once the source file(s) have a copyright header +@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') +@pytest.mark.copyright +@pytest.mark.linter +def test_copyright(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found errors' diff --git a/sjtu_drone_control/test/test_flake8.py b/sjtu_drone_control/test/test_flake8.py new file mode 100644 index 0000000..27ee107 --- /dev/null +++ b/sjtu_drone_control/test/test_flake8.py @@ -0,0 +1,25 @@ +# Copyright 2017 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_flake8.main import main_with_errors +import pytest + + +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + rc, errors = main_with_errors(argv=[]) + assert rc == 0, \ + 'Found %d code style errors / warnings:\n' % len(errors) + \ + '\n'.join(errors) diff --git a/sjtu_drone_control/test/test_pep257.py b/sjtu_drone_control/test/test_pep257.py new file mode 100644 index 0000000..b234a38 --- /dev/null +++ b/sjtu_drone_control/test/test_pep257.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_pep257.main import main +import pytest + + +@pytest.mark.linter +@pytest.mark.pep257 +def test_pep257(): + rc = main(argv=['.', 'test']) + assert rc == 0, 'Found code style errors / warnings' diff --git a/sjtu_drone_description/include/pid_controller.h b/sjtu_drone_description/include/pid_controller.h index 696de1c..5d466dd 100644 --- a/sjtu_drone_description/include/pid_controller.h +++ b/sjtu_drone_description/include/pid_controller.h @@ -1,3 +1,17 @@ +// Copyright 2023 Georg Novotny +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef PIDCONTROLLER_H #define PIDCONTROLLER_H diff --git a/sjtu_drone_description/include/plugin_drone.h b/sjtu_drone_description/include/plugin_drone.h index 5283bb0..d8846cf 100644 --- a/sjtu_drone_description/include/plugin_drone.h +++ b/sjtu_drone_description/include/plugin_drone.h @@ -1,3 +1,17 @@ +// Copyright 2023 Georg Novotny +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef PLUGIN_DRONE_H #define PLUGIN_DRONE_H diff --git a/sjtu_drone_description/src/pid_controller.cpp b/sjtu_drone_description/src/pid_controller.cpp index 997449b..e8825ca 100644 --- a/sjtu_drone_description/src/pid_controller.cpp +++ b/sjtu_drone_description/src/pid_controller.cpp @@ -1,3 +1,17 @@ +// Copyright 2023 Georg Novotny +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "pid_controller.h" PIDController::PIDController() diff --git a/sjtu_drone_description/src/plugin_drone.cpp b/sjtu_drone_description/src/plugin_drone.cpp index 45738be..a53c618 100644 --- a/sjtu_drone_description/src/plugin_drone.cpp +++ b/sjtu_drone_description/src/plugin_drone.cpp @@ -1,3 +1,17 @@ +// Copyright 2023 Georg Novotny +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "plugin_drone.h"