From e8dc7504356774ff294912ce6f448d09fa071ee8 Mon Sep 17 00:00:00 2001 From: Olav de Haas Date: Tue, 17 Mar 2020 19:21:24 +0100 Subject: [PATCH 1/3] Move rqt software check to here --- .flake8 | 1 + march_rqt_software_check/CMakeLists.txt | 19 +++ .../launch/checks/git_branch.launch | 5 + .../launch/checks/slave_count.launch | 5 + .../launch/march_rqt_software_check.launch | 3 + march_rqt_software_check/package.xml | 21 +++ march_rqt_software_check/plugin.xml | 12 ++ .../resource/img/march-walking.png | Bin 0 -> 8287 bytes .../resource/software_check.ui | 143 ++++++++++++++++++ .../scripts/march_git_branch_check | 22 +++ .../scripts/march_rqt_software_check | 9 ++ march_rqt_software_check/setup.py | 12 ++ .../src/march_rqt_software_check/__init__.py | 0 .../march_rqt_software_check/check_runner.py | 82 ++++++++++ .../checks/__init__.py | 0 .../checks/gait_file_directory_check.py | 33 ++++ .../checks/git_branch_check.py | 38 +++++ .../checks/launch_check.py | 22 +++ .../checks/slave_count_check.py | 22 +++ .../checks/software_check.py | 50 ++++++ .../checks/urdf_check.py | 43 ++++++ .../src/march_rqt_software_check/color.py | 12 ++ .../software_check.py | 68 +++++++++ .../software_check_thread.py | 11 ++ 24 files changed, 633 insertions(+) create mode 100644 march_rqt_software_check/CMakeLists.txt create mode 100644 march_rqt_software_check/launch/checks/git_branch.launch create mode 100644 march_rqt_software_check/launch/checks/slave_count.launch create mode 100644 march_rqt_software_check/launch/march_rqt_software_check.launch create mode 100644 march_rqt_software_check/package.xml create mode 100644 march_rqt_software_check/plugin.xml create mode 100644 march_rqt_software_check/resource/img/march-walking.png create mode 100644 march_rqt_software_check/resource/software_check.ui create mode 100755 march_rqt_software_check/scripts/march_git_branch_check create mode 100755 march_rqt_software_check/scripts/march_rqt_software_check create mode 100644 march_rqt_software_check/setup.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/__init__.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/check_runner.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/checks/__init__.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/checks/gait_file_directory_check.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/checks/git_branch_check.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/checks/launch_check.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/checks/slave_count_check.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/checks/software_check.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/checks/urdf_check.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/color.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/software_check.py create mode 100644 march_rqt_software_check/src/march_rqt_software_check/software_check_thread.py diff --git a/.flake8 b/.flake8 index b23ecc7..6d91cdb 100644 --- a/.flake8 +++ b/.flake8 @@ -7,6 +7,7 @@ application-package-names = march_rqt_gait_selection, march_rqt_input_device, march_rqt_note_taker, + march_rqt_software_check, march_shared_classes, march_shared_resources import-order-style = appnexus diff --git a/march_rqt_software_check/CMakeLists.txt b/march_rqt_software_check/CMakeLists.txt new file mode 100644 index 0000000..de228d4 --- /dev/null +++ b/march_rqt_software_check/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.8.3) +project(march_rqt_software_check) + +find_package(catkin REQUIRED) + +catkin_python_setup() +catkin_package() + +install(FILES plugin.xml + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) + +install(DIRECTORY launch resource + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) + +install(PROGRAMS scripts/march_git_branch_check scripts/march_rqt_software_check + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) diff --git a/march_rqt_software_check/launch/checks/git_branch.launch b/march_rqt_software_check/launch/checks/git_branch.launch new file mode 100644 index 0000000..c895499 --- /dev/null +++ b/march_rqt_software_check/launch/checks/git_branch.launch @@ -0,0 +1,5 @@ + + + + + diff --git a/march_rqt_software_check/launch/checks/slave_count.launch b/march_rqt_software_check/launch/checks/slave_count.launch new file mode 100644 index 0000000..b7dc188 --- /dev/null +++ b/march_rqt_software_check/launch/checks/slave_count.launch @@ -0,0 +1,5 @@ + + + + + diff --git a/march_rqt_software_check/launch/march_rqt_software_check.launch b/march_rqt_software_check/launch/march_rqt_software_check.launch new file mode 100644 index 0000000..9859e7c --- /dev/null +++ b/march_rqt_software_check/launch/march_rqt_software_check.launch @@ -0,0 +1,3 @@ + + + diff --git a/march_rqt_software_check/package.xml b/march_rqt_software_check/package.xml new file mode 100644 index 0000000..928095e --- /dev/null +++ b/march_rqt_software_check/package.xml @@ -0,0 +1,21 @@ + + + march_rqt_software_check + 0.0.0 + rqt automated software checks for the March exoskeleton + + Project March + + TODO + + catkin + + rospkg + rospy + rqt_gui + rqt_gui_py + + + + + diff --git a/march_rqt_software_check/plugin.xml b/march_rqt_software_check/plugin.xml new file mode 100644 index 0000000..d101d0a --- /dev/null +++ b/march_rqt_software_check/plugin.xml @@ -0,0 +1,12 @@ + + + + RQT plugin to perform all software checks. + + + + resource/img/march-walking.png + March Software Check + + + diff --git a/march_rqt_software_check/resource/img/march-walking.png b/march_rqt_software_check/resource/img/march-walking.png new file mode 100644 index 0000000000000000000000000000000000000000..15f9c92cab4f0056efc65e5c7129c8a88accdabf GIT binary patch literal 8287 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 + + SoftwareCheck + + + + 0 + 0 + 1109 + 796 + + + + March Software Check + + + QGroupBox { + border: 1px solid gray; + margin-top: 0.5em; +} + +QGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 3px 0 3px; +} + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + false + + + false + + + #Log { +background-color: #F2F1F0 +} + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Local + + + + + + + 150 + 150 + + + + Gait File Location + + + + + + + + 150 + 150 + + + + March IV +URDF Check + + + + + + + + + + Exoskeleton + + + + + + + 150 + 150 + + + + Slave Count + + + + + + + + 150 + 150 + + + + Git Branch + + + + + + + + + + + + + + diff --git a/march_rqt_software_check/scripts/march_git_branch_check b/march_rqt_software_check/scripts/march_git_branch_check new file mode 100755 index 0000000..0cdf130 --- /dev/null +++ b/march_rqt_software_check/scripts/march_git_branch_check @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os + +from pygit2 import Repository, GitError +import rospkg +import rospy + +result = [] + +march_launch_path = rospkg.RosPack().get_path("march_launch") +head = os.path.split(march_launch_path)[0] +source_path = os.path.split(head)[0] + +for repository_name in os.listdir(source_path): + repository_path = os.path.join(source_path, repository_name) + try: + branch_name = Repository(repository_path).head.shorthand + result.append([repository_name, branch_name]) + except GitError as e: + pass + +rospy.set_param("/checks/git_branch", result) diff --git a/march_rqt_software_check/scripts/march_rqt_software_check b/march_rqt_software_check/scripts/march_rqt_software_check new file mode 100755 index 0000000..3476365 --- /dev/null +++ b/march_rqt_software_check/scripts/march_rqt_software_check @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +import sys + +from rqt_gui.main import Main + +plugin = 'software_check' +main = Main(filename=plugin) +sys.exit(main.main(standalone=plugin)) diff --git a/march_rqt_software_check/setup.py b/march_rqt_software_check/setup.py new file mode 100644 index 0000000..659c0ab --- /dev/null +++ b/march_rqt_software_check/setup.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +from distutils.core import setup + +from catkin_pkg.python_setup import generate_distutils_setup + +d = generate_distutils_setup( + packages=['march_rqt_software_check', 'march_rqt_software_check.checks'], + package_dir={'': 'src'}, + scripts=['scripts/march_rqt_software_check'], +) + +setup(**d) diff --git a/march_rqt_software_check/src/march_rqt_software_check/__init__.py b/march_rqt_software_check/src/march_rqt_software_check/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/march_rqt_software_check/src/march_rqt_software_check/check_runner.py b/march_rqt_software_check/src/march_rqt_software_check/check_runner.py new file mode 100644 index 0000000..85294b0 --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/check_runner.py @@ -0,0 +1,82 @@ +from python_qt_binding.QtWidgets import QMessageBox +import rospy + +from .checks.gait_file_directory_check import GaitFileDirectoryCheck +from .checks.git_branch_check import GitBranchCheck +from .checks.slave_count_check import SlaveCountCheck +from .checks.urdf_check import URDFCheck +from .color import Color +from .software_check_thread import SoftwareCheckThread + + +class CheckRunner: + def __init__(self, logger=None): + self.checks = [GitBranchCheck(), GaitFileDirectoryCheck(), URDFCheck(), SlaveCountCheck()] + for check in self.checks: + check.log_signal.connect(lambda msg, color: self.log(msg, color)) + self.logger = logger + self.thread = None + + def run_check_by_name(self, name): + check = self.get_check(name) + if check is None: + self.log('Check with name ' + name + ' does not exist', Color.Error) + + return self.run_check(check) + + def run_check(self, check): + self.log('--------------------------------------', Color.Info) + + if self.thread is not None: + self.log('Already running another check', Color.Warning) + + if check is None: + self.log('Check does not exist', Color.Error) + return + + self.log('Starting check ' + str(check.name) + ': ' + str(check.description), Color.Info) + + start = rospy.get_rostime() + self.thread = SoftwareCheckThread(check) + self.thread.start() + + while not check.done: + if rospy.get_rostime() < start + rospy.Duration.from_sec(check.timeout): + rospy.sleep(0.1) + + else: + self.log('Check ' + str(check.name) + ' timed out after ' + str(check.timeout) + 's', Color.Error) + self.thread.exit() + self.thread = None + + check.reset() + return False + + self.thread.wait() + self.thread = None + result = check.passed + if result and check.manual_confirmation: + result = self.validate_manually() + check.reset() + + if result: + self.log('Check ' + str(check.name) + ' was succesful!', Color.Debug) + else: + self.log('Check ' + str(check.name) + ' has failed', Color.Error) + + return result + + def get_check(self, name): + for check in self.checks: + if check.name == name: + return check + return None + + def log(self, msg, level): + if self.logger is not None: + self.logger(msg, level) + + @staticmethod + def validate_manually(): + reply = QMessageBox.question(None, 'Message', 'Did the test pass?', QMessageBox.Yes, QMessageBox.No) + return reply == QMessageBox.Yes diff --git a/march_rqt_software_check/src/march_rqt_software_check/checks/__init__.py b/march_rqt_software_check/src/march_rqt_software_check/checks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/march_rqt_software_check/src/march_rqt_software_check/checks/gait_file_directory_check.py b/march_rqt_software_check/src/march_rqt_software_check/checks/gait_file_directory_check.py new file mode 100644 index 0000000..105a538 --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/checks/gait_file_directory_check.py @@ -0,0 +1,33 @@ +import rospkg +import rospy + +from march_rqt_software_check.color import Color + +from .launch_check import LaunchCheck + + +class GaitFileDirectoryCheck(LaunchCheck): + + def __init__(self): + LaunchCheck.__init__(self, 'GaitFileDirectory', 'Gaits are loaded from the following directory', + 'march_gait_selection', 'march_gait_selection.launch', manual_confirmation=True) + + def perform(self): + self.launch() + + rospy.sleep(rospy.Duration.from_sec(5)) + self.stop_launch_process() + package_name = self.get_key_from_parameter_server('/march/gait_file_package') + file_directory = self.get_key_from_parameter_server('/march/gait_file_directory') + + try: + rospkg.RosPack().get_path(package_name) + except rospkg.common.ResourceNotFound: + self.log('Package ' + str(package_name) + ' not found on local machine.', Color.Error) + self.fail_check() + + self.log('Package name: ' + str(package_name), Color.Info) + self.log('Gait file directory: ' + str(file_directory), Color.Info) + + self.passed = package_name is not None and file_directory is not None + self.done = True diff --git a/march_rqt_software_check/src/march_rqt_software_check/checks/git_branch_check.py b/march_rqt_software_check/src/march_rqt_software_check/checks/git_branch_check.py new file mode 100644 index 0000000..5cbaea5 --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/checks/git_branch_check.py @@ -0,0 +1,38 @@ +import rospy + +from march_rqt_software_check.color import Color + +from .launch_check import LaunchCheck + + +class GitBranchCheck(LaunchCheck): + + def __init__(self): + LaunchCheck.__init__(self, + 'GitBranch', + 'Please confirm the branches below', + 'march_rqt_software_check', + 'git_branch.launch', + 10, + True) + + def perform(self): + self.launch() + + rospy.sleep(4) + self.stop_launch_process() + + branch_tuples = self.get_key_from_parameter_server('/checks/git_branch') + + for branch_tuple in branch_tuples: + repository_name, branch_name = branch_tuple + print_string = repository_name + ': ' + branch_name + if branch_name == 'develop': + self.log(print_string, Color.Debug) + elif 'training/' in branch_name: + self.log(print_string, Color.Debug) + else: + self.log(print_string, Color.Warning) + + self.done = True + self.passed = True diff --git a/march_rqt_software_check/src/march_rqt_software_check/checks/launch_check.py b/march_rqt_software_check/src/march_rqt_software_check/checks/launch_check.py new file mode 100644 index 0000000..7d03a27 --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/checks/launch_check.py @@ -0,0 +1,22 @@ +import subprocess + +from .software_check import SoftwareCheck + + +class LaunchCheck(SoftwareCheck): + + def __init__(self, name, description, package, launch_file, timeout=10000, manual_confirmation=False): + SoftwareCheck.__init__(self, name, description, timeout, manual_confirmation) + self.package = package + self.file = launch_file + self.launch_process = None + + def launch(self): + cmd = 'roslaunch ' + self.package + ' ' + self.file + self.launch_process = subprocess.Popen(cmd, shell=True, executable='/bin/bash') + + def perform(self): + raise NotImplementedError('Please implement method "perform()" on the subclass') + + def stop_launch_process(self): + self.launch_process.kill() diff --git a/march_rqt_software_check/src/march_rqt_software_check/checks/slave_count_check.py b/march_rqt_software_check/src/march_rqt_software_check/checks/slave_count_check.py new file mode 100644 index 0000000..97bee90 --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/checks/slave_count_check.py @@ -0,0 +1,22 @@ +import rospy + +from march_rqt_software_check.color import Color + +from .launch_check import LaunchCheck + + +class SlaveCountCheck(LaunchCheck): + + def __init__(self): + LaunchCheck.__init__(self, 'SlaveCount', '', 'march_launch', 'slave_count.launch', manual_confirmation=True) + + def perform(self): + self.launch() + + rospy.sleep(rospy.Duration.from_sec(5)) + self.stop_launch_process() + slave_count = self.get_key_from_parameter_server('/check/slave_count') + + self.log('Ethercat found ' + str(slave_count) + ' slave(s)', Color.Info) + self.passed = slave_count > 0 + self.done = True diff --git a/march_rqt_software_check/src/march_rqt_software_check/checks/software_check.py b/march_rqt_software_check/src/march_rqt_software_check/checks/software_check.py new file mode 100644 index 0000000..ea2053d --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/checks/software_check.py @@ -0,0 +1,50 @@ +from PyQt5.QtCore import pyqtSignal, QObject +import rospy + +from march_rqt_software_check.color import Color + + +class SoftwareCheck(QObject): + log_signal = pyqtSignal(str, Color) + + def __init__(self, name, description, timeout=10, manual_confirmation=False): + QObject.__init__(self, None) + self.name = name + self.description = description + self.manual_confirmation = manual_confirmation + self.timeout = timeout + self.passed = False + self.done = False + + def reset(self): + self.passed = False + self.done = False + + def is_passed(self): + if self.done: + return self.passed + return False + + def perform(self): + raise NotImplementedError('Please implement method "perform()" on the subclass') + + def pass_check(self): + self.passed = True + self.done = True + + def fail_check(self): + self.passed = False + self.done = True + + def get_key_from_parameter_server(self, key, fail_on_exception=True): + try: + value = rospy.get_param(key) + except KeyError: + self.log('Could not find key ' + str(key), Color.Error) + if fail_on_exception: + self.fail_check() + return + return value + + def log(self, msg, level): + self.log_signal.emit(str(msg), level) diff --git a/march_rqt_software_check/src/march_rqt_software_check/checks/urdf_check.py b/march_rqt_software_check/src/march_rqt_software_check/checks/urdf_check.py new file mode 100644 index 0000000..6f1eed3 --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/checks/urdf_check.py @@ -0,0 +1,43 @@ +import rospy +from urdf_parser_py import urdf + +from march_rqt_software_check.color import Color + +from .launch_check import LaunchCheck + + +class URDFCheck(LaunchCheck): + + def __init__(self): + LaunchCheck.__init__(self, 'URDF', 'Please check if the loaded joints are correct', 'march_launch', + 'upload_march_urdf.launch', 10, True) + + def perform(self): + self.launch() + + rospy.sleep(rospy.Duration.from_sec(3)) + try: + robot = urdf.Robot.from_parameter_server() + except KeyError: + self.stop_launch_process() + self.fail_check() + + count = 0 + for joint in robot.joints: + if joint.type != 'fixed': + count += 1 + + self.log('Loaded ' + str(count) + ' joints', Color.Info) + for joint in robot.joints: + if joint.type != 'fixed': + lower = str(round(joint.safety_controller.soft_lower_limit, 4)) + upper = str(round(joint.safety_controller.soft_upper_limit, 4)) + velocity = str(round(joint.limit.velocity, 4)) + effort = str(round(joint.limit.effort, 4)) + msg = joint.name + ': (' + lower + ', ' + upper + ') max velocity: ' + \ + velocity + ' rad/s max effort ' + effort + ' IU' + self.log(msg, Color.Info) + + self.stop_launch_process() + self.passed = True + self.done = True diff --git a/march_rqt_software_check/src/march_rqt_software_check/color.py b/march_rqt_software_check/src/march_rqt_software_check/color.py new file mode 100644 index 0000000..57cc0bd --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/color.py @@ -0,0 +1,12 @@ +from enum import Enum + + +class Color(Enum): + Debug = '#009100' + Info = '#000000' + Warning = '#b27300' # noqa A003 + Error = '#FF0000' + Fatal = '#FF0000' + Check_Unknown = '#b27300' + Check_Failed = '#FF0000' + Check_Passed = '#009100' diff --git a/march_rqt_software_check/src/march_rqt_software_check/software_check.py b/march_rqt_software_check/src/march_rqt_software_check/software_check.py new file mode 100644 index 0000000..f7732df --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/software_check.py @@ -0,0 +1,68 @@ +import os + +from python_qt_binding import loadUi +from python_qt_binding.QtWidgets import QPlainTextEdit, QPushButton, QWidget +from qt_gui.plugin import Plugin +import rospkg + +from .check_runner import CheckRunner +from .color import Color + + +class SoftwareCheckPlugin(Plugin): + + def __init__(self, context): + super(SoftwareCheckPlugin, self).__init__(context) + # Give QObjects reasonable names + self.setObjectName('SoftwareCheckPlugin') + + # Create QWidget + self._widget = QWidget() + + # Get path to UI file which should be in the 'resource' folder of this package + ui_file = os.path.join(rospkg.RosPack().get_path('march_rqt_software_check'), 'resource', 'software_check.ui') + + # Extend the widget with all attributes and children from UI file + loadUi(ui_file, self._widget) + # Give QObjects reasonable names + self._widget.setObjectName('SoftwareCheck') + # Show _widget.windowTitle on left-top of each plugin (when + # it's set in _widget). This is useful when you open multiple + # plugins at once. Also if you open multiple instances of your + # plugin at once, these lines add number to make it easy to + # tell from pane to pane. + if context.serial_number() > 1: + self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) + # Add widget to the user interface + context.add_widget(self._widget) + + self.log('Welcome to the Software Check.', Color.Debug) + self.log('Select the software checks you want to perform.', Color.Info) + + self.check_runner = CheckRunner(self.log) + + self._widget.Checks.findChild(QPushButton, 'GitBranch') \ + .clicked.connect(lambda: self.run_test('GitBranch')) + self._widget.Checks.findChild(QPushButton, 'GaitFileDirectory') \ + .clicked.connect(lambda: self.run_test('GaitFileDirectory')) + self._widget.Checks.findChild(QPushButton, 'URDF') \ + .clicked.connect(lambda: self.run_test('URDF')) + self._widget.Checks.findChild(QPushButton, 'SlaveCount') \ + .clicked.connect(lambda: self.run_test('SlaveCount')) + + def log(self, msg, level): + self._widget.findChild(QPlainTextEdit, 'Log').appendHtml( + '

' + str(msg) + '

') + scrollbar = self._widget.findChild(QPlainTextEdit, 'Log').verticalScrollBar() + scrollbar.setValue(scrollbar.maximum()) + + def run_test(self, name): + result = self.check_runner.run_check_by_name(name) + self.update_test_button(name, result) + + def update_test_button(self, name, result): + button = self._widget.Checks.findChild(QPushButton, name) + if result: + button.setStyleSheet('background-color: ' + str(Color.Check_Passed.value)) + else: + button.setStyleSheet('background-color: ' + str(Color.Check_Failed.value)) diff --git a/march_rqt_software_check/src/march_rqt_software_check/software_check_thread.py b/march_rqt_software_check/src/march_rqt_software_check/software_check_thread.py new file mode 100644 index 0000000..1dcad43 --- /dev/null +++ b/march_rqt_software_check/src/march_rqt_software_check/software_check_thread.py @@ -0,0 +1,11 @@ +from pyqtgraph.Qt import QtCore + + +class SoftwareCheckThread(QtCore.QThread): + + def __init__(self, check): + QtCore.QThread.__init__(self) + self.check = check + + def run(self): + self.check.perform() From 7a5e73aa49dd267b76bbbc964175f675cba96808 Mon Sep 17 00:00:00 2001 From: Olav de Haas Date: Wed, 18 Mar 2020 09:37:16 +0100 Subject: [PATCH 2/3] Fix rospkg dependency --- march_rqt_software_check/package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/march_rqt_software_check/package.xml b/march_rqt_software_check/package.xml index 928095e..e47638d 100644 --- a/march_rqt_software_check/package.xml +++ b/march_rqt_software_check/package.xml @@ -10,7 +10,7 @@ catkin - rospkg + python-rospkg rospy rqt_gui rqt_gui_py From 2a3e759ff9978b8691d750e5cc2bf38861c70887 Mon Sep 17 00:00:00 2001 From: Olav de Haas Date: Wed, 18 Mar 2020 10:39:08 +0100 Subject: [PATCH 3/3] Fix catkin lint --- march_rqt_software_check/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/march_rqt_software_check/CMakeLists.txt b/march_rqt_software_check/CMakeLists.txt index de228d4..d410fec 100644 --- a/march_rqt_software_check/CMakeLists.txt +++ b/march_rqt_software_check/CMakeLists.txt @@ -14,6 +14,6 @@ install(DIRECTORY launch resource DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) -install(PROGRAMS scripts/march_git_branch_check scripts/march_rqt_software_check +install(PROGRAMS scripts/march_git_branch_check scripts/${PROJECT_NAME} DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )