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

Add ruff/ruff format to pre-commit & Add integration test #28

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
8 changes: 5 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ repos:
- id: requirements-txt-fixer
- id: sort-simple-yaml
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 22.12.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.9
hooks:
- id: black
- id: ruff
args: ['--output-format=full', '--fix', '--config', 'pyproject.toml']
- id: ruff-format
- repo: https://github.com/codespell-project/codespell
rev: v2.0.0
hooks:
Expand Down
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,12 @@ if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
find_package(ament_cmake_pytest REQUIRED)
find_package(ros2_control_test_assets REQUIRED)
find_package(ros_testing REQUIRED)

# ROS2 linters, but disable copyright test. PickNik's copyright's may not conform
# to this test
set(ament_cmake_flake8_FOUND TRUE)
set(ament_cmake_pep257_FOUND TRUE)
set(ament_cmake_cpplint_FOUND TRUE)
set(ament_cmake_uncrustify_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
Expand All @@ -68,6 +71,14 @@ if(BUILD_TESTING)
target_link_libraries(topic_based_system_test
${PROJECT_NAME})
ament_target_dependencies(topic_based_system_test ${THIS_PACKAGE_INCLUDE_DEPENDS} ros2_control_test_assets)

# Integration tests
add_ros_test(
test/ros2_control.test.py
TIMEOUT
120
ARGS
test_file:=${CMAKE_CURRENT_SOURCE_DIR}/test/test_topic_based_robot.py)
endif()

pluginlib_export_plugin_description_file(hardware_interface topic_based_ros2_control_plugin_description.xml)
Expand Down
1 change: 1 addition & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<test_depend>picknik_ament_copyright</test_depend>
<test_depend>ros2_control_test_assets</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>ros_testing</test_depend>

<export>
<build_type>ament_cmake</build_type>
Expand Down
20 changes: 20 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[tool.ruff]
extend-select = [
# Enabled by default
# pyflakes
# "F",
# pycodestyle
# "E",
"W",
# isort
"I",
# NumPy-specific rules
"NPY",
# Ruff-specific rules
"RUF",
]
# line-length = 88
ignore = ["E501"]
target-version = "py310"
[tool.ruff.pydocstyle]
convention = "google"
1 change: 1 addition & 0 deletions src/topic_based_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ CallbackReturn TopicBasedSystem::on_init(const hardware_interface::HardwareInfo&
// Check the initial_value param is used
if (!interface.initial_value.empty())
{
joint_states_[index][i] = std::stod(interface.initial_value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By setting this can it cause the connected robot to jump to the initial position when started?

joint_commands_[index][i] = std::stod(interface.initial_value);
}
}
Expand Down
70 changes: 70 additions & 0 deletions test/control.launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-

# Copyright 2024 PickNik Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the name of the PickNik Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import os
from pathlib import Path

import xacro
from launch import LaunchDescription
from launch_ros.actions import Node

SCRIPT_PATH = Path(os.path.realpath(__file__)).parent


def generate_launch_description():
ros2_controllers_file = Path(SCRIPT_PATH / "ros2_controllers.yaml")
robot_description = {
"robot_description": xacro.process_file(SCRIPT_PATH / "rrr.urdf.xacro").toxml(),
}
controllers = ["joint_state_broadcaster", "joint_trajectory_controller"]
return LaunchDescription(
[
Node(
package="robot_state_publisher",
executable="robot_state_publisher",
name="robot_state_publisher",
parameters=[robot_description],
),
Node(
package="controller_manager",
executable="ros2_control_node",
parameters=[robot_description, ros2_controllers_file],
output="screen",
),
]
+ [
Node(
package="controller_manager",
executable="spawner",
arguments=[controller],
)
for controller in controllers
],
)
92 changes: 92 additions & 0 deletions test/ros2_control.test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-

# Copyright 2024 PickNik Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the name of the s nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.


import os
import unittest
from pathlib import Path

import launch_testing
from launch import LaunchDescription
from launch.actions import (
DeclareLaunchArgument,
IncludeLaunchDescription,
TimerAction,
)
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import (
LaunchConfiguration,
PathJoinSubstitution,
)
from launch_ros.actions import Node

SCRIPT_PATH = Path(os.path.realpath(__file__)).parent


def generate_test_description():
test_node = Node(
executable=LaunchConfiguration("test_file"),
)

return LaunchDescription(
[
IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[
str(SCRIPT_PATH),
"control.launch.py",
],
),
],
),
),
DeclareLaunchArgument("test_file"),
TimerAction(period=2.0, actions=[test_node]),
launch_testing.util.KeepAliveProc(),
launch_testing.actions.ReadyToTest(),
],
), {
"test_node": test_node,
}


class TestWaitForCompletion(unittest.TestCase):
# Waits for test to complete, then waits a bit to make sure result files are generated
def test_run_complete(self, test_node):
self.proc_info.assertWaitForShutdown(test_node, timeout=4000.0)


@launch_testing.post_shutdown_test()
class TestProcessPostShutdown(unittest.TestCase):
# Checks if the test has been completed with acceptable exit codes (successful codes)
def test_pass(self, proc_info, test_node):
launch_testing.asserts.assertExitCodes(proc_info, process=test_node)
25 changes: 25 additions & 0 deletions test/ros2_controllers.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
controller_manager:
ros__parameters:
update_rate: 50
joint_state_broadcaster:
type: joint_state_broadcaster/JointStateBroadcaster
joint_trajectory_controller:
type: joint_trajectory_controller/JointTrajectoryController

joint_trajectory_controller:
ros__parameters:
joints:
- joint_1
- joint_2
- joint_3
command_interfaces:
- position
state_interfaces:
- position
- velocity
state_publish_rate: 100.0
action_monitor_rate: 20.0
allow_partial_joints_goal: false
constraints:
stopped_velocity_tolerance: 0.0
goal_time: 0.0
Loading
Loading