Skip to content

Commit

Permalink
Improve bridge command parser (ros2#396)
Browse files Browse the repository at this point in the history
* Refactor command parser to use vector of char*

Signed-off-by: LucasHaug <[email protected]>

* Add argc argv splitter to dynamic bridge

Signed-off-by: LucasHaug <[email protected]>

* Add argc argv splitter to paramter bridge

Signed-off-by: LucasHaug <[email protected]>

* Update github action

Signed-off-by: LucasHaug <[email protected]>

* Fix parameter bridge argv split

Signed-off-by: LucasHaug <[email protected]>

* Remove static argv reading

Signed-off-by: LucasHaug <[email protected]>

* Add command parser to parameter bridge

Signed-off-by: LucasHaug <[email protected]>

* Fix compilation errors

Signed-off-by: LucasHaug <[email protected]>

* Fix compilation errors

Signed-off-by: LucasHaug <[email protected]>

* Fix parameter bidge command parser

Signed-off-by: LucasHaug <[email protected]>

* Refactor to add command parser utils file

Signed-off-by: LucasHaug <[email protected]>

* Add github action issue workaround

Signed-off-by: LucasHaug <[email protected]>

* Ty to run github action inside container

Signed-off-by: LucasHaug <[email protected]>

* Fix ROS2 args when no ROS1 args

Signed-off-by: LucasHaug <[email protected]>

* Revert changes on GitHub Action config

Signed-off-by: LucasHaug <[email protected]>

* Change parameter bridge ROS init order

Signed-off-by: LucasHaug <[email protected]>

* Rename parser functions

Signed-off-by: LucasHaug <[email protected]>

* Add get_option_values function

Signed-off-by: LucasHaug <[email protected]>

* Fix wrong help for the parameter bridge

Signed-off-by: LucasHaug <[email protected]>

* Fix get_option_values parser function

Signed-off-by: LucasHaug <[email protected]>

* Refactor bridges to use the get_option_values

Signed-off-by: LucasHaug <[email protected]>

* Add running scetion to README

Signed-off-by: LucasHaug <[email protected]>

* Add print pairs to parameter bridge

---------

Signed-off-by: LucasHaug <[email protected]>
Co-authored-by: LucasHaug <[email protected]>
  • Loading branch information
LucasHaug authored and gavanderhoorn committed Oct 16, 2024
1 parent 3d5328d commit 0387316
Show file tree
Hide file tree
Showing 7 changed files with 421 additions and 62 deletions.
1 change: 0 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@ jobs:
package-name: ros1_bridge
target-ros1-distro: noetic
target-ros2-distro: rolling

1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ add_library(${PROJECT_NAME} SHARED
"src/builtin_interfaces_factories.cpp"
"src/convert_builtin_interfaces.cpp"
"src/bridge.cpp"
"src/command_parser_utils.cpp"
${generated_files})
ament_target_dependencies(${PROJECT_NAME}
${prefixed_ros1_message_packages}
Expand Down
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ To run the following examples you will also need these ROS 1 packages:

### Prerequisites for the examples in this file

In order to make the examples below portable between versions of ROS, we define two environment variables, `ROS1_INSTALL_PATH` and `ROS2_INSTALL_PATH`.
In order to make the examples below portable between versions of ROS, we define two environment variables, `ROS1_INSTALL_PATH` and `ROS2_INSTALL_PATH`.
These are defined as the paths to the installation location of their respective ROS versions.

If you installed Noetic in the default location, then the definition of `ROS1_INSTALL_PATH` will be `/opt/ros/noetic`.
Expand Down Expand Up @@ -125,6 +125,31 @@ colcon build --symlink-install --packages-select ros1_bridge --cmake-force-confi

*Note:* If you are building on a memory constrained system you might want to limit the number of parallel jobs by setting e.g. the environment variable `MAKEFLAGS=-j1`.

## Running the bridge

There are two types of bridges that are available for general use:

* The dynamic bridge which will watch the available ROS 1 and ROS 2 topics.
Once a *matching* topic has been detected it starts to bridge the messages on this topic.
* The parameter bridge which will just bridge specific topics with specific QoS profiles depending on a configuration provided by the user. For more details see the [Example 4](#example-4-bridge-only-selected-topics-and-services) section.

Too see the available command line options for each type of bridge run:

```bash
ros2 run ros1_bridge [dynamic_bridge|parameter_bridge] --help
```

To pass arguments to the ROS 1 node of the bridge, use the `--ros1-args` option. For example, to run the dynamic bridge changing the ROS 1 node namespace to `ros1_bridge`:

```bash
ros2 run ros1_bridge dynamic_bridge --ros1-args __ns:=ros1_bridge
```

To pass arguments to the ROS 2 node of the bridge, use the `--ros2-args` option. For example, to run the dynamic bridge changing the ROS 2 node namespace to `ros2_bridge`:

```bash
ros2 run ros1_bridge dynamic_bridge --ros2-args __ns:=ros2_bridge
```

## Example 1: run the bridge and the example talker and listener

Expand Down
51 changes: 51 additions & 0 deletions include/ros1_bridge/command_parser_utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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.

#ifndef ROS1_BRIDGE__COMMAND_PARSER_UTILS_HPP_
#define ROS1_BRIDGE__COMMAND_PARSER_UTILS_HPP_

#include <string>
#include <vector>

namespace ros1_bridge
{

bool find_command_option(
const std::vector<const char *> & args,
const std::string & option);

bool get_option_value(
std::vector<const char *> & args,
const std::string & option,
const char * & value,
bool remove = false);

bool get_option_values(
std::vector<const char *> & args, const std::string & option,
std::vector<const char *> & available_options,
std::vector<const char *> & values, bool remove = false);

bool get_option_flag(
std::vector<const char *> & args,
const std::string & option,
bool remove = false);

void split_ros1_ros2_args(
const std::vector<const char *> & args,
std::vector<const char *> & ros1_args,
std::vector<const char *> & ros2_args);

} // namespace ros1_bridge

#endif // ROS1_BRIDGE__COMMAND_PARSER_UTILS_HPP_
128 changes: 128 additions & 0 deletions src/command_parser_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// 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.

#include "ros1_bridge/command_parser_utils.hpp"

#include <algorithm>
#include <cstring>

namespace ros1_bridge
{

bool find_command_option(const std::vector<const char *> & args, const std::string & option)
{
auto it = std::find_if(args.begin(), args.end(), [&option] (const char * const & element) {
return strcmp(element, option.c_str()) == 0;
});

return it != args.end();
}

bool get_option_value(std::vector<const char *> & args, const std::string & option, const char * & value, bool remove)
{
auto it = std::find_if(args.begin(), args.end(), [&option] (const char * const & element) {
return strcmp(element, option.c_str()) == 0;
});

if (it != args.end()) {
auto value_it = std::next(it);

if (value_it != args.end()) {
value = *value_it;

if (remove) {
args.erase(it); // Remove option
args.erase(it); // Remove value
}

return true;
}
}

return false;
}

bool get_option_values(
std::vector<const char *> & args, const std::string & option,
std::vector<const char *> & available_options,
std::vector<const char *> & values, bool remove)
{
auto it = std::find_if(args.begin(), args.end(), [&option] (const char * const & element) {
return strcmp(element, option.c_str()) == 0;
});

if (it != args.end()) {
auto value_it = std::next(it);

while (value_it != args.end() and
std::none_of(available_options.begin(), available_options.end(),
[value_it](const char * available_option) {
return strcmp(*value_it, available_option) == 0;
})) {
values.push_back(*value_it);

if (remove) {
args.erase(value_it);
} else {
++value_it;
}
}

if (remove) {
args.erase(it); // Remove option
}

return true;
}

return false;
}

bool get_option_flag(std::vector<const char *> & args, const std::string & option, bool remove)
{
auto it = std::find_if(args.begin(), args.end(), [&option] (const char * const & element) {
return strcmp(element, option.c_str()) == 0;
});

if (it != args.end()) {
if (remove) {
args.erase(it);
}
return true;
}

return false;
}

void split_ros1_ros2_args(
const std::vector<const char *> & args, std::vector<const char *> & ros1_args,
std::vector<const char *> & ros2_args)
{
// Start iterating from the second argument, since the first argument is the executable name
auto it = std::find_if(args.begin() + 1, args.end(), [] (const char * const & element) {
return strcmp(element, "--ros-args") == 0;
});

if (it != args.end()) {
ros1_args = std::vector<const char *>(args.begin(), it);
ros2_args = std::vector<const char *>(it, args.end());
} else {
ros1_args = args;
ros2_args = {};
}

ros2_args.insert(ros2_args.begin(), args.at(0));
}

} // namespace ros1_bridge
Loading

0 comments on commit 0387316

Please sign in to comment.