Skip to content

Commit

Permalink
Replaced basic launch method with roslaunch manager (#352)
Browse files Browse the repository at this point in the history
* added roslaunch module

* updated roscore

* added PackageNotFound exception

* updated PackageNotFound

* added LaunchFileNotFound

* added locate method

* moved old launch submodules

* updated API for locate method

* bad whitespace

* updated moved code

* implemented read method

* ignore long URL

* fixed optional arg

* added __call__ alias

* updated config module

* added node submodule

* added parameter submodule

* added launch submodule

* added missing import

* fixed bad import

* bad import

* finished tidying config submodule

* removed old launch method

* updated CHANGELOG

* added stub write method

* implemented write method

* updated recipes
  • Loading branch information
ChrisTimperley authored Apr 30, 2020
1 parent f1921fe commit 9f23809
Show file tree
Hide file tree
Showing 18 changed files with 415 additions and 247 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
3.6 compatibility.
* Moved all logging from Python's built-in logging library to loguru.
* Added `to_xml_tree` method to `LaunchConfig`.
* Added `PackageNotFound` and `LaunchFileNotFound` exception.
* Added `roslaunch` property to `ROSCore`, which exposes a `ROSLaunchManager`.
The manager provides various `roslaunch`-related functionality including
locating, generating, parsing, flattening, and launching launch files.
* Removed `launch` method from `ROSCore`. Replaced with `roslaunch`.


# 1.1.0 (2020-23-04)
Expand Down
2 changes: 1 addition & 1 deletion docs/recipes/record_to_bag.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
ps_sitl = system.shell.popen(f'{FN_SITL} --model copter --defaults {FN_PARAMS}')

# use roslaunch to launch the application inside the ROS session
ros.launch('apm.launch', package='mavros', args={'fcu_url': 'tcp://127.0.0.1:5760@5760'})
ros.roslaunch('apm.launch', package='mavros', args={'fcu_url': 'tcp://127.0.0.1:5760@5760'})

# to record all ROS topic data for 300 seconds
with ros.record('filepath-on-host-machine.bag') as recorder:
Expand Down
2 changes: 1 addition & 1 deletion docs/recipes/service_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
ps_sitl = system.shell.popen(f'{FN_SITL} --model copter --defaults {FN_PARAMS}')

# use roslaunch to launch the application inside the ROS session
ros.launch('apm.launch', package='mavros', args={'fcu_url': 'tcp://127.0.0.1:5760@5760'})
ros.roslaunch('apm.launch', package='mavros', args={'fcu_url': 'tcp://127.0.0.1:5760@5760'})

# let's wait some time for the copter to become armable
time.sleep(60)
Expand Down
5 changes: 3 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ max-line-length = 79
per-file-ignores =
src/roswire/__init__.py:E402,F401
src/roswire/proxy/__init__.py:F401
src/roswire/proxy/launch/__init__.py:F401
src/roswire/proxy/launch/reader.py:F811,E704
src/roswire/proxy/roslaunch/__init__.py:F401
src/roswire/proxy/roslaunch/config/__init__.py:F401
src/roswire/proxy/roslaunch/reader.py:F811,E704,E501
src/roswire/definitions/__init__.py:F401

[tox]
Expand Down
18 changes: 18 additions & 0 deletions src/roswire/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ class ROSWireException(Exception):
"""Base class used by all ROSWire exceptions."""


@_attr.s(frozen=True, auto_exc=True, auto_attribs=True, str=False)
class PackageNotFound(ValueError, ROSWireException):
"""No package was found with a given name."""
package: str

def __str__(self) -> str:
return f"Could not find package with name: {self.package}"


@_attr.s(frozen=True, auto_exc=True, auto_attribs=True, str=False)
class LaunchFileNotFound(ValueError, ROSWireException):
"""No launch file was found at the given path."""
path: str

def __str__(self) -> str:
return f"Could not find launch file at path: {self.path}"


class FailedToParseLaunchFile(ROSWireException):
"""An attempt to parse a launch file failed."""

Expand Down
5 changes: 0 additions & 5 deletions src/roswire/proxy/launch/__init__.py

This file was deleted.

152 changes: 0 additions & 152 deletions src/roswire/proxy/launch/config.py

This file was deleted.

67 changes: 7 additions & 60 deletions src/roswire/proxy/roscore.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# -*- coding: utf-8 -*-
__all__ = ('ROSCore',)

from typing import Dict, List, Mapping, Optional, Union
from typing import Dict, Optional
import os
import xmlrpc.client
import shlex
import time

from loguru import logger
import dockerblade

from .bag import BagRecorder, BagPlayer
from ..description import SystemDescription
from ..exceptions import ROSWireException
from .bag import BagRecorder, BagPlayer
from .node import NodeManager
from .parameters import ParameterServer
from .roslaunch import ROSLaunchManager
from .service import ServiceManager


Expand All @@ -29,6 +29,8 @@ class ROSCore:
The XML-RPC connection to the ROS master.
nodes: NodeManager
Provides access to the nodes running on this ROS Master.
roslaunch: ROSLaunchManager
Provides access to roslaunch-related functionality.
services: ServiceManager
Provides access to the services advertised on this ROS Master.
parameters: ParameterServer
Expand Down Expand Up @@ -65,6 +67,8 @@ def __init__(self,
self.__ip_address,
self.__connection,
self.__shell)
self.roslaunch: ROSLaunchManager = \
ROSLaunchManager(self.__shell, self.__files)

@property
def nodes(self) -> NodeManager:
Expand All @@ -90,63 +94,6 @@ def topic_to_type(self) -> Dict[str, str]:
raise ROSWireException("bad API call!")
return {name: typ for (name, typ) in result}

def launch(self,
filename: str,
*,
package: Optional[str] = None,
args: Optional[Dict[str, Union[int, str]]] = None,
prefix: Optional[str] = None,
launch_prefixes: Optional[Mapping[str, str]] = None
) -> None:
"""Provides an interface to roslaunch.
Parameters
----------
filename: str
The name of the launch file, or an absolute path to the launch
file inside the container.
package: str, optional
The name of the package to which the launch file belongs.
args: Dict[str, Union[int, str]], optional
Keyword arguments that should be supplied to roslaunch.
prefix: str, optional
An optional prefix to add before the roslaunch command.
launch_prefixes: Mapping[str, str], optional
An optional mapping from nodes, given by their names, to their
individual launch prefix.
"""
shell = self.__shell
if not args:
args = {}
if not launch_prefixes:
launch_prefixes = {}
launch_args: List[str] = [f'{arg}:={val}' for arg, val in args.items()]

if launch_prefixes:
m = "individual launch prefixes are not yet implemented"
raise NotImplementedError(m)

# determine the absolute path of the launch file
if package:
filename_original = filename
logger.debug(f'determing location of launch file [{filename}]'
f' in package [{package}]')
package_escaped = shlex.quote(package)
find_package_command = f'rospack find {package_escaped}'
package_path = shell.check_output(find_package_command,
stderr=False)
filename = os.path.join(package_path, 'launch', filename)
logger.debug('determined location of launch file'
f' [{filename_original}] in package [{package}]: '
f'{filename}')

cmd = ['roslaunch', shlex.quote(filename)]
cmd += launch_args
if prefix:
cmd = [prefix] + cmd
cmd_str = ' '.join(cmd)
self.__shell.popen(cmd_str, stdout=False, stderr=False)

def record(self,
fn: str,
exclude_topics: Optional[str] = None
Expand Down
2 changes: 2 additions & 0 deletions src/roswire/proxy/roslaunch/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from .roslaunch import ROSLaunchManager
7 changes: 7 additions & 0 deletions src/roswire/proxy/roslaunch/config/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
"""
This module provides data structures for representing roslaunch configurations.
"""
from .launch import LaunchConfig
from .node import NodeConfig
from .parameter import Parameter
Loading

0 comments on commit 9f23809

Please sign in to comment.