Skip to content

Commit 4621860

Browse files
authored
Merge pull request #14 from UWARG/ci
Added ci/cd checks
2 parents 182c917 + 6a32233 commit 4621860

File tree

8 files changed

+146
-91
lines changed

8 files changed

+146
-91
lines changed

.github/workflows/run-tests.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# This workflow will run tests and linters with PyTest using Python 3.11
2+
# For more information see: https://docs.github.com/en/actions/about-github-actions
3+
4+
name: Run linter and docker tests
5+
6+
on:
7+
push:
8+
branches: [main]
9+
pull_request:
10+
branches: [main]
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
# Checkout repository
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
with:
21+
submodules: recursive
22+
23+
# Set Python version
24+
- name: Set up Python 3.11
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: 3.11
28+
29+
# Install tools
30+
- name: Install tools
31+
run: |
32+
python -m pip install --upgrade pip
33+
pip install black flake8 pylint pytest pytest-cov
34+
35+
# Run linters and formatters
36+
- name: Linters and formatters
37+
run: |
38+
black --check .
39+
flake8 . --max-line-length=140
40+
pylint ros2_ws/src/slam/slam --disable=import-error,missing-module-docstring,missing-function-docstring,missing-class-docstring,broad-exception-caught,too-few-public-methods
41+
42+
# Tests if Docker builds
43+
- name: Docker build
44+
run: docker build -f docker/Dockerfile -t temp-ci:latest docker/
45+
46+
- name: Colcon build (for the ros2 nodes)
47+
run: |
48+
docker run --rm \
49+
-v "$GITHUB_WORKSPACE/ros2_ws:/ros2_ws" \
50+
-w /ros2_ws \
51+
temp-ci:latest \
52+
bash -lc 'source /opt/ros/jazzy/setup.bash && colcon build --event-handlers console_cohesion+'

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,5 @@ Icon?
6666
.VolumeIcon.icns
6767
.com.apple.timemachine.donotpresent
6868
.com.apple.*
69+
70+
.venv/

ros2_ws/src/slam/launch/slam_launch.py

Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,100 +5,102 @@
55
from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
66
from launch_ros.actions import Node
77
from launch_ros.substitutions import FindPackageShare
8-
import os
98

109

1110
def generate_launch_description():
1211
provide_odom_frame_arg = DeclareLaunchArgument(
13-
'provide_odom_frame',
14-
default_value='false',
15-
description='Whether to provide odom frame'
12+
"provide_odom_frame",
13+
default_value="false",
14+
description="Whether to provide odom frame",
1615
)
17-
16+
1817
expected_sensor_ids_arg = DeclareLaunchArgument(
19-
'expected_sensor_ids',
18+
"expected_sensor_ids",
2019
default_value='["scan"]',
21-
description='Expected sensor IDs for cartographer'
20+
description="Expected sensor IDs for cartographer",
2221
)
23-
22+
2423
resolution_arg = DeclareLaunchArgument(
25-
'resolution',
26-
default_value='0.05',
27-
description='Resolution for occupancy grid'
24+
"resolution",
25+
default_value="0.05",
26+
description="Resolution for occupancy grid",
2827
)
29-
28+
3029
publish_period_arg = DeclareLaunchArgument(
31-
'publish_period_sec',
32-
default_value='1.0',
33-
description='Publish period for occupancy grid'
30+
"publish_period_sec",
31+
default_value="1.0",
32+
description="Publish period for occupancy grid",
3433
)
3534

36-
slam_package_dir = FindPackageShare('slam')
37-
38-
config_dir = PathJoinSubstitution([slam_package_dir, 'config'])
35+
slam_package_dir = FindPackageShare("slam")
36+
37+
config_dir = PathJoinSubstitution([slam_package_dir, "config"])
3938

4039
# SF45B driver process
4140
sf45b_process = ExecuteProcess(
42-
cmd=['./sf45b'],
43-
cwd='/workspace',
44-
name='sf45b_driver',
45-
output='screen'
41+
cmd=["./sf45b"], cwd="/workspace", name="sf45b_driver", output="screen"
4642
)
4743

4844
# Static transform publisher node
4945
static_transform_publisher = Node(
50-
package='tf2_ros',
51-
executable='static_transform_publisher',
52-
name='laser_transform_publisher',
53-
arguments=['0', '0', '0', '0', '0', '0', 'laser', 'laser_frame'],
54-
output='screen'
46+
package="tf2_ros",
47+
executable="static_transform_publisher",
48+
name="laser_transform_publisher",
49+
arguments=["0", "0", "0", "0", "0", "0", "laser", "laser_frame"],
50+
output="screen",
5551
)
5652

5753
# Cartographer node
5854
cartographer_node = Node(
59-
package='cartographer_ros',
60-
executable='cartographer_node',
61-
name='cartographer_node',
55+
package="cartographer_ros",
56+
executable="cartographer_node",
57+
name="cartographer_node",
6258
parameters=[
63-
{'provide_odom_frame': LaunchConfiguration('provide_odom_frame')},
64-
{'expected_sensor_ids': LaunchConfiguration('expected_sensor_ids')}
59+
{"provide_odom_frame": LaunchConfiguration("provide_odom_frame")},
60+
{"expected_sensor_ids": LaunchConfiguration("expected_sensor_ids")},
6561
],
6662
arguments=[
67-
'-configuration_directory', config_dir,
68-
'-configuration_basename', 'sf45b_2d.lua'
63+
"-configuration_directory",
64+
config_dir,
65+
"-configuration_basename",
66+
"sf45b_2d.lua",
6967
],
70-
remappings=[('scan', '/scan')],
71-
output='screen'
68+
remappings=[("scan", "/scan")],
69+
output="screen",
7270
)
7371

7472
# Cartographer occupancy grid node
7573
occupancy_grid_node = Node(
76-
package='cartographer_ros',
77-
executable='cartographer_occupancy_grid_node',
78-
name='cartographer_occupancy_grid_node',
74+
package="cartographer_ros",
75+
executable="cartographer_occupancy_grid_node",
76+
name="cartographer_occupancy_grid_node",
7977
arguments=[
80-
'-resolution', LaunchConfiguration('resolution'),
81-
'-publish_period_sec', LaunchConfiguration('publish_period_sec')
78+
"-resolution",
79+
LaunchConfiguration("resolution"),
80+
"-publish_period_sec",
81+
LaunchConfiguration("publish_period_sec"),
8282
],
83-
output='screen'
83+
output="screen",
8484
)
8585

8686
# RViz2 node
8787
rviz_node = Node(
88-
package='rviz2',
89-
executable='rviz2',
90-
name='rviz2',
91-
output='screen'
88+
package="rviz2",
89+
executable="rviz2",
90+
name="rviz2",
91+
output="screen",
9292
)
9393

94-
return LaunchDescription([
95-
provide_odom_frame_arg,
96-
expected_sensor_ids_arg,
97-
resolution_arg,
98-
publish_period_arg,
99-
sf45b_process,
100-
static_transform_publisher,
101-
cartographer_node,
102-
occupancy_grid_node,
103-
rviz_node
104-
])
94+
return LaunchDescription(
95+
[
96+
provide_odom_frame_arg,
97+
expected_sensor_ids_arg,
98+
resolution_arg,
99+
publish_period_arg,
100+
sf45b_process,
101+
static_transform_publisher,
102+
cartographer_node,
103+
occupancy_grid_node,
104+
rviz_node,
105+
]
106+
)

ros2_ws/src/slam/setup.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,30 @@
22
import os
33
from glob import glob
44

5-
package_name = 'slam'
5+
package_name = "slam"
66

77
setup(
88
name=package_name,
9-
version='0.0.0',
10-
packages=find_packages(exclude=['test']),
9+
version="0.0.0",
10+
packages=find_packages(exclude=["test"]),
1111
data_files=[
12-
('share/ament_index/resource_index/packages',
13-
['resource/' + package_name]),
14-
('share/' + package_name, ['package.xml']),
15-
(os.path.join('share', package_name, 'launch'), glob('launch/*.py')),
16-
(os.path.join('share', package_name, 'config'), glob('config/*')),
12+
("share/ament_index/resource_index/packages", ["resource/" + package_name]),
13+
("share/" + package_name, ["package.xml"]),
14+
(os.path.join("share", package_name, "launch"), glob("launch/*.py")),
15+
(os.path.join("share", package_name, "config"), glob("config/*")),
1716
],
18-
install_requires=['setuptools'],
17+
install_requires=["setuptools"],
1918
zip_safe=True,
20-
maintainer='root',
21-
maintainer_email='root@todo.todo',
22-
description='TODO: Package description',
23-
license='Apache-2.0',
19+
maintainer="root",
20+
maintainer_email="root@todo.todo",
21+
description="TODO: Package description",
22+
license="Apache-2.0",
2423
extras_require={
25-
'test': [
26-
'pytest',
24+
"test": [
25+
"pytest",
2726
],
2827
},
2928
entry_points={
30-
'console_scripts': [
31-
'scan_mavlink_bridge = slam.scan_mavlink_bridge:main'
32-
],
29+
"console_scripts": ["scan_mavlink_bridge = slam.scan_mavlink_bridge:main"],
3330
},
3431
)

ros2_ws/src/slam/slam/scan_mavlink_bridge.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88

99
class RawImuBridge(Node):
1010
def __init__(self):
11-
#Create Node
12-
super().__init__('raw_imu_bridge')
11+
# Create Node
12+
super().__init__("raw_imu_bridge")
1313

14-
self.imu_pub = self.create_publisher(Imu, '/imu/data_raw', 50)
14+
self.imu_pub = self.create_publisher(Imu, "/imu/data_raw", 50)
1515

16-
#Connect the Pixhawk
16+
# Connect the Pixhawk
1717
self.port = "/dev/ttyACM0"
1818
self.baud = 115200
1919

@@ -28,9 +28,9 @@ def __init__(self):
2828
self.master.mav.request_data_stream_send(
2929
self.master.target_system,
3030
self.master.target_component,
31-
mavutil.mavlink.MAV_DATA_STREAM_RAW_SENSORS,
31+
mavutil.mavlink.MAV_DATA_STREAM_RAW_SENSORS,
3232
50, # Hz
33-
1 # start streaming
33+
1, # start streaming
3434
)
3535
self.get_logger().info("Requested RAW_IMU stream (50 Hz)")
3636

@@ -40,10 +40,10 @@ def __init__(self):
4040
self.get_logger().error(f"Failed to connect: {e}")
4141
rclpy.shutdown()
4242

43-
#Obtain IMU data
43+
# Obtain IMU data
4444
def read_serial(self):
4545
"""Read RAW_IMU messages and publish to ROS topic."""
46-
msg = self.master.recv_match(type='RAW_IMU', blocking=False)
46+
msg = self.master.recv_match(type="RAW_IMU", blocking=False)
4747
if not msg:
4848
return
4949

ros2_ws/src/slam/test/test_copyright.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717

1818

1919
# Remove the `skip` decorator once the source file(s) have a copyright header
20-
@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.')
20+
@pytest.mark.skip(
21+
reason="No copyright header has been placed in the generated source file."
22+
)
2123
@pytest.mark.copyright
2224
@pytest.mark.linter
2325
def test_copyright():
24-
rc = main(argv=['.', 'test'])
25-
assert rc == 0, 'Found errors'
26+
rc = main(argv=[".", "test"])
27+
assert rc == 0, "Found errors"

ros2_ws/src/slam/test/test_flake8.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@
2020
@pytest.mark.linter
2121
def test_flake8():
2222
rc, errors = main_with_errors(argv=[])
23-
assert rc == 0, \
24-
'Found %d code style errors / warnings:\n' % len(errors) + \
25-
'\n'.join(errors)
23+
assert rc == 0, "Found %d code style errors / warnings:\n" % len(
24+
errors
25+
) + "\n".join(errors)

ros2_ws/src/slam/test/test_pep257.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@
1919
@pytest.mark.linter
2020
@pytest.mark.pep257
2121
def test_pep257():
22-
rc = main(argv=['.', 'test'])
23-
assert rc == 0, 'Found code style errors / warnings'
22+
rc = main(argv=[".", "test"])
23+
assert rc == 0, "Found code style errors / warnings"

0 commit comments

Comments
 (0)