Skip to content

Commit

Permalink
Merge pull request #48 from husarion/test-gazebo
Browse files Browse the repository at this point in the history
Test gazebo
  • Loading branch information
rafal-gorecki authored Nov 7, 2023
2 parents aa70ee7 + b438633 commit 5838e4d
Show file tree
Hide file tree
Showing 19 changed files with 734 additions and 21 deletions.
1 change: 1 addition & 0 deletions .github/workflows/industrial_ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ jobs:
- uses: ros-industrial/industrial_ci@master
env:
ROS_DISTRO: ${{matrix.ROS_DISTRO}}
HUSARION_ROS_BUILD: simulation
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,27 @@ black rosbot*
```


## Testing package

### Industrial CI
```
colcon test
```

> [!NOTE]
> Command `colcon test` does not build the code. Remember to build your code after changes.
If tests finish with errors print logs:
```
colcon test-result --verbose
```

### Format python code with [Black](https://github.com/psf/black)
```
cd src/
black rosbot*
```

## Demos

For further usage examples check out our other repositories:
Expand Down
2 changes: 1 addition & 1 deletion rosbot_xl_description/urdf/wheel.urdf.xacro
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<child link="${prefix}_wheel_link" />
<origin xyz="${x} ${y} 0.0" rpy="0.0 0.0 0.0" />
<axis xyz="0.0 1.0 0.0" />
<limit effort="1.27" velocity="21.0" />
<limit effort="1.5" velocity="30.0" />
<dynamics damping="0.001" friction="0.001" />
</joint>

Expand Down
11 changes: 0 additions & 11 deletions rosbot_xl_gazebo/CMakeLists.txt

This file was deleted.

32 changes: 27 additions & 5 deletions rosbot_xl_gazebo/launch/simulation.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
)
from launch.substitutions import (
PathJoinSubstitution,
PythonExpression,
LaunchConfiguration,
)
from launch.launch_description_sources import PythonLaunchDescriptionSource
Expand Down Expand Up @@ -59,13 +60,29 @@ def generate_launch_description():
description="Whether to include camera mount to the robot URDF",
)

map_package = get_package_share_directory("husarion_office_gz")
world_file = PathJoinSubstitution([map_package, "worlds", "husarion_world.sdf"])
world_package = get_package_share_directory("husarion_office_gz")
world_file = PathJoinSubstitution([world_package, "worlds", "husarion_world.sdf"])
world_cfg = LaunchConfiguration("world")
declare_world_arg = DeclareLaunchArgument(
"world", default_value=["-r ", world_file], description="SDF world file"
"world", default_value=world_file, description="SDF world file"
)

headless = LaunchConfiguration("headless")
declare_headless_arg = DeclareLaunchArgument(
"headless",
default_value="False",
description="Run Gazebo Ignition in the headless mode",
)

headless_cfg = PythonExpression(
[
"'--headless-rendering -s -r' if ",
headless,
" else '-r'",
]
)
gz_args = [headless_cfg, " ", world_cfg]

gz_sim = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
PathJoinSubstitution(
Expand All @@ -76,7 +93,10 @@ def generate_launch_description():
]
)
),
launch_arguments={"gz_args": world_cfg}.items(),
launch_arguments={
"gz_args": gz_args,
"on_exit_shutdown": "True",
}.items(),
)

gz_spawn_entity = Node(
Expand Down Expand Up @@ -153,7 +173,9 @@ def generate_launch_description():
declare_camera_model_arg,
declare_include_camera_mount_arg,
declare_world_arg,
# Sets use_sim_time for all nodes started below (doesn't work for nodes started from ignition gazebo)
declare_headless_arg,
# Sets use_sim_time for all nodes started below
# (doesn't work for nodes started from ignition gazebo)
SetParameter(name="use_sim_time", value=True),
gz_sim,
ign_bridge,
Expand Down
19 changes: 15 additions & 4 deletions rosbot_xl_gazebo/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@
<name>rosbot_xl_gazebo</name>
<version>0.8.9</version>

<description>The rosbot_xl_gazebo package</description>
<description>Gazebo Ignition simulation for ROSbot XL</description>
<license>Apache License 2.0</license>

<author email="maciej.stepien@husarion.com">Maciej Stępień</author>
<author email="krzysztof.wojciechowski@husarion.com">Krzysztof Wojciechowski</author>
<author email="jakub.delicat@husarion.com">Jakub Delicat</author>
<maintainer email="support@husarion.com">Husarion</maintainer>

<url type="website">https://husarion.com/</url>
<url type="repository">https://github.com/husarion/rosbot_xl_ros</url>
<url type="bugtracker">https://github.com/husarion/rosbot_xl_ros/issues</url>

<buildtool_depend>ament_cmake</buildtool_depend>

<exec_depend>rosbot_xl_bringup</exec_depend>

<exec_depend>launch</exec_depend>
Expand All @@ -30,7 +29,19 @@
<exec_depend>ros_gz_bridge</exec_depend>
<exec_depend>ign_ros2_control</exec_depend>

<test_depend>python3-pytest</test_depend>
<test_depend>launch</test_depend>
<test_depend>launch_ros</test_depend>
<test_depend>launch_pytest</test_depend>

<test_depend>tf_transformations</test_depend>
<test_depend>python-transforms3d-pip</test_depend>
<test_depend>nav_msgs</test_depend>
<test_depend>geometry_msgs</test_depend>

<test_depend>rosbot_xl_bringup</test_depend>

<export>
<build_type>ament_cmake</build_type>
<build_type>ament_python</build_type>
</export>
</package>
Empty file.
4 changes: 4 additions & 0 deletions rosbot_xl_gazebo/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[develop]
script_dir=$base/lib/rosbot_xl_gazebo
[install]
install_scripts=$base/lib/rosbot_xl_gazebo
40 changes: 40 additions & 0 deletions rosbot_xl_gazebo/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2023 Husarion
#
# 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 glob import glob
from setuptools import find_packages, setup

package_name = "rosbot_xl_gazebo"

setup(
name=package_name,
version="0.8.2",
packages=find_packages(exclude=["test"]),
data_files=[
("share/ament_index/resource_index/packages", ["resource/" + package_name]),
("share/" + package_name, ["package.xml"]),
(os.path.join("share", package_name, "launch"), glob("launch/*.launch.py")),
],
install_requires=["setuptools"],
zip_safe=True,
maintainer="Husarion",
maintainer_email="contact@husarion.com",
description="Gazebo Ignition simulation for ROSbot XL",
license="Apache License 2.0",
tests_require=["pytest"],
entry_points={
"console_scripts": [],
},
)
23 changes: 23 additions & 0 deletions rosbot_xl_gazebo/test/test_copyright.py
Original file line number Diff line number Diff line change
@@ -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_copyright.main import main
import pytest


@pytest.mark.copyright
@pytest.mark.linter
def test_copyright():
rc = main(argv=[".", "test"])
assert rc == 0, "Found errors"
88 changes: 88 additions & 0 deletions rosbot_xl_gazebo/test/test_diff_drive_simulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Copyright 2021 Open Source Robotics Foundation, Inc.
# Copyright 2023 Intel Corporation. All Rights Reserved.
# Copyright 2023 Husarion
#
# 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 launch_pytest
import pytest
import rclpy

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.substitutions import PathJoinSubstitution
from launch.launch_description_sources import PythonLaunchDescriptionSource

from test_utils import SimulationTestNode
from test_ign_kill_utils import kill_ign_linux_processes


@launch_pytest.fixture
def generate_test_description():
rosbot_xl_gazebo = get_package_share_directory("rosbot_xl_gazebo")
simulation_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
PathJoinSubstitution(
[
rosbot_xl_gazebo,
"launch",
"simulation.launch.py",
]
)
),
launch_arguments={
"headless": "True",
}.items(),
)

return LaunchDescription([simulation_launch])


@pytest.mark.launch(fixture=generate_test_description)
def test_diff_drive_simulation():
rclpy.init()
try:
node = SimulationTestNode("test_bringup")
node.create_test_subscribers_and_publishers()
node.start_node_thread()

flag = node.odom_tf_event.wait(timeout=60.0)
assert (
flag
), "Expected odom to base_link tf but it was not received. Check robot_localization!"

# 0.9 m/s and 3.0 rad/s are controller's limits defined in
# rosbot_controller/config/diff_drive_controller.yaml
node.set_destination_speed(0.9, 0.0, 0.0)
controller_flag = node.controller_odom_event.wait(timeout=20.0)
ekf_flag = node.ekf_odom_event.wait(timeout=20.0)
assert (
controller_flag
), "ROSbot does not move properly in x direction. Check rosbot_xl_base_controller!"
assert ekf_flag, "ROSbot does not move properly in x direction. Check ekf_filter_node!"

node.set_destination_speed(0.0, 0.0, 3.0)
controller_flag = node.controller_odom_event.wait(timeout=20.0)
ekf_flag = node.ekf_odom_event.wait(timeout=20.0)
assert controller_flag, "ROSbot does not rotate properly. Check rosbot_xl_base_controller!"
assert ekf_flag, "ROSbot does not rotate properly. Check ekf_filter_node!"

flag = node.scan_event.wait(timeout=20.0)
assert flag, "ROSbot's lidar does not work properly!"

finally:
# The pytest cannot kill properly the Gazebo Ignition's tasks what blocks launching
# several tests in a row.
kill_ign_linux_processes()
rclpy.shutdown()
23 changes: 23 additions & 0 deletions rosbot_xl_gazebo/test/test_flake8.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 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)
38 changes: 38 additions & 0 deletions rosbot_xl_gazebo/test/test_ign_kill_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2023 Husarion
#
# 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 subprocess

# The pytest cannot kill properly the Gazebo Ignition's tasks what blocks launching
# several tests in a row.


def kill_ign_linux_processes():
try:
result = subprocess.run(
["pgrep", "-f", "ign gazebo"],
capture_output=True,
text=True,
check=True,
)

pids = result.stdout.strip().split("\n")
for pid in pids:
subprocess.run(["kill", pid], check=True)
print("Killed all Ignition Gazebo processes")
except subprocess.CalledProcessError as e:
print(e)


kill_ign_linux_processes()
Loading

0 comments on commit 5838e4d

Please sign in to comment.