Skip to content

Commit 2eabdce

Browse files
authored
Indigo, Kinetic branch Merge (#35)
Sizable merge of my indigo-devel branch on to kinetic-devel -Adds ability to generate code similar to gennodejs -Fixes a number of bugs -Updates ServiceClient calls to queue, allowing multiple successive calls that will execute in order. -Updates xmlrpc master/slave code so that calls are queued/ retried in order instead of each client retrying individually -Exposes access to log streams for other code -Support ROSCONSOLE_JS_FORMAT to format console logging -Simplifies host name logic -More TCPROS header validation -More testing -Moves examples out of repo root
1 parent 2a425c6 commit 2eabdce

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+5621
-1196
lines changed

example2.js renamed to examples/on_the_fly.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
let rosnodejs = require('./index.js');
3+
let rosnodejs = require('../index.js');
44

55
rosnodejs.initNode('/my_node', {
66
messages: ['std_msgs/String'],

example.js renamed to examples/standard.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
'use strict';
22

3-
let rosnodejs = require('./index.js');
3+
let rosnodejs = require('../index.js');
44
const std_msgs = rosnodejs.require('std_msgs').msg;
55
const SetBool = rosnodejs.require('std_srvs').srv.SetBool;
66

7-
rosnodejs.initNode('/my_node')
7+
rosnodejs.initNode('/test_node')
88
.then((rosNode) => {
99
// EXP 1) Service Server
1010
let service = rosNode.advertiseService('/set_bool', SetBool,
@@ -78,5 +78,5 @@ rosnodejs.initNode('/my_node')
7878
);
7979
})
8080
.catch((err) => {
81-
rosnodejs.log.info(err);
81+
rosnodejs.log.error(err.stack);
8282
});
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ rosnodejs.initNode('/my_node', {onTheFly: true}).then((rosNode) => {
7575
// wait two seconds for previous example to complete
7676
setTimeout(function() {
7777
let shapeActionGoal = rosnodejs.require('turtle_actionlib').msg.ShapeActionGoal;
78-
let ac = rosnodejs.getActionClient({
78+
let ac = nh.actionClient({
7979
type: "turtle_actionlib/ShapeAction",
8080
actionServer: "/turtle_shape"
8181
});

index.js

Lines changed: 80 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
const netUtils = require('./utils/network_utils.js');
2323
const msgUtils = require('./utils/message_utils.js');
24-
const messages = require('./utils/messages.js');
24+
const messages = require('./utils/messageGeneration/messages.js');
2525
const util = require('util');
2626
const RosLogStream = require('./utils/log/RosLogStream.js');
2727
const ConsoleLogStream = require('./utils/log/ConsoleLogStream.js');
@@ -31,7 +31,7 @@ const NodeHandle = require('./lib/NodeHandle.js');
3131
const Logging = require('./lib/Logging.js');
3232
const ActionClient = require('./lib/ActionClient.js');
3333

34-
msgUtils.findMessageFiles();
34+
const MsgLoader = require('./utils/messageGeneration/MessageLoader.js');
3535

3636
// these will be modules, they depend on logger which isn't initialized yet
3737
// though so they'll be required later (in initNode)
@@ -41,31 +41,43 @@ msgUtils.findMessageFiles();
4141
// will be initialized through call to initNode
4242
let log = Logging.getLogger();
4343
let rosNode = null;
44-
let firstCheck = true;
4544

4645
//------------------------------------------------------------------
4746

48-
function _checkMasterHelper(callback, timeout) {
49-
setTimeout(() => {
50-
// also check that the slave api server is set up
51-
if (!rosNode.slaveApiSetupComplete()) {
52-
_checkMasterHelper(callback, 500);
53-
return;
54-
}
55-
// else
56-
rosNode.getMasterUri()
57-
.then((resp) => {
58-
log.infoOnce('Connected to master!');
59-
callback();
60-
})
61-
.catch((err, resp) => {
47+
function _checkMasterHelper(timeout=500) {
48+
let firstCheck = true;
49+
50+
const localHelper = (resolve) => {
51+
setTimeout(() => {
52+
// also check that the slave api server is set up
53+
if (!rosNode.slaveApiSetupComplete()) {
54+
localHelper(resolve);
55+
return;
56+
}
57+
// else
6258
if (firstCheck) {
63-
log.warnOnce('Unable to connect to master. ' + err);
59+
// hook into master api connection errors.
60+
// api client will continue trying to connect
61+
rosNode._masterApi.getXmlrpcClient().once('ECONNREFUSED', (err) => {
62+
log.warn(`Unable to register with master node [${rosNode.getRosMasterUri()}]: master may not be running yet. Will keep trying.`);
63+
});
6464
firstCheck = false;
6565
}
66-
_checkMasterHelper(callback, 500);
67-
})
68-
}, timeout);
66+
rosNode.getMasterUri()
67+
.then(() => {
68+
log.infoOnce(`Connected to master at ${rosNode.getRosMasterUri()}!`);
69+
resolve();
70+
})
71+
.catch((err, resp) => {
72+
log.warnThrottle(60000, 'Unable to connect to master. ' + err);
73+
localHelper(resolve);
74+
})
75+
}, timeout);
76+
};
77+
78+
return new Promise((resolve, reject) => {
79+
localHelper(resolve);
80+
});
6981
}
7082

7183
/**
@@ -120,55 +132,63 @@ let Rosnodejs = {
120132
rosMasterUri = options.rosMasterUri;
121133
}
122134

123-
if (options.useRosEnvVars) {
124-
netUtils.useRosEnvironmentVariables();
125-
}
126-
127-
if (options.portRange) {
128-
netUtils.setPortRange(options.portRange);
129-
}
135+
Logging.initializeNodeLogger(nodeName, options.logging);
130136

131137
// create the ros node. Return a promise that will
132138
// resolve when connection to master is established
133-
let checkMasterTimeout = 0;
134139
rosNode = new RosNode(nodeName, rosMasterUri);
135140

136-
return new Promise((resolve, reject) => {
137-
const connectedToMasterCallback = () => {
138-
Logging.initializeOptions(this, options.logging);
139-
resolve(this.getNodeHandle());
140-
};
141-
142-
if (options.onTheFly) {
143-
// generate definitions for all messages and services
144-
messages.getAll(function() {
145-
_checkMasterHelper(connectedToMasterCallback, 0);
146-
});
147-
} else {
148-
_checkMasterHelper(connectedToMasterCallback, 0);
149-
}
141+
142+
return this._loadOnTheFlyMessages(options)
143+
.then(_checkMasterHelper)
144+
.then(Logging.initializeRosOptions.bind(Logging, this, options.logging))
145+
.then(() => { return this.getNodeHandle(); })
146+
.catch((err) => {
147+
log.error('Error: ' + err);
148+
});
149+
},
150+
151+
reset() {
152+
rosNode = null;
153+
},
154+
155+
_loadOnTheFlyMessages({onTheFly}) {
156+
if (onTheFly) {
157+
return new Promise((resolve, reject) => {
158+
messages.getAll(resolve);
159+
});
160+
}
161+
// else
162+
return Promise.resolve();
163+
},
164+
165+
loadPackage(packageName, outputDir=null, verbose=false) {
166+
const msgLoader = new MsgLoader(verbose);
167+
if (!outputDir) {
168+
outputDir = msgUtils.getTopLevelMessageDirectory();
169+
}
170+
return msgLoader.buildPackage(packageName, outputDir)
171+
.then(() => {
172+
console.log('Finished building messages!');
150173
})
151174
.catch((err) => {
152-
log.error('Error: ' + err);
175+
console.error(err);
153176
});
154177
},
155178

156-
require(msgPackage) {
157-
// check our registry of on-demand generate message definition
158-
var fromRegistry = messages.getPackageFromRegistry(msgPackage);
159-
if (fromRegistry) {
160-
return fromRegistry;
179+
loadAllPackages(outputDir=null, verbose=false) {
180+
const msgLoader = new MsgLoader(verbose);
181+
if (!outputDir) {
182+
outputDir = msgUtils.getTopLevelMessageDirectory();
161183
}
184+
return msgLoader.buildPackageTree(outputDir)
185+
.then(() => {
186+
console.log('Finished building messages!');
187+
})
188+
},
162189

163-
// if we can't find it in registry, check for gennodejs
164-
// pre-compiled versions
165-
let pack = msgUtils.getPackage(msgPackage);
166-
if (!pack) {
167-
msgUtils.loadMessagePackage(msgPackage);
168-
return msgUtils.getPackage(msgPackage);
169-
}
170-
// else
171-
return pack;
190+
require(msgPackage) {
191+
return msgUtils.requireMsgPackage(msgPackage);
172192
},
173193

174194
/** check that a message definition is loaded for a ros message
@@ -238,9 +258,9 @@ let Rosnodejs = {
238258
goal: { edges: 3, radius: 1 } }));
239259
*/
240260
getActionClient(options) {
241-
options.rosnodejs = Rosnodejs;
261+
options.nh = this.nh;
242262
return new ActionClient(options);
243263
}
244-
}
264+
};
245265

246266
module.exports = Rosnodejs;

lib/ActionClient.js

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
'use strict';
1919

2020
const timeUtils = require('../utils/time_utils.js');
21-
let EventEmitter = require('events');
21+
const msgUtils = require('../utils/message_utils.js');
22+
const GoalID = msgUtils.requireMsgPackage('actionlib_msgs').msg.GoalID;
23+
const EventEmitter = require('events');
2224

2325
class ActionClient extends EventEmitter {
2426
constructor(options) {
@@ -28,8 +30,7 @@ class ActionClient extends EventEmitter {
2830

2931
this._actionServer = options.actionServer;
3032

31-
this._rosnodejs = options.rosnodejs;
32-
const nh = this._rosnodejs.getNodeHandle();
33+
const nh = options.nh;
3334

3435
// FIXME: support user options for these parameters
3536
this._goalPub = nh.advertise(this._actionServer + '/goal',
@@ -79,11 +80,28 @@ class ActionClient extends EventEmitter {
7980
}
8081
}
8182

83+
/**
84+
* Cancel the given goal. If none is given, send an empty goal message,
85+
* i.e. cancel all goals. See
86+
* http://wiki.ros.org/actionlib/DetailedDescription#The_Messages
87+
* @param [goalId] {string} id of the goal to cancel
88+
*/
89+
cancel(goalId) {
90+
const cancelGoal = new GoalID({stamp: timeUtils.now()});
91+
if (!goalId) {
92+
this._cancelPub.publish(cancelGoal);
93+
}
94+
else if (this._goals.hasOwnProperty(goalId)) {
95+
cancelGoal.id = goalId;
96+
this._cancelPub.publish(cancelGoal);
97+
}
98+
}
99+
82100
sendGoal(goal) {
83101
if (!goal.goal_id) {
84102
goal.goal_id = {
85103
stamp: timeUtils.now(),
86-
id: this._generateGoalId()
104+
id: this.generateGoalId()
87105
};
88106
}
89107
if (!goal.header) {
@@ -100,19 +118,7 @@ class ActionClient extends EventEmitter {
100118
return goal;
101119
}
102120

103-
/** Cancel the given goal. If none is given, send an empty goal message,
104-
i.e. cancel all goals. See
105-
http://wiki.ros.org/actionlib/DetailedDescription#The_Messages
106-
*/
107-
cancel(goal) {
108-
if (!goal) {
109-
let GoalID = this._rosnodejs.require('actionlib_msgs').msg.GoalID;
110-
goal = new GoalID();
111-
}
112-
this._cancelPub.publish(goal);
113-
}
114-
115-
_generateGoalId() {
121+
generateGoalId() {
116122
let id = this._actionType + '.';
117123
id += 'xxxxxxxx'.replace(/[x]/g, function(c) {
118124
return (Math.random()*16).toString(16);

0 commit comments

Comments
 (0)