custom ROS messages in parfeval function?

8 views (last 30 days)
Andreas Schwager
Andreas Schwager on 2 Jun 2021
Moved: Remo Pillat on 29 Jan 2024
Hi,
rosgenmsg allows Matlab reading from individually compiled ROS mesages (using ROS Toolbox).
This works fine in my environment.
Now, I like to read the ROS message inside a parfeval function.
There is the error message:
'Cannot determine the message type of the /myRosNode/myTopic topic. Either the topic is not registered with the ROS master, or the ROS master is not reachable.'
How to copy all environment settings to the parfeval function?
Is it possible to let the parfeval function heritage all settings from calling function or current workspace?
Thanks
  2 Comments
Jagadeesh Konakalla
Jagadeesh Konakalla on 3 Jun 2021
Hi Andreas,
Can you please provide us the script that you are executing to reproduce issue on our end ?
Thanks,
Jagadeesh K.
Andreas Schwager
Andreas Schwager on 4 Jun 2021
Hello Jagadeesh ,
function parallelReadCustomTopic()
disp('parallelReadCustomTopic()')
% Parallel Computing Toolbox
p = gcp('nocreate'); % If no pool, do not create new one.
if isempty(p)
disp('Starting Parallel Computing Toolbox')
app.pool.obj = parpool;
else
disp('Parallel Computing Toolbox already running')
end
app.pool.n = 0; % count number of parallel tasks
% check if ROS is already running, if not, start ROS
[status,cmdout] = system('ps -ef|grep ros');
if status == 0
if contains(cmdout,'/opt/ros/melodic/bin/roscore')
disp('ROS is already running')
else
disp('Starting ROS...')
[status,cmdout] = system('roscore &');
pause(2);
end
else
warning(cmdout);
error(['checking ROS "ps -ef|grep ros" status: ' num2str(status)]);
end
% rosinit('192.168.213.1') % How can I check, if this is already done at another place?
disp(' ')
app.iP.d = rosdevice('192.168.213.1','login', 'password');
app.pool.q = parallel.pool.DataQueue();
[status,cmdout] = system(['ssh login@192.168.213.3 "~/startMyTopics.sh" &']);
pause(6)
rtl = rostopic("list");
topicEcho = rostopic("echo", '/rosout'); % read a standard ROS topic first. After this reading custom designed ROS topic work
disp(topicEcho.Msg)
rI = find(contains(rtl, '/myDevice/myTopic'))
topicinfo = rostopic("info", rtl{rI(1)});
if ~isempty(topicinfo.Publishers)
topicType = rostopic("type", rtl{rI(1)});
topicEcho = rostopic("echo", rtl{rI(1)});
n = size(topicEcho.specialValues,1);
disp([rtl{rI(1)} ' Number specialValues: ' num2str(n)]) % this is running fine...
end
app.pool.n = app.pool.n +1;
afterEach(app.pool.q, @disp);
app.pool.F(app.pool.n) = parfeval(@parFunction,1,app.pool.q);
% if there was an error ... plot meaasges, place breakpoint here
app.pool.F(1, app.pool.n).Error.message
app.pool.F(1, app.pool.n).Error.stack
app.pool.F(1, app.pool.n).Diary
rPTest = fetchOutputs(app.pool.F(app.pool.n));
end
function rpOut = parFunction(q)
% try
% rosinit('192.168.213.1') % How can I check, if this is already done at another place?
% catch ME
% disp(ME)
% end
send(q, sprintf('parFunction queue output'));
rtl = rostopic('list');
disp(rtl)
rpOut = rossubscriber('/myDevice/myTopic_1',@PlotResultsCallback);
send(q, sprintf('PlotRadarCallback1 initiated'));
end
function PlotResultsCallback(~, message) % it's impossible to pass arguments into rossubscriber callbacks, because these callbacks are called by ROS, not by Matlab
global rP;
n = size(message.specialValues,1);
if n> 0
% ... do my processings ...
set(handlePlot, 'XData', xyz(2,:), 'YData',xyz(1,:), 'CData',c);
end
end
The workbench shows:
>> parallelReadCustomTopic
parallelReadCustomTopic()
Parallel Computing Toolbox already running
ROS is already running
Number of available strategies: 2 Number of enabled strategies: 1
rI =
7
8
9
10
11
12
/myDevice/myTopic_1 Number Values: 14
59 app.pool.F(1, app.pool.n).Error.message
parFunction queue output
K>> app.pool.F(1, app.pool.n).Error.message
app.pool.F(1, app.pool.n).Error.stack
app.pool.F(1, app.pool.n).Diary
ans =
'Failed to create a ROS subscriber with topic name /myDevice/myTopic_1 and message type myMsgs/Image.'
ans =
struct with fields:
file: '/home/login/git/myProject/a/GUI/parallelReadCustomTopic.m'
name: 'parFunction'
line: 79
ans =
' {'/anyTopic_1' }
{'/anyTopic_2' }
{'/anyTopic_3' }
{'/anyTopic_4' }
{'/anyTopic_5' }
{'/anyTopic_6' }
{'/myDevice/myTopic_1' }
{'/myDevice/myTopic_2' }
{'/myDevice/myTopic_3' }
{'/myDevice/myTopic_4' }
{'/myDevice/myTopic_5' }
{'/myDevice/myTopic_6' }
{'/diagnostics' }
{'/rosout' }
{'/rosout_agg' }
{'/tf' }
'
K>>
I like to shift the handling of /myDevice/myTopic_1 to anoether worker. My fist core runs at almost 100% system load and I have to add more functionality.
Checking the rostopic('list') in the worker is fine. But calling rossubscriber fails...
Do you see any issues in the code, above?
Thanks for your help
Andreas

Sign in to comment.

Answers (1)

Jagadeesh Konakalla
Jagadeesh Konakalla on 8 Jun 2021
Moved: Remo Pillat on 29 Jan 2024
Hi Andreas,
Sorry for the late reply.
In ROS Toolbox, You have convenience functions like rossubscriber,rospublisher. Where all these functions uses one global node that is created at the time of rosinit. This looks like causing issues when you use functions provided by Parallel Computing Toolbox.
So, i recommend you to create and use objects of ros.Node, ros.Subscriber, ros.Publisher classes for creating a node, creating subscriber and publisher.
Please note that all the network intropsection API's (example : rostopic, rosnode) uses global node. So, i receommend you to avoid these functions in the code that is designed to run in other other workers. You can still use the introspection API's in the main MATLAB.
Below, i have provided some recommendations for you to make changes to your parFunction. Please note that i have provided a workaround (on cleanup,do rosshutdown) to work in rostopic list is in this function. This workaround should allow to use casual API's. I have not done much testing on my end.
But my recommendation is to aviod the casual API's and introspection API's in parFunction.
function rpOut = parFunction(q)
% I recommend you to avoid the rosinit and rostopic, rossubscriber in workers code.
% Use the following workaround if it works.
rosinit('192.168.213.1')
cleanVar = onCleanup(@rosshutdown);
send(q, sprintf('parFunction queue output'));
rtl = rostopic('list');
disp(rtl)
% I recommend you create a new node in worker code. In this case for subscriber create a new
% node and make sure to provide the MASTER_URI to which master uri that node to be connected.
sub_node = ros.Node('sub','http://192.168.213.1:11311');
rpOut = ros.Subscriber(sub_node,'/myDevice/myTopic_1',@PlotResultsCallback);
send(q, sprintf('PlotRadarCallback1 initiated'));
end
Please let me know if this works for you.
Thanks,
Jagadeesh K

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!