Skip to content

Commit 5bf3230

Browse files
qiuzhongMinggang Wang
authored andcommitted
Use new strategy to verify message transmitting (#250)
* Use new strategy to verify message transmitting Before we used console output of C++ and Python subscription to check the message, this may sometimes fail on low performance machine. Now we use a new strategy to verify message: * Rclnodejs publisher sends message to C++ or Python subscriptions * The subscriptions then send the message back by creating a new publisher * The rclnodejs side then creates a new subscription to receive messages Therefore, there is no need to keep the rclnodejs subscription - C++/Python publisher cases any more. Fix: #222
1 parent 159cf0c commit 5bf3230

17 files changed

+717
-1350
lines changed

scripts/compile_cpp.js

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,40 @@ const os = require('os');
1919
const path = require('path');
2020
const child = require('child_process');
2121

22-
var platform = os.platform();
22+
// var platform = os.platform();
2323
var rootDir = path.dirname(__dirname);
2424
var testCppDir = path.join(rootDir, 'test', 'cpp');
2525

26-
var publisher = (platform === 'win32') ? 'publisher_msg.exe' : 'publisher_msg';
27-
var subscription = (platform === 'win32') ? 'subscription_msg.exe' : 'subscription_msg';
26+
function getExecutable(input) {
27+
if (os.platform() === 'win32')
28+
return input + '.exe';
29+
30+
return input;
31+
}
32+
33+
var publisher = getExecutable('publisher_msg');
34+
var subscription = getExecutable('subscription_msg');
35+
var listener = getExecutable('listener');
36+
var client = getExecutable('add_two_ints_client');
37+
38+
function getExecutablePath(input) {
39+
var releaseDir = '';
40+
if (os.platform() === 'win32')
41+
releaseDir = 'Release';
42+
43+
return path.join(rootDir, 'build', 'cpp_nodes', releaseDir, input);
44+
}
45+
46+
var publisherPath = getExecutablePath(publisher);
47+
var subscriptionPath = getExecutablePath(subscription);
48+
var listenerPath = getExecutablePath(listener);
49+
var clientPath = getExecutablePath(client);
2850

29-
var publisherPath = path.join(rootDir, 'build', 'cpp_nodes',
30-
(platform === 'win32') ? 'Release' : '', publisher);
31-
var subscriptionPath = path.join(rootDir, 'build', 'cpp_nodes',
32-
(platform === 'win32') ? 'Release' : '', subscription);
3351

3452
function copyFile(platform, srcFile, destFile) {
3553
// eslint-disable-next-line
3654
if (!fs.existsSync(destFile)) {
37-
if (platform === 'win32') {
55+
if (os.platform() === 'win32') {
3856
child.spawn('cmd.exe', ['/c', `copy ${srcFile} ${destFile}`]);
3957
} else {
4058
child.spawn('sh', ['-c', `cp ${srcFile} ${destFile}`]);
@@ -44,16 +62,18 @@ function copyFile(platform, srcFile, destFile) {
4462

4563
function copyAll(fileList, dest) {
4664
fileList.forEach((file) => {
47-
copyFile(platform, file, path.join(dest, path.basename(file)));
65+
copyFile(os.platform(), file, path.join(dest, path.basename(file)));
4866
});
4967
}
5068

5169
// eslint-disable-next-line
52-
if (!fs.existsSync(publisherPath) && !fs.existsSync(subscriptionPath)) {
70+
if (!fs.existsSync(publisherPath) && !fs.existsSync(subscriptionPath) &&
71+
// eslint-disable-next-line
72+
!fs.existsSync(listenerPath) && !fs.existsSync(clientPath)) {
5373
var compileProcess = child.spawn('ament', ['build', testCppDir, '--skip-install']);
5474
compileProcess.on('close', (code) => {
55-
copyAll([publisherPath, subscriptionPath], testCppDir);
75+
copyAll([publisherPath, subscriptionPath, listenerPath, clientPath], testCppDir);
5676
});
5777
} else {
58-
copyAll([publisherPath, subscriptionPath], testCppDir);
78+
copyAll([publisherPath, subscriptionPath, , listenerPath, clientPath], testCppDir);
5979
}

test/blacklist.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"Linux": ["test-cross-lang.js", "test-interactive.js", "test-multi-nodes.js"],
3-
"Darwin": ["test-cross-lang.js", "test-interactive.js", "test-multi-nodes.js"],
4-
"Windows_NT": ["test-cross-lang.js", "test-interactive.js", "test-multi-nodes.js"]
2+
"Linux": [],
3+
"Darwin": [],
4+
"Windows_NT": []
55
}

test/client_setup.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ const rclnodejs = require('../index.js');
1919
rclnodejs.init().then(function() {
2020
var node = rclnodejs.createNode('client');
2121
const AddTwoInts = 'example_interfaces/srv/AddTwoInts';
22+
const Int8 = 'std_msgs/msg/Int8';
2223
var client = node.createClient(AddTwoInts, 'add_two_ints');
2324
const request = {
2425
a: 1,
2526
b: 2,
2627
};
27-
client.sendRequest(request, function(response) {
28-
process.stdout.write(response.sum.toString());
28+
var publisher = node.createPublisher(Int8, 'back_add_two_ints');
29+
client.sendRequest(request, (response) => {
30+
publisher.publish(response.sum);
2931
});
3032
rclnodejs.spin(node);
3133

test/cpp/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,5 @@ endfunction()
3131

3232
custom_executable(publisher_msg)
3333
custom_executable(subscription_msg)
34+
custom_executable(listener)
35+
custom_executable(add_two_ints_client)

test/cpp/add_two_ints_client.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2014 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <chrono>
16+
#include <iostream>
17+
#include <memory>
18+
#include <string>
19+
20+
#include "rclcpp/rclcpp.hpp"
21+
#include "rcutils/cmdline_parser.h"
22+
23+
#include "std_msgs/msg/int8.hpp"
24+
#include "example_interfaces/srv/add_two_ints.hpp"
25+
26+
using namespace std::chrono_literals;
27+
28+
rclcpp::Publisher<std_msgs::msg::Int8>::SharedPtr publisher = nullptr;
29+
30+
void print_usage()
31+
{
32+
printf("Usage for add_two_ints_client app:\n");
33+
printf("add_two_ints_client [-t topic_name] [-h]\n");
34+
printf("options:\n");
35+
printf("-h : Print this help function.\n");
36+
printf("-s service_name : Specify the service name for this client. Defaults to add_two_ints.\n");
37+
}
38+
39+
// TODO(wjwwood): make this into a method of rclcpp::client::Client.
40+
example_interfaces::srv::AddTwoInts_Response::SharedPtr send_request(
41+
rclcpp::Node::SharedPtr node,
42+
rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client,
43+
example_interfaces::srv::AddTwoInts_Request::SharedPtr request)
44+
{
45+
auto result = client->async_send_request(request);
46+
// Wait for the result.
47+
if (rclcpp::spin_until_future_complete(node, result) ==
48+
rclcpp::executor::FutureReturnCode::SUCCESS)
49+
{
50+
return result.get();
51+
} else {
52+
return NULL;
53+
}
54+
}
55+
56+
int main(int argc, char ** argv)
57+
{
58+
rclcpp::init(argc, argv);
59+
60+
auto node = rclcpp::Node::make_shared("add_two_ints_client");
61+
62+
if (rcutils_cli_option_exist(argv, argv + argc, "-h")) {
63+
print_usage();
64+
return 0;
65+
}
66+
67+
auto topic = std::string("add_two_ints");
68+
if (rcutils_cli_option_exist(argv, argv + argc, "-s")) {
69+
topic = std::string(rcutils_cli_get_option(argv, argv + argc, "-s"));
70+
}
71+
auto client = node->create_client<example_interfaces::srv::AddTwoInts>(topic);
72+
73+
auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();
74+
request->a = 2;
75+
request->b = 3;
76+
77+
while (!client->wait_for_service(1s)) {
78+
if (!rclcpp::ok()) {
79+
printf("add_two_ints_client was interrupted while waiting for the service. Exiting.\n");
80+
return 0;
81+
}
82+
printf("service not available, waiting again...\n");
83+
}
84+
85+
// TODO(wjwwood): make it like `client->send_request(node, request)->sum`
86+
// TODO(wjwwood): consider error condition
87+
rmw_qos_profile_t custom_qos_profile = rmw_qos_profile_default;
88+
custom_qos_profile.depth = 7;
89+
auto msg = std::make_shared<std_msgs::msg::Int8>();
90+
publisher = node->create_publisher<std_msgs::msg::Int8>(
91+
std::string("back_") + topic, custom_qos_profile);
92+
93+
94+
auto future_result = client->async_send_request(request);
95+
96+
// Wait for the result.
97+
if (rclcpp::spin_until_future_complete(node, future_result) ==
98+
rclcpp::executor::FutureReturnCode::SUCCESS)
99+
{
100+
// printf("Result of add_two_ints: %zd\n", future_result.get()->sum);
101+
msg->data = future_result.get()->sum;
102+
publisher->publish(msg);
103+
} else {
104+
printf("add_two_ints_client_async was interrupted. Exiting.\n");
105+
}
106+
107+
rclcpp::shutdown();
108+
return 0;
109+
}

test/cpp/listener.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2014 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <iostream>
16+
#include <memory>
17+
#include <string>
18+
19+
#include "rclcpp/rclcpp.hpp"
20+
#include "rcutils/cmdline_parser.h"
21+
22+
#include "std_msgs/msg/string.hpp"
23+
24+
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher = nullptr;
25+
26+
void print_usage()
27+
{
28+
printf("Usage for listener app:\n");
29+
printf("listener [-t topic_name] [-h]\n");
30+
printf("options:\n");
31+
printf("-h : Print this help function.\n");
32+
printf("-t topic_name : Specify the topic on which to subscribe. Defaults to chatter.\n");
33+
}
34+
35+
void chatterCallback(const std_msgs::msg::String::SharedPtr msg)
36+
{
37+
publisher->publish(msg);
38+
}
39+
40+
41+
42+
int main(int argc, char * argv[])
43+
{
44+
rclcpp::init(argc, argv);
45+
auto node = rclcpp::Node::make_shared("listener");
46+
47+
if (rcutils_cli_option_exist(argv, argv + argc, "-h")) {
48+
print_usage();
49+
return 0;
50+
}
51+
rmw_qos_profile_t custom_qos_profile = rmw_qos_profile_default;
52+
custom_qos_profile.depth = 7;
53+
auto topic = std::string("chatter");
54+
if (rcutils_cli_option_exist(argv, argv + argc, "-t")) {
55+
topic = std::string(rcutils_cli_get_option(argv, argv + argc, "-t"));
56+
}
57+
58+
publisher = node->create_publisher<std_msgs::msg::String>(
59+
std::string("back_") + topic, custom_qos_profile);
60+
auto sub = node->create_subscription<std_msgs::msg::String>(
61+
topic, chatterCallback, rmw_qos_profile_default);
62+
63+
rclcpp::spin(node);
64+
65+
return 0;
66+
}

0 commit comments

Comments
 (0)