1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
\r
4 * https://github.com/hij1nx/EventEmitter2
\r
6 * Copyright (c) 2013 hij1nx
\r
7 * Licensed under the MIT license.
\r
9 ;!function(undefined) {
\r
11 var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {
\r
12 return Object.prototype.toString.call(obj) === "[object Array]";
\r
14 var defaultMaxListeners = 10;
\r
19 configure.call(this, this._conf);
\r
23 function configure(conf) {
\r
27 conf.delimiter && (this.delimiter = conf.delimiter);
\r
28 this._events.maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners;
\r
29 conf.wildcard && (this.wildcard = conf.wildcard);
\r
30 conf.newListener && (this.newListener = conf.newListener);
\r
31 conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak);
\r
33 if (this.wildcard) {
\r
34 this.listenerTree = {};
\r
37 this._events.maxListeners = defaultMaxListeners;
\r
41 function logPossibleMemoryLeak(count, eventName) {
\r
42 var errorMsg = '(node) warning: possible EventEmitter memory ' +
\r
43 'leak detected. %d listeners added. ' +
\r
44 'Use emitter.setMaxListeners() to increase limit.';
\r
46 if(this.verboseMemoryLeak){
\r
47 errorMsg += ' Event name: %s.';
\r
48 console.error(errorMsg, count, eventName);
\r
50 console.error(errorMsg, count);
\r
58 function EventEmitter(conf) {
\r
60 this.newListener = false;
\r
61 this.verboseMemoryLeak = false;
\r
62 configure.call(this, conf);
\r
64 EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property
\r
67 // Attention, function return type now is array, always !
\r
68 // It has zero elements if no any matches found and one or more
\r
69 // elements (leafs) if there are matches
\r
71 function searchListenerTree(handlers, type, tree, i) {
\r
75 var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached,
\r
76 typeLength = type.length, currentType = type[i], nextType = type[i+1];
\r
77 if (i === typeLength && tree._listeners) {
\r
79 // If at the end of the event(s) list and the tree has listeners
\r
80 // invoke those listeners.
\r
82 if (typeof tree._listeners === 'function') {
\r
83 handlers && handlers.push(tree._listeners);
\r
86 for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) {
\r
87 handlers && handlers.push(tree._listeners[leaf]);
\r
93 if ((currentType === '*' || currentType === '**') || tree[currentType]) {
\r
95 // If the event emitted is '*' at this part
\r
96 // or there is a concrete match at this patch
\r
98 if (currentType === '*') {
\r
99 for (branch in tree) {
\r
100 if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
\r
101 listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1));
\r
105 } else if(currentType === '**') {
\r
106 endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*'));
\r
107 if(endReached && tree._listeners) {
\r
108 // The next element has a _listeners, add it to the handlers.
\r
109 listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength));
\r
112 for (branch in tree) {
\r
113 if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
\r
114 if(branch === '*' || branch === '**') {
\r
115 if(tree[branch]._listeners && !endReached) {
\r
116 listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength));
\r
118 listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
\r
119 } else if(branch === nextType) {
\r
120 listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2));
\r
122 // No match on this one, shift into the tree but not in the type array.
\r
123 listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
\r
130 listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1));
\r
136 // If the listener tree will allow any match for this part,
\r
137 // then recursively explore all branches of the tree
\r
139 searchListenerTree(handlers, type, xTree, i+1);
\r
142 xxTree = tree['**'];
\r
144 if(i < typeLength) {
\r
145 if(xxTree._listeners) {
\r
146 // If we have a listener on a '**', it will catch all, so add its handler.
\r
147 searchListenerTree(handlers, type, xxTree, typeLength);
\r
150 // Build arrays of matching next branches and others.
\r
151 for(branch in xxTree) {
\r
152 if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) {
\r
153 if(branch === nextType) {
\r
154 // We know the next element will match, so jump twice.
\r
155 searchListenerTree(handlers, type, xxTree[branch], i+2);
\r
156 } else if(branch === currentType) {
\r
157 // Current node matches, move into the tree.
\r
158 searchListenerTree(handlers, type, xxTree[branch], i+1);
\r
160 isolatedBranch = {};
\r
161 isolatedBranch[branch] = xxTree[branch];
\r
162 searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1);
\r
166 } else if(xxTree._listeners) {
\r
167 // We have reached the end and still on a '**'
\r
168 searchListenerTree(handlers, type, xxTree, typeLength);
\r
169 } else if(xxTree['*'] && xxTree['*']._listeners) {
\r
170 searchListenerTree(handlers, type, xxTree['*'], typeLength);
\r
177 function growListenerTree(type, listener) {
\r
179 type = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
\r
182 // Looks for two consecutive '**', if so, don't add the event at all.
\r
184 for(var i = 0, len = type.length; i+1 < len; i++) {
\r
185 if(type[i] === '**' && type[i+1] === '**') {
\r
190 var tree = this.listenerTree;
\r
191 var name = type.shift();
\r
193 while (name !== undefined) {
\r
201 if (type.length === 0) {
\r
203 if (!tree._listeners) {
\r
204 tree._listeners = listener;
\r
207 if (typeof tree._listeners === 'function') {
\r
208 tree._listeners = [tree._listeners];
\r
211 tree._listeners.push(listener);
\r
214 !tree._listeners.warned &&
\r
215 this._events.maxListeners > 0 &&
\r
216 tree._listeners.length > this._events.maxListeners
\r
218 tree._listeners.warned = true;
\r
219 logPossibleMemoryLeak.call(this, tree._listeners.length, name);
\r
224 name = type.shift();
\r
229 // By default EventEmitters will print a warning if more than
\r
230 // 10 listeners are added to it. This is a useful default which
\r
231 // helps finding memory leaks.
\r
233 // Obviously not all Emitters should be limited to 10. This function allows
\r
234 // that to be increased. Set to zero for unlimited.
\r
236 EventEmitter.prototype.delimiter = '.';
\r
238 EventEmitter.prototype.setMaxListeners = function(n) {
\r
239 if (n !== undefined) {
\r
240 this._events || init.call(this);
\r
241 this._events.maxListeners = n;
\r
242 if (!this._conf) this._conf = {};
\r
243 this._conf.maxListeners = n;
\r
247 EventEmitter.prototype.event = '';
\r
249 EventEmitter.prototype.once = function(event, fn) {
\r
250 this.many(event, 1, fn);
\r
254 EventEmitter.prototype.many = function(event, ttl, fn) {
\r
257 if (typeof fn !== 'function') {
\r
258 throw new Error('many only accepts instances of Function');
\r
261 function listener() {
\r
263 self.off(event, listener);
\r
265 fn.apply(this, arguments);
\r
268 listener._origin = fn;
\r
270 this.on(event, listener);
\r
275 EventEmitter.prototype.emit = function() {
\r
277 this._events || init.call(this);
\r
279 var type = arguments[0];
\r
281 if (type === 'newListener' && !this.newListener) {
\r
282 if (!this._events.newListener) {
\r
287 var al = arguments.length;
\r
291 if (this._all && this._all.length) {
\r
292 handler = this._all.slice();
\r
294 args = new Array(al);
\r
295 for (j = 0; j < al; j++) args[j] = arguments[j];
\r
298 for (i = 0, l = handler.length; i < l; i++) {
\r
302 handler[i].call(this, type);
\r
305 handler[i].call(this, type, arguments[1]);
\r
308 handler[i].call(this, type, arguments[1], arguments[2]);
\r
311 handler[i].apply(this, args);
\r
316 if (this.wildcard) {
\r
318 var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
\r
319 searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
\r
321 handler = this._events[type];
\r
322 if (typeof handler === 'function') {
\r
326 handler.call(this);
\r
329 handler.call(this, arguments[1]);
\r
332 handler.call(this, arguments[1], arguments[2]);
\r
335 args = new Array(al - 1);
\r
336 for (j = 1; j < al; j++) args[j - 1] = arguments[j];
\r
337 handler.apply(this, args);
\r
340 } else if (handler) {
\r
341 // need to make copy of handlers because list can change in the middle
\r
343 handler = handler.slice();
\r
347 if (handler && handler.length) {
\r
349 args = new Array(al - 1);
\r
350 for (j = 1; j < al; j++) args[j - 1] = arguments[j];
\r
352 for (i = 0, l = handler.length; i < l; i++) {
\r
356 handler[i].call(this);
\r
359 handler[i].call(this, arguments[1]);
\r
362 handler[i].call(this, arguments[1], arguments[2]);
\r
365 handler[i].apply(this, args);
\r
369 } else if (!this._all && type === 'error') {
\r
370 if (arguments[1] instanceof Error) {
\r
371 throw arguments[1]; // Unhandled 'error' event
\r
373 throw new Error("Uncaught, unspecified 'error' event.");
\r
378 return !!this._all;
\r
381 EventEmitter.prototype.emitAsync = function() {
\r
383 this._events || init.call(this);
\r
385 var type = arguments[0];
\r
387 if (type === 'newListener' && !this.newListener) {
\r
388 if (!this._events.newListener) { return Promise.resolve([false]); }
\r
393 var al = arguments.length;
\r
399 args = new Array(al);
\r
400 for (j = 1; j < al; j++) args[j] = arguments[j];
\r
402 for (i = 0, l = this._all.length; i < l; i++) {
\r
406 promises.push(this._all[i].call(this, type));
\r
409 promises.push(this._all[i].call(this, type, arguments[1]));
\r
412 promises.push(this._all[i].call(this, type, arguments[1], arguments[2]));
\r
415 promises.push(this._all[i].apply(this, args));
\r
420 if (this.wildcard) {
\r
422 var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
\r
423 searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
\r
425 handler = this._events[type];
\r
428 if (typeof handler === 'function') {
\r
432 promises.push(handler.call(this));
\r
435 promises.push(handler.call(this, arguments[1]));
\r
438 promises.push(handler.call(this, arguments[1], arguments[2]));
\r
441 args = new Array(al - 1);
\r
442 for (j = 1; j < al; j++) args[j - 1] = arguments[j];
\r
443 promises.push(handler.apply(this, args));
\r
445 } else if (handler && handler.length) {
\r
447 args = new Array(al - 1);
\r
448 for (j = 1; j < al; j++) args[j - 1] = arguments[j];
\r
450 for (i = 0, l = handler.length; i < l; i++) {
\r
454 promises.push(handler[i].call(this));
\r
457 promises.push(handler[i].call(this, arguments[1]));
\r
460 promises.push(handler[i].call(this, arguments[1], arguments[2]));
\r
463 promises.push(handler[i].apply(this, args));
\r
466 } else if (!this._all && type === 'error') {
\r
467 if (arguments[1] instanceof Error) {
\r
468 return Promise.reject(arguments[1]); // Unhandled 'error' event
\r
470 return Promise.reject("Uncaught, unspecified 'error' event.");
\r
474 return Promise.all(promises);
\r
477 EventEmitter.prototype.on = function(type, listener) {
\r
478 if (typeof type === 'function') {
\r
483 if (typeof listener !== 'function') {
\r
484 throw new Error('on only accepts instances of Function');
\r
486 this._events || init.call(this);
\r
488 // To avoid recursion in the case that type == "newListeners"! Before
\r
489 // adding it to the listeners, first emit "newListeners".
\r
490 this.emit('newListener', type, listener);
\r
492 if (this.wildcard) {
\r
493 growListenerTree.call(this, type, listener);
\r
497 if (!this._events[type]) {
\r
498 // Optimize the case of one listener. Don't need the extra array object.
\r
499 this._events[type] = listener;
\r
502 if (typeof this._events[type] === 'function') {
\r
503 // Change to array.
\r
504 this._events[type] = [this._events[type]];
\r
507 // If we've already got an array, just append.
\r
508 this._events[type].push(listener);
\r
510 // Check for listener leak
\r
512 !this._events[type].warned &&
\r
513 this._events.maxListeners > 0 &&
\r
514 this._events[type].length > this._events.maxListeners
\r
516 this._events[type].warned = true;
\r
517 logPossibleMemoryLeak.call(this, this._events[type].length, type);
\r
524 EventEmitter.prototype.onAny = function(fn) {
\r
525 if (typeof fn !== 'function') {
\r
526 throw new Error('onAny only accepts instances of Function');
\r
533 // Add the function to the event listener collection.
\r
534 this._all.push(fn);
\r
538 EventEmitter.prototype.addListener = EventEmitter.prototype.on;
\r
540 EventEmitter.prototype.off = function(type, listener) {
\r
541 if (typeof listener !== 'function') {
\r
542 throw new Error('removeListener only takes instances of Function');
\r
545 var handlers,leafs=[];
\r
547 if(this.wildcard) {
\r
548 var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
\r
549 leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
\r
552 // does not use listeners(), so no side effect of creating _events[type]
\r
553 if (!this._events[type]) return this;
\r
554 handlers = this._events[type];
\r
555 leafs.push({_listeners:handlers});
\r
558 for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
\r
559 var leaf = leafs[iLeaf];
\r
560 handlers = leaf._listeners;
\r
561 if (isArray(handlers)) {
\r
565 for (var i = 0, length = handlers.length; i < length; i++) {
\r
566 if (handlers[i] === listener ||
\r
567 (handlers[i].listener && handlers[i].listener === listener) ||
\r
568 (handlers[i]._origin && handlers[i]._origin === listener)) {
\r
574 if (position < 0) {
\r
578 if(this.wildcard) {
\r
579 leaf._listeners.splice(position, 1);
\r
582 this._events[type].splice(position, 1);
\r
585 if (handlers.length === 0) {
\r
586 if(this.wildcard) {
\r
587 delete leaf._listeners;
\r
590 delete this._events[type];
\r
594 this.emit("removeListener", type, listener);
\r
598 else if (handlers === listener ||
\r
599 (handlers.listener && handlers.listener === listener) ||
\r
600 (handlers._origin && handlers._origin === listener)) {
\r
601 if(this.wildcard) {
\r
602 delete leaf._listeners;
\r
605 delete this._events[type];
\r
608 this.emit("removeListener", type, listener);
\r
612 function recursivelyGarbageCollect(root) {
\r
613 if (root === undefined) {
\r
616 var keys = Object.keys(root);
\r
617 for (var i in keys) {
\r
619 var obj = root[key];
\r
620 if ((obj instanceof Function) || (typeof obj !== "object") || (obj === null))
\r
622 if (Object.keys(obj).length > 0) {
\r
623 recursivelyGarbageCollect(root[key]);
\r
625 if (Object.keys(obj).length === 0) {
\r
630 recursivelyGarbageCollect(this.listenerTree);
\r
635 EventEmitter.prototype.offAny = function(fn) {
\r
636 var i = 0, l = 0, fns;
\r
637 if (fn && this._all && this._all.length > 0) {
\r
639 for(i = 0, l = fns.length; i < l; i++) {
\r
640 if(fn === fns[i]) {
\r
642 this.emit("removeListenerAny", fn);
\r
648 for(i = 0, l = fns.length; i < l; i++)
\r
649 this.emit("removeListenerAny", fns[i]);
\r
655 EventEmitter.prototype.removeListener = EventEmitter.prototype.off;
\r
657 EventEmitter.prototype.removeAllListeners = function(type) {
\r
658 if (arguments.length === 0) {
\r
659 !this._events || init.call(this);
\r
663 if (this.wildcard) {
\r
664 var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
\r
665 var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
\r
667 for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
\r
668 var leaf = leafs[iLeaf];
\r
669 leaf._listeners = null;
\r
672 else if (this._events) {
\r
673 this._events[type] = null;
\r
678 EventEmitter.prototype.listeners = function(type) {
\r
679 if (this.wildcard) {
\r
681 var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
\r
682 searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);
\r
686 this._events || init.call(this);
\r
688 if (!this._events[type]) this._events[type] = [];
\r
689 if (!isArray(this._events[type])) {
\r
690 this._events[type] = [this._events[type]];
\r
692 return this._events[type];
\r
695 EventEmitter.prototype.listenerCount = function(type) {
\r
696 return this.listeners(type).length;
\r
699 EventEmitter.prototype.listenersAny = function() {
\r
710 if (typeof define === 'function' && define.amd) {
\r
711 // AMD. Register as an anonymous module.
\r
712 define(function() {
\r
713 return EventEmitter;
\r
715 } else if (typeof exports === 'object') {
\r
717 module.exports = EventEmitter;
\r
721 window.EventEmitter2 = EventEmitter;
\r
725 },{}],2:[function(require,module,exports){
\r
733 /* eslint-disable no-unused-vars */
\r
734 var getOwnPropertySymbols = Object.getOwnPropertySymbols;
\r
735 var hasOwnProperty = Object.prototype.hasOwnProperty;
\r
736 var propIsEnumerable = Object.prototype.propertyIsEnumerable;
\r
738 function toObject(val) {
\r
739 if (val === null || val === undefined) {
\r
740 throw new TypeError('Object.assign cannot be called with null or undefined');
\r
743 return Object(val);
\r
746 function shouldUseNative() {
\r
748 if (!Object.assign) {
\r
752 // Detect buggy property enumeration order in older V8 versions.
\r
754 // https://bugs.chromium.org/p/v8/issues/detail?id=4118
\r
755 var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
\r
757 if (Object.getOwnPropertyNames(test1)[0] === '5') {
\r
761 // https://bugs.chromium.org/p/v8/issues/detail?id=3056
\r
763 for (var i = 0; i < 10; i++) {
\r
764 test2['_' + String.fromCharCode(i)] = i;
\r
766 var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
\r
769 if (order2.join('') !== '0123456789') {
\r
773 // https://bugs.chromium.org/p/v8/issues/detail?id=3056
\r
775 'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
\r
776 test3[letter] = letter;
\r
778 if (Object.keys(Object.assign({}, test3)).join('') !==
\r
779 'abcdefghijklmnopqrst') {
\r
785 // We don't expect any of the above to throw, but better to be safe.
\r
790 module.exports = shouldUseNative() ? Object.assign : function (target, source) {
\r
792 var to = toObject(target);
\r
795 for (var s = 1; s < arguments.length; s++) {
\r
796 from = Object(arguments[s]);
\r
798 for (var key in from) {
\r
799 if (hasOwnProperty.call(from, key)) {
\r
800 to[key] = from[key];
\r
804 if (getOwnPropertySymbols) {
\r
805 symbols = getOwnPropertySymbols(from);
\r
806 for (var i = 0; i < symbols.length; i++) {
\r
807 if (propIsEnumerable.call(from, symbols[i])) {
\r
808 to[symbols[i]] = from[symbols[i]];
\r
817 },{}],3:[function(require,module,exports){
\r
820 * @author Russell Toris - rctoris@wpi.edu
\r
824 * If you use roslib in a browser, all the classes will be exported to a global variable called ROSLIB.
\r
826 * If you use nodejs, this is the variable you get when you require('roslib')
\r
828 var ROSLIB = this.ROSLIB || {
\r
829 REVISION : '0.20.0'
\r
832 var assign = require('object-assign');
\r
834 // Add core components
\r
835 assign(ROSLIB, require('./core'));
\r
837 assign(ROSLIB, require('./actionlib'));
\r
839 assign(ROSLIB, require('./math'));
\r
841 assign(ROSLIB, require('./tf'));
\r
843 assign(ROSLIB, require('./urdf'));
\r
845 module.exports = ROSLIB;
\r
847 },{"./actionlib":9,"./core":18,"./math":23,"./tf":26,"./urdf":38,"object-assign":2}],4:[function(require,module,exports){
\r
848 (function (global){
\r
849 global.ROSLIB = require('./RosLib');
\r
850 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
\r
851 },{"./RosLib":3}],5:[function(require,module,exports){
\r
854 * @author Russell Toris - rctoris@wpi.edu
\r
857 var Topic = require('../core/Topic');
\r
858 var Message = require('../core/Message');
\r
859 var EventEmitter2 = require('eventemitter2').EventEmitter2;
\r
862 * An actionlib action client.
\r
864 * Emits the following events:
\r
865 * * 'timeout' - if a timeout occurred while sending a goal
\r
866 * * 'status' - the status messages received from the action server
\r
867 * * 'feedback' - the feedback messages received from the action server
\r
868 * * 'result' - the result returned from the action server
\r
871 * @param options - object with following keys:
\r
872 * * ros - the ROSLIB.Ros connection handle
\r
873 * * serverName - the action server name, like /fibonacci
\r
874 * * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction'
\r
875 * * timeout - the timeout length when connecting to the action server
\r
877 function ActionClient(options) {
\r
879 options = options || {};
\r
880 this.ros = options.ros;
\r
881 this.serverName = options.serverName;
\r
882 this.actionName = options.actionName;
\r
883 this.timeout = options.timeout;
\r
884 this.omitFeedback = options.omitFeedback;
\r
885 this.omitStatus = options.omitStatus;
\r
886 this.omitResult = options.omitResult;
\r
889 // flag to check if a status has been received
\r
890 var receivedStatus = false;
\r
892 // create the topics associated with actionlib
\r
893 this.feedbackListener = new Topic({
\r
895 name : this.serverName + '/feedback',
\r
896 messageType : this.actionName + 'Feedback'
\r
899 this.statusListener = new Topic({
\r
901 name : this.serverName + '/status',
\r
902 messageType : 'actionlib_msgs/GoalStatusArray'
\r
905 this.resultListener = new Topic({
\r
907 name : this.serverName + '/result',
\r
908 messageType : this.actionName + 'Result'
\r
911 this.goalTopic = new Topic({
\r
913 name : this.serverName + '/goal',
\r
914 messageType : this.actionName + 'Goal'
\r
917 this.cancelTopic = new Topic({
\r
919 name : this.serverName + '/cancel',
\r
920 messageType : 'actionlib_msgs/GoalID'
\r
923 // advertise the goal and cancel topics
\r
924 this.goalTopic.advertise();
\r
925 this.cancelTopic.advertise();
\r
927 // subscribe to the status topic
\r
928 if (!this.omitStatus) {
\r
929 this.statusListener.subscribe(function(statusMessage) {
\r
930 receivedStatus = true;
\r
931 statusMessage.status_list.forEach(function(status) {
\r
932 var goal = that.goals[status.goal_id.id];
\r
934 goal.emit('status', status);
\r
940 // subscribe the the feedback topic
\r
941 if (!this.omitFeedback) {
\r
942 this.feedbackListener.subscribe(function(feedbackMessage) {
\r
943 var goal = that.goals[feedbackMessage.status.goal_id.id];
\r
945 goal.emit('status', feedbackMessage.status);
\r
946 goal.emit('feedback', feedbackMessage.feedback);
\r
951 // subscribe to the result topic
\r
952 if (!this.omitResult) {
\r
953 this.resultListener.subscribe(function(resultMessage) {
\r
954 var goal = that.goals[resultMessage.status.goal_id.id];
\r
957 goal.emit('status', resultMessage.status);
\r
958 goal.emit('result', resultMessage.result);
\r
963 // If timeout specified, emit a 'timeout' event if the action server does not respond
\r
964 if (this.timeout) {
\r
965 setTimeout(function() {
\r
966 if (!receivedStatus) {
\r
967 that.emit('timeout');
\r
973 ActionClient.prototype.__proto__ = EventEmitter2.prototype;
\r
976 * Cancel all goals associated with this ActionClient.
\r
978 ActionClient.prototype.cancel = function() {
\r
979 var cancelMessage = new Message();
\r
980 this.cancelTopic.publish(cancelMessage);
\r
984 * Unsubscribe and unadvertise all topics associated with this ActionClient.
\r
986 ActionClient.prototype.dispose = function() {
\r
987 this.goalTopic.unadvertise();
\r
988 this.cancelTopic.unadvertise();
\r
989 if (!this.omitStatus) {this.statusListener.unsubscribe();}
\r
990 if (!this.omitFeedback) {this.feedbackListener.unsubscribe();}
\r
991 if (!this.omitResult) {this.resultListener.unsubscribe();}
\r
994 module.exports = ActionClient;
\r
996 },{"../core/Message":10,"../core/Topic":17,"eventemitter2":1}],6:[function(require,module,exports){
\r
999 * @author Justin Young - justin@oodar.com.au
\r
1000 * @author Russell Toris - rctoris@wpi.edu
\r
1003 var Topic = require('../core/Topic');
\r
1004 var Message = require('../core/Message');
\r
1005 var EventEmitter2 = require('eventemitter2').EventEmitter2;
\r
1008 * An actionlib action listener
\r
1010 * Emits the following events:
\r
1011 * * 'status' - the status messages received from the action server
\r
1012 * * 'feedback' - the feedback messages received from the action server
\r
1013 * * 'result' - the result returned from the action server
\r
1016 * @param options - object with following keys:
\r
1017 * * ros - the ROSLIB.Ros connection handle
\r
1018 * * serverName - the action server name, like /fibonacci
\r
1019 * * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction'
\r
1021 function ActionListener(options) {
\r
1023 options = options || {};
\r
1024 this.ros = options.ros;
\r
1025 this.serverName = options.serverName;
\r
1026 this.actionName = options.actionName;
\r
1027 this.timeout = options.timeout;
\r
1028 this.omitFeedback = options.omitFeedback;
\r
1029 this.omitStatus = options.omitStatus;
\r
1030 this.omitResult = options.omitResult;
\r
1033 // create the topics associated with actionlib
\r
1034 var goalListener = new Topic({
\r
1036 name : this.serverName + '/goal',
\r
1037 messageType : this.actionName + 'Goal'
\r
1040 var feedbackListener = new Topic({
\r
1042 name : this.serverName + '/feedback',
\r
1043 messageType : this.actionName + 'Feedback'
\r
1046 var statusListener = new Topic({
\r
1048 name : this.serverName + '/status',
\r
1049 messageType : 'actionlib_msgs/GoalStatusArray'
\r
1052 var resultListener = new Topic({
\r
1054 name : this.serverName + '/result',
\r
1055 messageType : this.actionName + 'Result'
\r
1058 goalListener.subscribe(function(goalMessage) {
\r
1059 that.emit('goal', goalMessage);
\r
1062 statusListener.subscribe(function(statusMessage) {
\r
1063 statusMessage.status_list.forEach(function(status) {
\r
1064 that.emit('status', status);
\r
1068 feedbackListener.subscribe(function(feedbackMessage) {
\r
1069 that.emit('status', feedbackMessage.status);
\r
1070 that.emit('feedback', feedbackMessage.feedback);
\r
1073 // subscribe to the result topic
\r
1074 resultListener.subscribe(function(resultMessage) {
\r
1075 that.emit('status', resultMessage.status);
\r
1076 that.emit('result', resultMessage.result);
\r
1081 ActionListener.prototype.__proto__ = EventEmitter2.prototype;
\r
1083 module.exports = ActionListener;
\r
1085 },{"../core/Message":10,"../core/Topic":17,"eventemitter2":1}],7:[function(require,module,exports){
\r
1088 * @author Russell Toris - rctoris@wpi.edu
\r
1091 var Message = require('../core/Message');
\r
1092 var EventEmitter2 = require('eventemitter2').EventEmitter2;
\r
1095 * An actionlib goal goal is associated with an action server.
\r
1097 * Emits the following events:
\r
1098 * * 'timeout' - if a timeout occurred while sending a goal
\r
1101 * @param object with following keys:
\r
1102 * * actionClient - the ROSLIB.ActionClient to use with this goal
\r
1103 * * goalMessage - The JSON object containing the goal for the action server
\r
1105 function Goal(options) {
\r
1107 this.actionClient = options.actionClient;
\r
1108 this.goalMessage = options.goalMessage;
\r
1109 this.isFinished = false;
\r
1111 // Used to create random IDs
\r
1112 var date = new Date();
\r
1114 // Create a random ID
\r
1115 this.goalID = 'goal_' + Math.random() + '_' + date.getTime();
\r
1116 // Fill in the goal message
\r
1117 this.goalMessage = new Message({
\r
1125 goal : this.goalMessage
\r
1128 this.on('status', function(status) {
\r
1129 that.status = status;
\r
1132 this.on('result', function(result) {
\r
1133 that.isFinished = true;
\r
1134 that.result = result;
\r
1137 this.on('feedback', function(feedback) {
\r
1138 that.feedback = feedback;
\r
1142 this.actionClient.goals[this.goalID] = this;
\r
1145 Goal.prototype.__proto__ = EventEmitter2.prototype;
\r
1148 * Send the goal to the action server.
\r
1150 * @param timeout (optional) - a timeout length for the goal's result
\r
1152 Goal.prototype.send = function(timeout) {
\r
1154 that.actionClient.goalTopic.publish(that.goalMessage);
\r
1156 setTimeout(function() {
\r
1157 if (!that.isFinished) {
\r
1158 that.emit('timeout');
\r
1165 * Cancel the current goal.
\r
1167 Goal.prototype.cancel = function() {
\r
1168 var cancelMessage = new Message({
\r
1171 this.actionClient.cancelTopic.publish(cancelMessage);
\r
1174 module.exports = Goal;
\r
1175 },{"../core/Message":10,"eventemitter2":1}],8:[function(require,module,exports){
\r
1178 * @author Laura Lindzey - lindzey@gmail.com
\r
1181 var Topic = require('../core/Topic');
\r
1182 var Message = require('../core/Message');
\r
1183 var EventEmitter2 = require('eventemitter2').EventEmitter2;
\r
1186 * An actionlib action server client.
\r
1188 * Emits the following events:
\r
1189 * * 'goal' - goal sent by action client
\r
1190 * * 'cancel' - action client has canceled the request
\r
1193 * @param options - object with following keys:
\r
1194 * * ros - the ROSLIB.Ros connection handle
\r
1195 * * serverName - the action server name, like /fibonacci
\r
1196 * * actionName - the action message name, like 'actionlib_tutorials/FibonacciAction'
\r
1199 function SimpleActionServer(options) {
\r
1201 options = options || {};
\r
1202 this.ros = options.ros;
\r
1203 this.serverName = options.serverName;
\r
1204 this.actionName = options.actionName;
\r
1206 // create and advertise publishers
\r
1207 this.feedbackPublisher = new Topic({
\r
1209 name : this.serverName + '/feedback',
\r
1210 messageType : this.actionName + 'Feedback'
\r
1212 this.feedbackPublisher.advertise();
\r
1214 var statusPublisher = new Topic({
\r
1216 name : this.serverName + '/status',
\r
1217 messageType : 'actionlib_msgs/GoalStatusArray'
\r
1219 statusPublisher.advertise();
\r
1221 this.resultPublisher = new Topic({
\r
1223 name : this.serverName + '/result',
\r
1224 messageType : this.actionName + 'Result'
\r
1226 this.resultPublisher.advertise();
\r
1228 // create and subscribe to listeners
\r
1229 var goalListener = new Topic({
\r
1231 name : this.serverName + '/goal',
\r
1232 messageType : this.actionName + 'Goal'
\r
1235 var cancelListener = new Topic({
\r
1237 name : this.serverName + '/cancel',
\r
1238 messageType : 'actionlib_msgs/GoalID'
\r
1241 // Track the goals and their status in order to publish status...
\r
1242 this.statusMessage = new Message({
\r
1244 stamp : {secs : 0, nsecs : 100},
\r
1250 // needed for handling preemption prompted by a new goal being received
\r
1251 this.currentGoal = null; // currently tracked goal
\r
1252 this.nextGoal = null; // the one that'll be preempting
\r
1254 goalListener.subscribe(function(goalMessage) {
\r
1256 if(that.currentGoal) {
\r
1257 that.nextGoal = goalMessage;
\r
1258 // needs to happen AFTER rest is set up
\r
1259 that.emit('cancel');
\r
1261 that.statusMessage.status_list = [{goal_id : goalMessage.goal_id, status : 1}];
\r
1262 that.currentGoal = goalMessage;
\r
1263 that.emit('goal', goalMessage.goal);
\r
1267 // helper function for determing ordering of timestamps
\r
1268 // returns t1 < t2
\r
1269 var isEarlier = function(t1, t2) {
\r
1270 if(t1.secs > t2.secs) {
\r
1272 } else if(t1.secs < t2.secs) {
\r
1274 } else if(t1.nsecs < t2.nsecs) {
\r
1281 // TODO: this may be more complicated than necessary, since I'm
\r
1282 // not sure if the callbacks can ever wind up with a scenario
\r
1283 // where we've been preempted by a next goal, it hasn't finished
\r
1284 // processing, and then we get a cancel message
\r
1285 cancelListener.subscribe(function(cancelMessage) {
\r
1287 // cancel ALL goals if both empty
\r
1288 if(cancelMessage.stamp.secs === 0 && cancelMessage.stamp.secs === 0 && cancelMessage.id === '') {
\r
1289 that.nextGoal = null;
\r
1290 if(that.currentGoal) {
\r
1291 that.emit('cancel');
\r
1293 } else { // treat id and stamp independently
\r
1294 if(that.currentGoal && cancelMessage.id === that.currentGoal.goal_id.id) {
\r
1295 that.emit('cancel');
\r
1296 } else if(that.nextGoal && cancelMessage.id === that.nextGoal.goal_id.id) {
\r
1297 that.nextGoal = null;
\r
1300 if(that.nextGoal && isEarlier(that.nextGoal.goal_id.stamp,
\r
1301 cancelMessage.stamp)) {
\r
1302 that.nextGoal = null;
\r
1304 if(that.currentGoal && isEarlier(that.currentGoal.goal_id.stamp,
\r
1305 cancelMessage.stamp)) {
\r
1307 that.emit('cancel');
\r
1312 // publish status at pseudo-fixed rate; required for clients to know they've connected
\r
1313 var statusInterval = setInterval( function() {
\r
1314 var currentTime = new Date();
\r
1315 var secs = Math.floor(currentTime.getTime()/1000);
\r
1316 var nsecs = Math.round(1000000000*(currentTime.getTime()/1000-secs));
\r
1317 that.statusMessage.header.stamp.secs = secs;
\r
1318 that.statusMessage.header.stamp.nsecs = nsecs;
\r
1319 statusPublisher.publish(that.statusMessage);
\r
1320 }, 500); // publish every 500ms
\r
1324 SimpleActionServer.prototype.__proto__ = EventEmitter2.prototype;
\r
1327 * Set action state to succeeded and return to client
\r
1330 SimpleActionServer.prototype.setSucceeded = function(result2) {
\r
1333 var resultMessage = new Message({
\r
1334 status : {goal_id : this.currentGoal.goal_id, status : 3},
\r
1337 this.resultPublisher.publish(resultMessage);
\r
1339 this.statusMessage.status_list = [];
\r
1340 if(this.nextGoal) {
\r
1341 this.currentGoal = this.nextGoal;
\r
1342 this.nextGoal = null;
\r
1343 this.emit('goal', this.currentGoal.goal);
\r
1345 this.currentGoal = null;
\r
1350 * Function to send feedback
\r
1353 SimpleActionServer.prototype.sendFeedback = function(feedback2) {
\r
1355 var feedbackMessage = new Message({
\r
1356 status : {goal_id : this.currentGoal.goal_id, status : 1},
\r
1357 feedback : feedback2
\r
1359 this.feedbackPublisher.publish(feedbackMessage);
\r
1363 * Handle case where client requests preemption
\r
1366 SimpleActionServer.prototype.setPreempted = function() {
\r
1368 this.statusMessage.status_list = [];
\r
1369 var resultMessage = new Message({
\r
1370 status : {goal_id : this.currentGoal.goal_id, status : 2},
\r
1372 this.resultPublisher.publish(resultMessage);
\r
1374 if(this.nextGoal) {
\r
1375 this.currentGoal = this.nextGoal;
\r
1376 this.nextGoal = null;
\r
1377 this.emit('goal', this.currentGoal.goal);
\r
1379 this.currentGoal = null;
\r
1383 module.exports = SimpleActionServer;
\r
1384 },{"../core/Message":10,"../core/Topic":17,"eventemitter2":1}],9:[function(require,module,exports){
\r
1385 var Ros = require('../core/Ros');
\r
1386 var mixin = require('../mixin');
\r
1388 var action = module.exports = {
\r
1389 ActionClient: require('./ActionClient'),
\r
1390 ActionListener: require('./ActionListener'),
\r
1391 Goal: require('./Goal'),
\r
1392 SimpleActionServer: require('./SimpleActionServer')
\r
1395 mixin(Ros, ['ActionClient', 'SimpleActionServer'], action);
\r
1397 },{"../core/Ros":12,"../mixin":24,"./ActionClient":5,"./ActionListener":6,"./Goal":7,"./SimpleActionServer":8}],10:[function(require,module,exports){
\r
1400 * @author Brandon Alexander - baalexander@gmail.com
\r
1403 var assign = require('object-assign');
\r
1406 * Message objects are used for publishing and subscribing to and from topics.
\r
1409 * @param values - object matching the fields defined in the .msg definition file
\r
1411 function Message(values) {
\r
1412 assign(this, values);
\r
1415 module.exports = Message;
\r
1416 },{"object-assign":2}],11:[function(require,module,exports){
\r
1419 * @author Brandon Alexander - baalexander@gmail.com
\r
1422 var Service = require('./Service');
\r
1423 var ServiceRequest = require('./ServiceRequest');
\r
1426 * A ROS parameter.
\r
1429 * @param options - possible keys include:
\r
1430 * * ros - the ROSLIB.Ros connection handle
\r
1431 * * name - the param name, like max_vel_x
\r
1433 function Param(options) {
\r
1434 options = options || {};
\r
1435 this.ros = options.ros;
\r
1436 this.name = options.name;
\r
1440 * Fetches the value of the param.
\r
1442 * @param callback - function with the following params:
\r
1443 * * value - the value of the param from ROS.
\r
1445 Param.prototype.get = function(callback) {
\r
1446 var paramClient = new Service({
\r
1448 name : '/rosapi/get_param',
\r
1449 serviceType : 'rosapi/GetParam'
\r
1452 var request = new ServiceRequest({
\r
1456 paramClient.callService(request, function(result) {
\r
1457 var value = JSON.parse(result.value);
\r
1463 * Sets the value of the param in ROS.
\r
1465 * @param value - value to set param to.
\r
1467 Param.prototype.set = function(value, callback) {
\r
1468 var paramClient = new Service({
\r
1470 name : '/rosapi/set_param',
\r
1471 serviceType : 'rosapi/SetParam'
\r
1474 var request = new ServiceRequest({
\r
1476 value : JSON.stringify(value)
\r
1479 paramClient.callService(request, callback);
\r
1483 * Delete this parameter on the ROS server.
\r
1485 Param.prototype.delete = function(callback) {
\r
1486 var paramClient = new Service({
\r
1488 name : '/rosapi/delete_param',
\r
1489 serviceType : 'rosapi/DeleteParam'
\r
1492 var request = new ServiceRequest({
\r
1496 paramClient.callService(request, callback);
\r
1499 module.exports = Param;
\r
1500 },{"./Service":13,"./ServiceRequest":14}],12:[function(require,module,exports){
\r
1503 * @author Brandon Alexander - baalexander@gmail.com
\r
1506 var WebSocket = require('ws');
\r
1507 var socketAdapter = require('./SocketAdapter.js');
\r
1509 var Service = require('./Service');
\r
1510 var ServiceRequest = require('./ServiceRequest');
\r
1512 var assign = require('object-assign');
\r
1513 var EventEmitter2 = require('eventemitter2').EventEmitter2;
\r
1516 * Manages connection to the server and all interactions with ROS.
\r
1518 * Emits the following events:
\r
1519 * * 'error' - there was an error with ROS
\r
1520 * * 'connection' - connected to the WebSocket server
\r
1521 * * 'close' - disconnected to the WebSocket server
\r
1522 * * <topicName> - a message came from rosbridge with the given topic name
\r
1523 * * <serviceID> - a service response came from rosbridge with the given ID
\r
1526 * @param options - possible keys include: <br>
\r
1527 * * url (optional) - (can be specified later with `connect`) the WebSocket URL for rosbridge or the node server url to connect using socket.io (if socket.io exists in the page) <br>
\r
1528 * * groovyCompatibility - don't use interfaces that changed after the last groovy release or rosbridge_suite and related tools (defaults to true)
\r
1529 * * transportLibrary (optional) - one of 'websocket' (default), 'socket.io' or RTCPeerConnection instance controlling how the connection is created in `connect`.
\r
1530 * * transportOptions (optional) - the options to use use when creating a connection. Currently only used if `transportLibrary` is RTCPeerConnection.
\r
1532 function Ros(options) {
\r
1533 options = options || {};
\r
1534 this.socket = null;
\r
1535 this.idCounter = 0;
\r
1536 this.isConnected = false;
\r
1537 this.transportLibrary = options.transportLibrary || 'websocket';
\r
1538 this.transportOptions = options.transportOptions || {};
\r
1540 if (typeof options.groovyCompatibility === 'undefined') {
\r
1541 this.groovyCompatibility = true;
\r
1544 this.groovyCompatibility = options.groovyCompatibility;
\r
1547 // Sets unlimited event listeners.
\r
1548 this.setMaxListeners(0);
\r
1550 // begin by checking if a URL was given
\r
1551 if (options.url) {
\r
1552 this.connect(options.url);
\r
1556 Ros.prototype.__proto__ = EventEmitter2.prototype;
\r
1559 * Connect to the specified WebSocket.
\r
1561 * @param url - WebSocket URL or RTCDataChannel label for Rosbridge
\r
1563 Ros.prototype.connect = function(url) {
\r
1564 if (this.transportLibrary === 'socket.io') {
\r
1565 this.socket = assign(io(url, {'force new connection': true}), socketAdapter(this));
\r
1566 this.socket.on('connect', this.socket.onopen);
\r
1567 this.socket.on('data', this.socket.onmessage);
\r
1568 this.socket.on('close', this.socket.onclose);
\r
1569 this.socket.on('error', this.socket.onerror);
\r
1570 } else if (this.transportLibrary.constructor.name === 'RTCPeerConnection') {
\r
1571 this.socket = assign(this.transportLibrary.createDataChannel(url, this.transportOptions), socketAdapter(this));
\r
1573 this.socket = assign(new WebSocket(url), socketAdapter(this));
\r
1579 * Disconnect from the WebSocket server.
\r
1581 Ros.prototype.close = function() {
\r
1582 if (this.socket) {
\r
1583 this.socket.close();
\r
1588 * Sends an authorization request to the server.
\r
1590 * @param mac - MAC (hash) string given by the trusted source.
\r
1591 * @param client - IP of the client.
\r
1592 * @param dest - IP of the destination.
\r
1593 * @param rand - Random string given by the trusted source.
\r
1594 * @param t - Time of the authorization request.
\r
1595 * @param level - User level as a string given by the client.
\r
1596 * @param end - End time of the client's session.
\r
1598 Ros.prototype.authenticate = function(mac, client, dest, rand, t, level, end) {
\r
1599 // create the request
\r
1610 // send the request
\r
1611 this.callOnConnection(auth);
\r
1615 * Sends the message over the WebSocket, but queues the message up if not yet
\r
1618 Ros.prototype.callOnConnection = function(message) {
\r
1620 var messageJson = JSON.stringify(message);
\r
1621 var emitter = null;
\r
1622 if (this.transportLibrary === 'socket.io') {
\r
1623 emitter = function(msg){that.socket.emit('operation', msg);};
\r
1625 emitter = function(msg){that.socket.send(msg);};
\r
1628 if (!this.isConnected) {
\r
1629 that.once('connection', function() {
\r
1630 emitter(messageJson);
\r
1633 emitter(messageJson);
\r
1638 * Sends a set_level request to the server
\r
1640 * @param level - Status level (none, error, warning, info)
\r
1641 * @param id - Optional: Operation ID to change status level on
\r
1643 Ros.prototype.setStatusLevel = function(level, id){
\r
1650 this.callOnConnection(levelMsg);
\r
1654 * Retrieves Action Servers in ROS as an array of string
\r
1656 * * actionservers - Array of action server names
\r
1658 Ros.prototype.getActionServers = function(callback, failedCallback) {
\r
1659 var getActionServers = new Service({
\r
1661 name : '/rosapi/action_servers',
\r
1662 serviceType : 'rosapi/GetActionServers'
\r
1665 var request = new ServiceRequest({});
\r
1666 if (typeof failedCallback === 'function'){
\r
1667 getActionServers.callService(request,
\r
1668 function(result) {
\r
1669 callback(result.action_servers);
\r
1671 function(message){
\r
1672 failedCallback(message);
\r
1676 getActionServers.callService(request, function(result) {
\r
1677 callback(result.action_servers);
\r
1683 * Retrieves list of topics in ROS as an array.
\r
1685 * @param callback function with params:
\r
1686 * * topics - Array of topic names
\r
1688 Ros.prototype.getTopics = function(callback, failedCallback) {
\r
1689 var topicsClient = new Service({
\r
1691 name : '/rosapi/topics',
\r
1692 serviceType : 'rosapi/Topics'
\r
1695 var request = new ServiceRequest();
\r
1696 if (typeof failedCallback === 'function'){
\r
1697 topicsClient.callService(request,
\r
1698 function(result) {
\r
1701 function(message){
\r
1702 failedCallback(message);
\r
1706 topicsClient.callService(request, function(result) {
\r
1713 * Retrieves Topics in ROS as an array as specific type
\r
1715 * @param topicType topic type to find:
\r
1716 * @param callback function with params:
\r
1717 * * topics - Array of topic names
\r
1719 Ros.prototype.getTopicsForType = function(topicType, callback, failedCallback) {
\r
1720 var topicsForTypeClient = new Service({
\r
1722 name : '/rosapi/topics_for_type',
\r
1723 serviceType : 'rosapi/TopicsForType'
\r
1726 var request = new ServiceRequest({
\r
1729 if (typeof failedCallback === 'function'){
\r
1730 topicsForTypeClient.callService(request,
\r
1731 function(result) {
\r
1732 callback(result.topics);
\r
1734 function(message){
\r
1735 failedCallback(message);
\r
1739 topicsForTypeClient.callService(request, function(result) {
\r
1740 callback(result.topics);
\r
1746 * Retrieves list of active service names in ROS.
\r
1748 * @param callback - function with the following params:
\r
1749 * * services - array of service names
\r
1751 Ros.prototype.getServices = function(callback, failedCallback) {
\r
1752 var servicesClient = new Service({
\r
1754 name : '/rosapi/services',
\r
1755 serviceType : 'rosapi/Services'
\r
1758 var request = new ServiceRequest();
\r
1759 if (typeof failedCallback === 'function'){
\r
1760 servicesClient.callService(request,
\r
1761 function(result) {
\r
1762 callback(result.services);
\r
1764 function(message) {
\r
1765 failedCallback(message);
\r
1769 servicesClient.callService(request, function(result) {
\r
1770 callback(result.services);
\r
1776 * Retrieves list of services in ROS as an array as specific type
\r
1778 * @param serviceType service type to find:
\r
1779 * @param callback function with params:
\r
1780 * * topics - Array of service names
\r
1782 Ros.prototype.getServicesForType = function(serviceType, callback, failedCallback) {
\r
1783 var servicesForTypeClient = new Service({
\r
1785 name : '/rosapi/services_for_type',
\r
1786 serviceType : 'rosapi/ServicesForType'
\r
1789 var request = new ServiceRequest({
\r
1792 if (typeof failedCallback === 'function'){
\r
1793 servicesForTypeClient.callService(request,
\r
1794 function(result) {
\r
1795 callback(result.services);
\r
1797 function(message) {
\r
1798 failedCallback(message);
\r
1802 servicesForTypeClient.callService(request, function(result) {
\r
1803 callback(result.services);
\r
1809 * Retrieves a detail of ROS service request.
\r
1811 * @param service name of service:
\r
1812 * @param callback - function with params:
\r
1813 * * type - String of the service type
\r
1815 Ros.prototype.getServiceRequestDetails = function(type, callback, failedCallback) {
\r
1816 var serviceTypeClient = new Service({
\r
1818 name : '/rosapi/service_request_details',
\r
1819 serviceType : 'rosapi/ServiceRequestDetails'
\r
1821 var request = new ServiceRequest({
\r
1825 if (typeof failedCallback === 'function'){
\r
1826 serviceTypeClient.callService(request,
\r
1827 function(result) {
\r
1830 function(message){
\r
1831 failedCallback(message);
\r
1835 serviceTypeClient.callService(request, function(result) {
\r
1842 * Retrieves a detail of ROS service request.
\r
1844 * @param service name of service:
\r
1845 * @param callback - function with params:
\r
1846 * * type - String of the service type
\r
1848 Ros.prototype.getServiceResponseDetails = function(type, callback, failedCallback) {
\r
1849 var serviceTypeClient = new Service({
\r
1851 name : '/rosapi/service_response_details',
\r
1852 serviceType : 'rosapi/ServiceResponseDetails'
\r
1854 var request = new ServiceRequest({
\r
1858 if (typeof failedCallback === 'function'){
\r
1859 serviceTypeClient.callService(request,
\r
1860 function(result) {
\r
1863 function(message){
\r
1864 failedCallback(message);
\r
1868 serviceTypeClient.callService(request, function(result) {
\r
1875 * Retrieves list of active node names in ROS.
\r
1877 * @param callback - function with the following params:
\r
1878 * * nodes - array of node names
\r
1880 Ros.prototype.getNodes = function(callback, failedCallback) {
\r
1881 var nodesClient = new Service({
\r
1883 name : '/rosapi/nodes',
\r
1884 serviceType : 'rosapi/Nodes'
\r
1887 var request = new ServiceRequest();
\r
1888 if (typeof failedCallback === 'function'){
\r
1889 nodesClient.callService(request,
\r
1890 function(result) {
\r
1891 callback(result.nodes);
\r
1893 function(message) {
\r
1894 failedCallback(message);
\r
1898 nodesClient.callService(request, function(result) {
\r
1899 callback(result.nodes);
\r
1905 * Retrieves list subscribed topics, publishing topics and services of a specific node
\r
1907 * @param node name of the node:
\r
1908 * @param callback - function with params:
\r
1909 * * publications - array of published topic names
\r
1910 * * subscriptions - array of subscribed topic names
\r
1911 * * services - array of service names hosted
\r
1913 Ros.prototype.getNodeDetails = function(node, callback, failedCallback) {
\r
1914 var nodesClient = new Service({
\r
1916 name : '/rosapi/node_details',
\r
1917 serviceType : 'rosapi/NodeDetails'
\r
1920 var request = new ServiceRequest({
\r
1923 if (typeof failedCallback === 'function'){
\r
1924 nodesClient.callService(request,
\r
1925 function(result) {
\r
1926 callback(result.subscribing, result.publishing, result.services);
\r
1928 function(message) {
\r
1929 failedCallback(message);
\r
1933 nodesClient.callService(request, function(result) {
\r
1940 * Retrieves list of param names from the ROS Parameter Server.
\r
1942 * @param callback function with params:
\r
1943 * * params - array of param names.
\r
1945 Ros.prototype.getParams = function(callback, failedCallback) {
\r
1946 var paramsClient = new Service({
\r
1948 name : '/rosapi/get_param_names',
\r
1949 serviceType : 'rosapi/GetParamNames'
\r
1951 var request = new ServiceRequest();
\r
1952 if (typeof failedCallback === 'function'){
\r
1953 paramsClient.callService(request,
\r
1954 function(result) {
\r
1955 callback(result.names);
\r
1957 function(message){
\r
1958 failedCallback(message);
\r
1962 paramsClient.callService(request, function(result) {
\r
1963 callback(result.names);
\r
1969 * Retrieves a type of ROS topic.
\r
1971 * @param topic name of the topic:
\r
1972 * @param callback - function with params:
\r
1973 * * type - String of the topic type
\r
1975 Ros.prototype.getTopicType = function(topic, callback, failedCallback) {
\r
1976 var topicTypeClient = new Service({
\r
1978 name : '/rosapi/topic_type',
\r
1979 serviceType : 'rosapi/TopicType'
\r
1981 var request = new ServiceRequest({
\r
1985 if (typeof failedCallback === 'function'){
\r
1986 topicTypeClient.callService(request,
\r
1987 function(result) {
\r
1988 callback(result.type);
\r
1990 function(message){
\r
1991 failedCallback(message);
\r
1995 topicTypeClient.callService(request, function(result) {
\r
1996 callback(result.type);
\r
2002 * Retrieves a type of ROS service.
\r
2004 * @param service name of service:
\r
2005 * @param callback - function with params:
\r
2006 * * type - String of the service type
\r
2008 Ros.prototype.getServiceType = function(service, callback, failedCallback) {
\r
2009 var serviceTypeClient = new Service({
\r
2011 name : '/rosapi/service_type',
\r
2012 serviceType : 'rosapi/ServiceType'
\r
2014 var request = new ServiceRequest({
\r
2018 if (typeof failedCallback === 'function'){
\r
2019 serviceTypeClient.callService(request,
\r
2020 function(result) {
\r
2021 callback(result.type);
\r
2023 function(message){
\r
2024 failedCallback(message);
\r
2028 serviceTypeClient.callService(request, function(result) {
\r
2029 callback(result.type);
\r
2035 * Retrieves a detail of ROS message.
\r
2037 * @param callback - function with params:
\r
2038 * * details - Array of the message detail
\r
2039 * @param message - String of a topic type
\r
2041 Ros.prototype.getMessageDetails = function(message, callback, failedCallback) {
\r
2042 var messageDetailClient = new Service({
\r
2044 name : '/rosapi/message_details',
\r
2045 serviceType : 'rosapi/MessageDetails'
\r
2047 var request = new ServiceRequest({
\r
2051 if (typeof failedCallback === 'function'){
\r
2052 messageDetailClient.callService(request,
\r
2053 function(result) {
\r
2054 callback(result.typedefs);
\r
2056 function(message){
\r
2057 failedCallback(message);
\r
2061 messageDetailClient.callService(request, function(result) {
\r
2062 callback(result.typedefs);
\r
2068 * Decode a typedefs into a dictionary like `rosmsg show foo/bar`
\r
2070 * @param defs - array of type_def dictionary
\r
2072 Ros.prototype.decodeTypeDefs = function(defs) {
\r
2075 // calls itself recursively to resolve type definition using hints.
\r
2076 var decodeTypeDefsRec = function(theType, hints) {
\r
2077 var typeDefDict = {};
\r
2078 for (var i = 0; i < theType.fieldnames.length; i++) {
\r
2079 var arrayLen = theType.fieldarraylen[i];
\r
2080 var fieldName = theType.fieldnames[i];
\r
2081 var fieldType = theType.fieldtypes[i];
\r
2082 if (fieldType.indexOf('/') === -1) { // check the fieldType includes '/' or not
\r
2083 if (arrayLen === -1) {
\r
2084 typeDefDict[fieldName] = fieldType;
\r
2087 typeDefDict[fieldName] = [fieldType];
\r
2091 // lookup the name
\r
2093 for (var j = 0; j < hints.length; j++) {
\r
2094 if (hints[j].type.toString() === fieldType.toString()) {
\r
2100 var subResult = decodeTypeDefsRec(sub, hints);
\r
2101 if (arrayLen === -1) {
\r
2104 typeDefDict[fieldName] = [subResult];
\r
2108 that.emit('error', 'Cannot find ' + fieldType + ' in decodeTypeDefs');
\r
2112 return typeDefDict;
\r
2115 return decodeTypeDefsRec(defs[0], defs);
\r
2119 module.exports = Ros;
\r
2121 },{"./Service":13,"./ServiceRequest":14,"./SocketAdapter.js":16,"eventemitter2":1,"object-assign":2,"ws":39}],13:[function(require,module,exports){
\r
2124 * @author Brandon Alexander - baalexander@gmail.com
\r
2127 var ServiceResponse = require('./ServiceResponse');
\r
2128 var ServiceRequest = require('./ServiceRequest');
\r
2129 var EventEmitter2 = require('eventemitter2').EventEmitter2;
\r
2132 * A ROS service client.
\r
2135 * @params options - possible keys include:
\r
2136 * * ros - the ROSLIB.Ros connection handle
\r
2137 * * name - the service name, like /add_two_ints
\r
2138 * * serviceType - the service type, like 'rospy_tutorials/AddTwoInts'
\r
2140 function Service(options) {
\r
2141 options = options || {};
\r
2142 this.ros = options.ros;
\r
2143 this.name = options.name;
\r
2144 this.serviceType = options.serviceType;
\r
2145 this.isAdvertised = false;
\r
2147 this._serviceCallback = null;
\r
2149 Service.prototype.__proto__ = EventEmitter2.prototype;
\r
2151 * Calls the service. Returns the service response in the callback.
\r
2153 * @param request - the ROSLIB.ServiceRequest to send
\r
2154 * @param callback - function with params:
\r
2155 * * response - the response from the service request
\r
2156 * @param failedCallback - the callback function when the service call failed (optional). Params:
\r
2157 * * error - the error message reported by ROS
\r
2159 Service.prototype.callService = function(request, callback, failedCallback) {
\r
2160 if (this.isAdvertised) {
\r
2164 var serviceCallId = 'call_service:' + this.name + ':' + (++this.ros.idCounter);
\r
2166 if (callback || failedCallback) {
\r
2167 this.ros.once(serviceCallId, function(message) {
\r
2168 if (message.result !== undefined && message.result === false) {
\r
2169 if (typeof failedCallback === 'function') {
\r
2170 failedCallback(message.values);
\r
2172 } else if (typeof callback === 'function') {
\r
2173 callback(new ServiceResponse(message.values));
\r
2179 op : 'call_service',
\r
2180 id : serviceCallId,
\r
2181 service : this.name,
\r
2184 this.ros.callOnConnection(call);
\r
2188 * Every time a message is published for the given topic, the callback
\r
2189 * will be called with the message object.
\r
2191 * @param callback - function with the following params:
\r
2192 * * message - the published message
\r
2194 Service.prototype.advertise = function(callback) {
\r
2195 if (this.isAdvertised || typeof callback !== 'function') {
\r
2199 this._serviceCallback = callback;
\r
2200 this.ros.on(this.name, this._serviceResponse.bind(this));
\r
2201 this.ros.callOnConnection({
\r
2202 op: 'advertise_service',
\r
2203 type: this.serviceType,
\r
2204 service: this.name
\r
2206 this.isAdvertised = true;
\r
2209 Service.prototype.unadvertise = function() {
\r
2210 if (!this.isAdvertised) {
\r
2213 this.ros.callOnConnection({
\r
2214 op: 'unadvertise_service',
\r
2215 service: this.name
\r
2217 this.isAdvertised = false;
\r
2220 Service.prototype._serviceResponse = function(rosbridgeRequest) {
\r
2221 var response = {};
\r
2222 var success = this._serviceCallback(rosbridgeRequest.args, response);
\r
2225 op: 'service_response',
\r
2226 service: this.name,
\r
2227 values: new ServiceResponse(response),
\r
2231 if (rosbridgeRequest.id) {
\r
2232 call.id = rosbridgeRequest.id;
\r
2235 this.ros.callOnConnection(call);
\r
2238 module.exports = Service;
\r
2239 },{"./ServiceRequest":14,"./ServiceResponse":15,"eventemitter2":1}],14:[function(require,module,exports){
\r
2242 * @author Brandon Alexander - balexander@willowgarage.com
\r
2245 var assign = require('object-assign');
\r
2248 * A ServiceRequest is passed into the service call.
\r
2251 * @param values - object matching the fields defined in the .srv definition file
\r
2253 function ServiceRequest(values) {
\r
2254 assign(this, values);
\r
2257 module.exports = ServiceRequest;
\r
2258 },{"object-assign":2}],15:[function(require,module,exports){
\r
2261 * @author Brandon Alexander - balexander@willowgarage.com
\r
2264 var assign = require('object-assign');
\r
2267 * A ServiceResponse is returned from the service call.
\r
2270 * @param values - object matching the fields defined in the .srv definition file
\r
2272 function ServiceResponse(values) {
\r
2273 assign(this, values);
\r
2276 module.exports = ServiceResponse;
\r
2277 },{"object-assign":2}],16:[function(require,module,exports){
\r
2279 * Socket event handling utilities for handling events on either
\r
2280 * WebSocket and TCP sockets
\r
2282 * Note to anyone reviewing this code: these functions are called
\r
2283 * in the context of their parent object, unless bound
\r
2288 var decompressPng = require('../util/decompressPng');
\r
2289 var WebSocket = require('ws');
\r
2291 if(typeof bson !== 'undefined'){
\r
2292 BSON = bson().BSON;
\r
2296 * Events listeners for a WebSocket or TCP socket to a JavaScript
\r
2297 * ROS Client. Sets up Messages for a given topic to trigger an
\r
2298 * event on the ROS client.
\r
2300 * @namespace SocketAdapter
\r
2303 function SocketAdapter(client) {
\r
2304 function handleMessage(message) {
\r
2305 if (message.op === 'publish') {
\r
2306 client.emit(message.topic, message.msg);
\r
2307 } else if (message.op === 'service_response') {
\r
2308 client.emit(message.id, message);
\r
2309 } else if (message.op === 'call_service') {
\r
2310 client.emit(message.service, message);
\r
2311 } else if(message.op === 'status'){
\r
2313 client.emit('status:'+message.id, message);
\r
2315 client.emit('status', message);
\r
2320 function handlePng(message, callback) {
\r
2321 if (message.op === 'png') {
\r
2322 decompressPng(message.data, callback);
\r
2324 callback(message);
\r
2328 function decodeBSON(data, callback) {
\r
2330 throw 'Cannot process BSON encoded message without BSON header.';
\r
2332 var reader = new FileReader();
\r
2333 reader.onload = function() {
\r
2334 var uint8Array = new Uint8Array(this.result);
\r
2335 var msg = BSON.deserialize(uint8Array);
\r
2338 reader.readAsArrayBuffer(data);
\r
2343 * Emits a 'connection' event on WebSocket connection.
\r
2345 * @param event - the argument to emit with the event.
\r
2346 * @memberof SocketAdapter
\r
2348 onopen: function onOpen(event) {
\r
2349 client.isConnected = true;
\r
2350 client.emit('connection', event);
\r
2354 * Emits a 'close' event on WebSocket disconnection.
\r
2356 * @param event - the argument to emit with the event.
\r
2357 * @memberof SocketAdapter
\r
2359 onclose: function onClose(event) {
\r
2360 client.isConnected = false;
\r
2361 client.emit('close', event);
\r
2365 * Emits an 'error' event whenever there was an error.
\r
2367 * @param event - the argument to emit with the event.
\r
2368 * @memberof SocketAdapter
\r
2370 onerror: function onError(event) {
\r
2371 client.emit('error', event);
\r
2375 * Parses message responses from rosbridge and sends to the appropriate
\r
2376 * topic, service, or param.
\r
2378 * @param message - the raw JSON message from rosbridge.
\r
2379 * @memberof SocketAdapter
\r
2381 onmessage: function onMessage(data) {
\r
2382 if (typeof Blob !== 'undefined' && data.data instanceof Blob) {
\r
2383 decodeBSON(data.data, function (message) {
\r
2384 handlePng(message, handleMessage);
\r
2387 var message = JSON.parse(typeof data === 'string' ? data : data.data);
\r
2388 handlePng(message, handleMessage);
\r
2394 module.exports = SocketAdapter;
\r
2396 },{"../util/decompressPng":41,"ws":39}],17:[function(require,module,exports){
\r
2399 * @author Brandon Alexander - baalexander@gmail.com
\r
2402 var EventEmitter2 = require('eventemitter2').EventEmitter2;
\r
2403 var Message = require('./Message');
\r
2406 * Publish and/or subscribe to a topic in ROS.
\r
2408 * Emits the following events:
\r
2409 * * 'warning' - if there are any warning during the Topic creation
\r
2410 * * 'message' - the message data from rosbridge
\r
2413 * @param options - object with following keys:
\r
2414 * * ros - the ROSLIB.Ros connection handle
\r
2415 * * name - the topic name, like /cmd_vel
\r
2416 * * messageType - the message type, like 'std_msgs/String'
\r
2417 * * compression - the type of compression to use, like 'png'
\r
2418 * * throttle_rate - the rate (in ms in between messages) at which to throttle the topics
\r
2419 * * queue_size - the queue created at bridge side for re-publishing webtopics (defaults to 100)
\r
2420 * * latch - latch the topic when publishing
\r
2421 * * queue_length - the queue length at bridge side used when subscribing (defaults to 0, no queueing).
\r
2422 * * reconnect_on_close - the flag to enable resubscription and readvertisement on close event(defaults to true).
\r
2424 function Topic(options) {
\r
2425 options = options || {};
\r
2426 this.ros = options.ros;
\r
2427 this.name = options.name;
\r
2428 this.messageType = options.messageType;
\r
2429 this.isAdvertised = false;
\r
2430 this.compression = options.compression || 'none';
\r
2431 this.throttle_rate = options.throttle_rate || 0;
\r
2432 this.latch = options.latch || false;
\r
2433 this.queue_size = options.queue_size || 100;
\r
2434 this.queue_length = options.queue_length || 0;
\r
2435 this.reconnect_on_close = options.reconnect_on_close || true;
\r
2437 // Check for valid compression types
\r
2438 if (this.compression && this.compression !== 'png' &&
\r
2439 this.compression !== 'none') {
\r
2440 this.emit('warning', this.compression +
\r
2441 ' compression is not supported. No compression will be used.');
\r
2444 // Check if throttle rate is negative
\r
2445 if (this.throttle_rate < 0) {
\r
2446 this.emit('warning', this.throttle_rate + ' is not allowed. Set to 0');
\r
2447 this.throttle_rate = 0;
\r
2451 if (this.reconnect_on_close) {
\r
2452 this.callForSubscribeAndAdvertise = function(message) {
\r
2453 that.ros.callOnConnection(message);
\r
2455 that.waitForReconnect = false;
\r
2456 that.reconnectFunc = function() {
\r
2457 if(!that.waitForReconnect) {
\r
2458 that.waitForReconnect = true;
\r
2459 that.ros.callOnConnection(message);
\r
2460 that.ros.once('connection', function() {
\r
2461 that.waitForReconnect = false;
\r
2465 that.ros.on('close', that.reconnectFunc);
\r
2469 this.callForSubscribeAndAdvertise = this.ros.callOnConnection;
\r
2472 this._messageCallback = function(data) {
\r
2473 that.emit('message', new Message(data));
\r
2476 Topic.prototype.__proto__ = EventEmitter2.prototype;
\r
2479 * Every time a message is published for the given topic, the callback
\r
2480 * will be called with the message object.
\r
2482 * @param callback - function with the following params:
\r
2483 * * message - the published message
\r
2485 Topic.prototype.subscribe = function(callback) {
\r
2486 if (typeof callback === 'function') {
\r
2487 this.on('message', callback);
\r
2490 if (this.subscribeId) { return; }
\r
2491 this.ros.on(this.name, this._messageCallback);
\r
2492 this.subscribeId = 'subscribe:' + this.name + ':' + (++this.ros.idCounter);
\r
2494 this.callForSubscribeAndAdvertise({
\r
2496 id: this.subscribeId,
\r
2497 type: this.messageType,
\r
2499 compression: this.compression,
\r
2500 throttle_rate: this.throttle_rate,
\r
2501 queue_length: this.queue_length
\r
2506 * Unregisters as a subscriber for the topic. Unsubscribing stop remove
\r
2507 * all subscribe callbacks. To remove a call back, you must explicitly
\r
2508 * pass the callback function in.
\r
2510 * @param callback - the optional callback to unregister, if
\r
2511 * * provided and other listeners are registered the topic won't
\r
2512 * * unsubscribe, just stop emitting to the passed listener
\r
2514 Topic.prototype.unsubscribe = function(callback) {
\r
2516 this.off('message', callback);
\r
2517 // If there is any other callbacks still subscribed don't unsubscribe
\r
2518 if (this.listeners('message').length) { return; }
\r
2520 if (!this.subscribeId) { return; }
\r
2521 // Note: Don't call this.removeAllListeners, allow client to handle that themselves
\r
2522 this.ros.off(this.name, this._messageCallback);
\r
2523 if(this.reconnect_on_close) {
\r
2524 this.ros.off('close', this.reconnectFunc);
\r
2526 this.emit('unsubscribe');
\r
2527 this.ros.callOnConnection({
\r
2528 op: 'unsubscribe',
\r
2529 id: this.subscribeId,
\r
2532 this.subscribeId = null;
\r
2537 * Registers as a publisher for the topic.
\r
2539 Topic.prototype.advertise = function() {
\r
2540 if (this.isAdvertised) {
\r
2543 this.advertiseId = 'advertise:' + this.name + ':' + (++this.ros.idCounter);
\r
2544 this.callForSubscribeAndAdvertise({
\r
2546 id: this.advertiseId,
\r
2547 type: this.messageType,
\r
2549 latch: this.latch,
\r
2550 queue_size: this.queue_size
\r
2552 this.isAdvertised = true;
\r
2554 if(!this.reconnect_on_close) {
\r
2556 this.ros.on('close', function() {
\r
2557 that.isAdvertised = false;
\r
2563 * Unregisters as a publisher for the topic.
\r
2565 Topic.prototype.unadvertise = function() {
\r
2566 if (!this.isAdvertised) {
\r
2569 if(this.reconnect_on_close) {
\r
2570 this.ros.off('close', this.reconnectFunc);
\r
2572 this.emit('unadvertise');
\r
2573 this.ros.callOnConnection({
\r
2574 op: 'unadvertise',
\r
2575 id: this.advertiseId,
\r
2578 this.isAdvertised = false;
\r
2582 * Publish the message.
\r
2584 * @param message - A ROSLIB.Message object.
\r
2586 Topic.prototype.publish = function(message) {
\r
2587 if (!this.isAdvertised) {
\r
2591 this.ros.idCounter++;
\r
2594 id: 'publish:' + this.name + ':' + this.ros.idCounter,
\r
2599 this.ros.callOnConnection(call);
\r
2602 module.exports = Topic;
\r
2604 },{"./Message":10,"eventemitter2":1}],18:[function(require,module,exports){
\r
2605 var mixin = require('../mixin');
\r
2607 var core = module.exports = {
\r
2608 Ros: require('./Ros'),
\r
2609 Topic: require('./Topic'),
\r
2610 Message: require('./Message'),
\r
2611 Param: require('./Param'),
\r
2612 Service: require('./Service'),
\r
2613 ServiceRequest: require('./ServiceRequest'),
\r
2614 ServiceResponse: require('./ServiceResponse')
\r
2617 mixin(core.Ros, ['Param', 'Service', 'Topic'], core);
\r
2619 },{"../mixin":24,"./Message":10,"./Param":11,"./Ros":12,"./Service":13,"./ServiceRequest":14,"./ServiceResponse":15,"./Topic":17}],19:[function(require,module,exports){
\r
2622 * @author David Gossow - dgossow@willowgarage.com
\r
2625 var Vector3 = require('./Vector3');
\r
2626 var Quaternion = require('./Quaternion');
\r
2629 * A Pose in 3D space. Values are copied into this object.
\r
2632 * @param options - object with following keys:
\r
2633 * * position - the Vector3 describing the position
\r
2634 * * orientation - the ROSLIB.Quaternion describing the orientation
\r
2636 function Pose(options) {
\r
2637 options = options || {};
\r
2638 // copy the values into this object if they exist
\r
2639 this.position = new Vector3(options.position);
\r
2640 this.orientation = new Quaternion(options.orientation);
\r
2644 * Apply a transform against this pose.
\r
2646 * @param tf the transform
\r
2648 Pose.prototype.applyTransform = function(tf) {
\r
2649 this.position.multiplyQuaternion(tf.rotation);
\r
2650 this.position.add(tf.translation);
\r
2651 var tmp = tf.rotation.clone();
\r
2652 tmp.multiply(this.orientation);
\r
2653 this.orientation = tmp;
\r
2657 * Clone a copy of this pose.
\r
2659 * @returns the cloned pose
\r
2661 Pose.prototype.clone = function() {
\r
2662 return new Pose(this);
\r
2665 module.exports = Pose;
\r
2666 },{"./Quaternion":20,"./Vector3":22}],20:[function(require,module,exports){
\r
2669 * @author David Gossow - dgossow@willowgarage.com
\r
2676 * @param options - object with following keys:
\r
2677 * * x - the x value
\r
2678 * * y - the y value
\r
2679 * * z - the z value
\r
2680 * * w - the w value
\r
2682 function Quaternion(options) {
\r
2683 options = options || {};
\r
2684 this.x = options.x || 0;
\r
2685 this.y = options.y || 0;
\r
2686 this.z = options.z || 0;
\r
2687 this.w = (typeof options.w === 'number') ? options.w : 1;
\r
2691 * Perform a conjugation on this quaternion.
\r
2693 Quaternion.prototype.conjugate = function() {
\r
2700 * Return the norm of this quaternion.
\r
2702 Quaternion.prototype.norm = function() {
\r
2703 return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
\r
2707 * Perform a normalization on this quaternion.
\r
2709 Quaternion.prototype.normalize = function() {
\r
2710 var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
\r
2718 this.x = this.x * l;
\r
2719 this.y = this.y * l;
\r
2720 this.z = this.z * l;
\r
2721 this.w = this.w * l;
\r
2726 * Convert this quaternion into its inverse.
\r
2728 Quaternion.prototype.invert = function() {
\r
2734 * Set the values of this quaternion to the product of itself and the given quaternion.
\r
2736 * @param q the quaternion to multiply with
\r
2738 Quaternion.prototype.multiply = function(q) {
\r
2739 var newX = this.x * q.w + this.y * q.z - this.z * q.y + this.w * q.x;
\r
2740 var newY = -this.x * q.z + this.y * q.w + this.z * q.x + this.w * q.y;
\r
2741 var newZ = this.x * q.y - this.y * q.x + this.z * q.w + this.w * q.z;
\r
2742 var newW = -this.x * q.x - this.y * q.y - this.z * q.z + this.w * q.w;
\r
2750 * Clone a copy of this quaternion.
\r
2752 * @returns the cloned quaternion
\r
2754 Quaternion.prototype.clone = function() {
\r
2755 return new Quaternion(this);
\r
2758 module.exports = Quaternion;
\r
2760 },{}],21:[function(require,module,exports){
\r
2763 * @author David Gossow - dgossow@willowgarage.com
\r
2766 var Vector3 = require('./Vector3');
\r
2767 var Quaternion = require('./Quaternion');
\r
2770 * A Transform in 3-space. Values are copied into this object.
\r
2773 * @param options - object with following keys:
\r
2774 * * translation - the Vector3 describing the translation
\r
2775 * * rotation - the ROSLIB.Quaternion describing the rotation
\r
2777 function Transform(options) {
\r
2778 options = options || {};
\r
2779 // Copy the values into this object if they exist
\r
2780 this.translation = new Vector3(options.translation);
\r
2781 this.rotation = new Quaternion(options.rotation);
\r
2785 * Clone a copy of this transform.
\r
2787 * @returns the cloned transform
\r
2789 Transform.prototype.clone = function() {
\r
2790 return new Transform(this);
\r
2793 module.exports = Transform;
\r
2794 },{"./Quaternion":20,"./Vector3":22}],22:[function(require,module,exports){
\r
2797 * @author David Gossow - dgossow@willowgarage.com
\r
2804 * @param options - object with following keys:
\r
2805 * * x - the x value
\r
2806 * * y - the y value
\r
2807 * * z - the z value
\r
2809 function Vector3(options) {
\r
2810 options = options || {};
\r
2811 this.x = options.x || 0;
\r
2812 this.y = options.y || 0;
\r
2813 this.z = options.z || 0;
\r
2817 * Set the values of this vector to the sum of itself and the given vector.
\r
2819 * @param v the vector to add with
\r
2821 Vector3.prototype.add = function(v) {
\r
2828 * Set the values of this vector to the difference of itself and the given vector.
\r
2830 * @param v the vector to subtract with
\r
2832 Vector3.prototype.subtract = function(v) {
\r
2839 * Multiply the given Quaternion with this vector.
\r
2841 * @param q - the quaternion to multiply with
\r
2843 Vector3.prototype.multiplyQuaternion = function(q) {
\r
2844 var ix = q.w * this.x + q.y * this.z - q.z * this.y;
\r
2845 var iy = q.w * this.y + q.z * this.x - q.x * this.z;
\r
2846 var iz = q.w * this.z + q.x * this.y - q.y * this.x;
\r
2847 var iw = -q.x * this.x - q.y * this.y - q.z * this.z;
\r
2848 this.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;
\r
2849 this.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;
\r
2850 this.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;
\r
2854 * Clone a copy of this vector.
\r
2856 * @returns the cloned vector
\r
2858 Vector3.prototype.clone = function() {
\r
2859 return new Vector3(this);
\r
2862 module.exports = Vector3;
\r
2863 },{}],23:[function(require,module,exports){
\r
2864 module.exports = {
\r
2865 Pose: require('./Pose'),
\r
2866 Quaternion: require('./Quaternion'),
\r
2867 Transform: require('./Transform'),
\r
2868 Vector3: require('./Vector3')
\r
2871 },{"./Pose":19,"./Quaternion":20,"./Transform":21,"./Vector3":22}],24:[function(require,module,exports){
\r
2873 * Mixin a feature to the core/Ros prototype.
\r
2874 * For example, mixin(Ros, ['Topic'], {Topic: <Topic>})
\r
2875 * will add a topic bound to any Ros instances so a user
\r
2876 * can call `var topic = ros.Topic({name: '/foo'});`
\r
2878 * @author Graeme Yeates - github.com/megawac
\r
2880 module.exports = function(Ros, classes, features) {
\r
2881 classes.forEach(function(className) {
\r
2882 var Class = features[className];
\r
2883 Ros.prototype[className] = function(options) {
\r
2884 options.ros = this;
\r
2885 return new Class(options);
\r
2890 },{}],25:[function(require,module,exports){
\r
2893 * @author David Gossow - dgossow@willowgarage.com
\r
2896 var ActionClient = require('../actionlib/ActionClient');
\r
2897 var Goal = require('../actionlib/Goal');
\r
2899 var Service = require('../core/Service.js');
\r
2900 var ServiceRequest = require('../core/ServiceRequest.js');
\r
2902 var Transform = require('../math/Transform');
\r
2905 * A TF Client that listens to TFs from tf2_web_republisher.
\r
2908 * @param options - object with following keys:
\r
2909 * * ros - the ROSLIB.Ros connection handle
\r
2910 * * fixedFrame - the fixed frame, like /base_link
\r
2911 * * angularThres - the angular threshold for the TF republisher
\r
2912 * * transThres - the translation threshold for the TF republisher
\r
2913 * * rate - the rate for the TF republisher
\r
2914 * * updateDelay - the time (in ms) to wait after a new subscription
\r
2915 * to update the TF republisher's list of TFs
\r
2916 * * topicTimeout - the timeout parameter for the TF republisher
\r
2917 * * serverName (optional) - the name of the tf2_web_republisher server
\r
2918 * * repubServiceName (optional) - the name of the republish_tfs service (non groovy compatibility mode only)
\r
2919 * default: '/republish_tfs'
\r
2921 function TFClient(options) {
\r
2922 options = options || {};
\r
2923 this.ros = options.ros;
\r
2924 this.fixedFrame = options.fixedFrame || '/base_link';
\r
2925 this.angularThres = options.angularThres || 2.0;
\r
2926 this.transThres = options.transThres || 0.01;
\r
2927 this.rate = options.rate || 10.0;
\r
2928 this.updateDelay = options.updateDelay || 50;
\r
2929 var seconds = options.topicTimeout || 2.0;
\r
2930 var secs = Math.floor(seconds);
\r
2931 var nsecs = Math.floor((seconds - secs) * 1000000000);
\r
2932 this.topicTimeout = {
\r
2936 this.serverName = options.serverName || '/tf2_web_republisher';
\r
2937 this.repubServiceName = options.repubServiceName || '/republish_tfs';
\r
2939 this.currentGoal = false;
\r
2940 this.currentTopic = false;
\r
2941 this.frameInfos = {};
\r
2942 this.republisherUpdateRequested = false;
\r
2944 // Create an Action client
\r
2945 this.actionClient = this.ros.ActionClient({
\r
2946 serverName : this.serverName,
\r
2947 actionName : 'tf2_web_republisher/TFSubscriptionAction',
\r
2948 omitStatus : true,
\r
2952 // Create a Service client
\r
2953 this.serviceClient = this.ros.Service({
\r
2954 name: this.repubServiceName,
\r
2955 serviceType: 'tf2_web_republisher/RepublishTFs'
\r
2960 * Process the incoming TF message and send them out using the callback
\r
2963 * @param tf - the TF message from the server
\r
2965 TFClient.prototype.processTFArray = function(tf) {
\r
2967 tf.transforms.forEach(function(transform) {
\r
2968 var frameID = transform.child_frame_id;
\r
2969 if (frameID[0] === '/')
\r
2971 frameID = frameID.substring(1);
\r
2973 var info = this.frameInfos[frameID];
\r
2975 info.transform = new Transform({
\r
2976 translation : transform.transform.translation,
\r
2977 rotation : transform.transform.rotation
\r
2979 info.cbs.forEach(function(cb) {
\r
2980 cb(info.transform);
\r
2987 * Create and send a new goal (or service request) to the tf2_web_republisher
\r
2988 * based on the current list of TFs.
\r
2990 TFClient.prototype.updateGoal = function() {
\r
2991 var goalMessage = {
\r
2992 source_frames : Object.keys(this.frameInfos),
\r
2993 target_frame : this.fixedFrame,
\r
2994 angular_thres : this.angularThres,
\r
2995 trans_thres : this.transThres,
\r
2999 // if we're running in groovy compatibility mode (the default)
\r
3000 // then use the action interface to tf2_web_republisher
\r
3001 if(this.ros.groovyCompatibility) {
\r
3002 if (this.currentGoal) {
\r
3003 this.currentGoal.cancel();
\r
3005 this.currentGoal = new Goal({
\r
3006 actionClient : this.actionClient,
\r
3007 goalMessage : goalMessage
\r
3010 this.currentGoal.on('feedback', this.processTFArray.bind(this));
\r
3011 this.currentGoal.send();
\r
3014 // otherwise, use the service interface
\r
3015 // The service interface has the same parameters as the action,
\r
3016 // plus the timeout
\r
3017 goalMessage.timeout = this.topicTimeout;
\r
3018 var request = new ServiceRequest(goalMessage);
\r
3020 this.serviceClient.callService(request, this.processResponse.bind(this));
\r
3023 this.republisherUpdateRequested = false;
\r
3027 * Process the service response and subscribe to the tf republisher
\r
3030 * @param response the service response containing the topic name
\r
3032 TFClient.prototype.processResponse = function(response) {
\r
3033 // if we subscribed to a topic before, unsubscribe so
\r
3034 // the republisher stops publishing it
\r
3035 if (this.currentTopic) {
\r
3036 this.currentTopic.unsubscribe();
\r
3039 this.currentTopic = this.ros.Topic({
\r
3040 name: response.topic_name,
\r
3041 messageType: 'tf2_web_republisher/TFArray'
\r
3043 this.currentTopic.subscribe(this.processTFArray.bind(this));
\r
3047 * Subscribe to the given TF frame.
\r
3049 * @param frameID - the TF frame to subscribe to
\r
3050 * @param callback - function with params:
\r
3051 * * transform - the transform data
\r
3053 TFClient.prototype.subscribe = function(frameID, callback) {
\r
3054 // remove leading slash, if it's there
\r
3055 if (frameID[0] === '/')
\r
3057 frameID = frameID.substring(1);
\r
3059 // if there is no callback registered for the given frame, create emtpy callback list
\r
3060 if (!this.frameInfos[frameID]) {
\r
3061 this.frameInfos[frameID] = {
\r
3064 if (!this.republisherUpdateRequested) {
\r
3065 setTimeout(this.updateGoal.bind(this), this.updateDelay);
\r
3066 this.republisherUpdateRequested = true;
\r
3069 // if we already have a transform, call back immediately
\r
3070 else if (this.frameInfos[frameID].transform) {
\r
3071 callback(this.frameInfos[frameID].transform);
\r
3073 this.frameInfos[frameID].cbs.push(callback);
\r
3077 * Unsubscribe from the given TF frame.
\r
3079 * @param frameID - the TF frame to unsubscribe from
\r
3080 * @param callback - the callback function to remove
\r
3082 TFClient.prototype.unsubscribe = function(frameID, callback) {
\r
3083 // remove leading slash, if it's there
\r
3084 if (frameID[0] === '/')
\r
3086 frameID = frameID.substring(1);
\r
3088 var info = this.frameInfos[frameID];
\r
3089 for (var cbs = info && info.cbs || [], idx = cbs.length; idx--;) {
\r
3090 if (cbs[idx] === callback) {
\r
3091 cbs.splice(idx, 1);
\r
3094 if (!callback || cbs.length === 0) {
\r
3095 delete this.frameInfos[frameID];
\r
3100 * Unsubscribe and unadvertise all topics associated with this TFClient.
\r
3102 TFClient.prototype.dispose = function() {
\r
3103 this.actionClient.dispose();
\r
3104 if (this.currentTopic) {
\r
3105 this.currentTopic.unsubscribe();
\r
3109 module.exports = TFClient;
\r
3111 },{"../actionlib/ActionClient":5,"../actionlib/Goal":7,"../core/Service.js":13,"../core/ServiceRequest.js":14,"../math/Transform":21}],26:[function(require,module,exports){
\r
3112 var Ros = require('../core/Ros');
\r
3113 var mixin = require('../mixin');
\r
3115 var tf = module.exports = {
\r
3116 TFClient: require('./TFClient')
\r
3119 mixin(Ros, ['TFClient'], tf);
\r
3120 },{"../core/Ros":12,"../mixin":24,"./TFClient":25}],27:[function(require,module,exports){
\r
3123 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3124 * @author Russell Toris - rctoris@wpi.edu
\r
3127 var Vector3 = require('../math/Vector3');
\r
3128 var UrdfTypes = require('./UrdfTypes');
\r
3131 * A Box element in a URDF.
\r
3134 * @param options - object with following keys:
\r
3135 * * xml - the XML element to parse
\r
3137 function UrdfBox(options) {
\r
3138 this.dimension = null;
\r
3139 this.type = UrdfTypes.URDF_BOX;
\r
3141 // Parse the xml string
\r
3142 var xyz = options.xml.getAttribute('size').split(' ');
\r
3143 this.dimension = new Vector3({
\r
3144 x : parseFloat(xyz[0]),
\r
3145 y : parseFloat(xyz[1]),
\r
3146 z : parseFloat(xyz[2])
\r
3150 module.exports = UrdfBox;
\r
3151 },{"../math/Vector3":22,"./UrdfTypes":36}],28:[function(require,module,exports){
\r
3154 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3155 * @author Russell Toris - rctoris@wpi.edu
\r
3159 * A Color element in a URDF.
\r
3162 * @param options - object with following keys:
\r
3163 * * xml - the XML element to parse
\r
3165 function UrdfColor(options) {
\r
3166 // Parse the xml string
\r
3167 var rgba = options.xml.getAttribute('rgba').split(' ');
\r
3168 this.r = parseFloat(rgba[0]);
\r
3169 this.g = parseFloat(rgba[1]);
\r
3170 this.b = parseFloat(rgba[2]);
\r
3171 this.a = parseFloat(rgba[3]);
\r
3174 module.exports = UrdfColor;
\r
3175 },{}],29:[function(require,module,exports){
\r
3178 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3179 * @author Russell Toris - rctoris@wpi.edu
\r
3182 var UrdfTypes = require('./UrdfTypes');
\r
3185 * A Cylinder element in a URDF.
\r
3188 * @param options - object with following keys:
\r
3189 * * xml - the XML element to parse
\r
3191 function UrdfCylinder(options) {
\r
3192 this.type = UrdfTypes.URDF_CYLINDER;
\r
3193 this.length = parseFloat(options.xml.getAttribute('length'));
\r
3194 this.radius = parseFloat(options.xml.getAttribute('radius'));
\r
3197 module.exports = UrdfCylinder;
\r
3198 },{"./UrdfTypes":36}],30:[function(require,module,exports){
\r
3201 * @author David V. Lu!! davidvlu@gmail.com
\r
3205 * A Joint element in a URDF.
\r
3208 * @param options - object with following keys:
\r
3209 * * xml - the XML element to parse
\r
3211 function UrdfJoint(options) {
\r
3212 this.name = options.xml.getAttribute('name');
\r
3213 this.type = options.xml.getAttribute('type');
\r
3215 var parents = options.xml.getElementsByTagName('parent');
\r
3216 if(parents.length > 0) {
\r
3217 this.parent = parents[0].getAttribute('link');
\r
3220 var children = options.xml.getElementsByTagName('child');
\r
3221 if(children.length > 0) {
\r
3222 this.child = children[0].getAttribute('link');
\r
3225 var limits = options.xml.getElementsByTagName('limit');
\r
3226 if (limits.length > 0) {
\r
3227 this.minval = parseFloat( limits[0].getAttribute('lower') );
\r
3228 this.maxval = parseFloat( limits[0].getAttribute('upper') );
\r
3232 module.exports = UrdfJoint;
\r
3234 },{}],31:[function(require,module,exports){
\r
3237 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3238 * @author Russell Toris - rctoris@wpi.edu
\r
3241 var UrdfVisual = require('./UrdfVisual');
\r
3244 * A Link element in a URDF.
\r
3247 * @param options - object with following keys:
\r
3248 * * xml - the XML element to parse
\r
3250 function UrdfLink(options) {
\r
3251 this.name = options.xml.getAttribute('name');
\r
3252 this.visuals = [];
\r
3253 var visuals = options.xml.getElementsByTagName('visual');
\r
3255 for( var i=0; i<visuals.length; i++ ) {
\r
3256 this.visuals.push( new UrdfVisual({
\r
3262 module.exports = UrdfLink;
\r
3263 },{"./UrdfVisual":37}],32:[function(require,module,exports){
\r
3266 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3267 * @author Russell Toris - rctoris@wpi.edu
\r
3270 var UrdfColor = require('./UrdfColor');
\r
3273 * A Material element in a URDF.
\r
3276 * @param options - object with following keys:
\r
3277 * * xml - the XML element to parse
\r
3279 function UrdfMaterial(options) {
\r
3280 this.textureFilename = null;
\r
3281 this.color = null;
\r
3283 this.name = options.xml.getAttribute('name');
\r
3286 var textures = options.xml.getElementsByTagName('texture');
\r
3287 if (textures.length > 0) {
\r
3288 this.textureFilename = textures[0].getAttribute('filename');
\r
3292 var colors = options.xml.getElementsByTagName('color');
\r
3293 if (colors.length > 0) {
\r
3294 // Parse the RBGA string
\r
3295 this.color = new UrdfColor({
\r
3301 UrdfMaterial.prototype.isLink = function() {
\r
3302 return this.color === null && this.textureFilename === null;
\r
3305 var assign = require('object-assign');
\r
3307 UrdfMaterial.prototype.assign = function(obj) {
\r
3308 return assign(this, obj);
\r
3311 module.exports = UrdfMaterial;
\r
3313 },{"./UrdfColor":28,"object-assign":2}],33:[function(require,module,exports){
\r
3316 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3317 * @author Russell Toris - rctoris@wpi.edu
\r
3320 var Vector3 = require('../math/Vector3');
\r
3321 var UrdfTypes = require('./UrdfTypes');
\r
3324 * A Mesh element in a URDF.
\r
3327 * @param options - object with following keys:
\r
3328 * * xml - the XML element to parse
\r
3330 function UrdfMesh(options) {
\r
3331 this.scale = null;
\r
3333 this.type = UrdfTypes.URDF_MESH;
\r
3334 this.filename = options.xml.getAttribute('filename');
\r
3336 // Check for a scale
\r
3337 var scale = options.xml.getAttribute('scale');
\r
3340 var xyz = scale.split(' ');
\r
3341 this.scale = new Vector3({
\r
3342 x : parseFloat(xyz[0]),
\r
3343 y : parseFloat(xyz[1]),
\r
3344 z : parseFloat(xyz[2])
\r
3349 module.exports = UrdfMesh;
\r
3350 },{"../math/Vector3":22,"./UrdfTypes":36}],34:[function(require,module,exports){
\r
3353 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3354 * @author Russell Toris - rctoris@wpi.edu
\r
3357 var UrdfMaterial = require('./UrdfMaterial');
\r
3358 var UrdfLink = require('./UrdfLink');
\r
3359 var UrdfJoint = require('./UrdfJoint');
\r
3360 var DOMParser = require('xmldom').DOMParser;
\r
3362 // See https://developer.mozilla.org/docs/XPathResult#Constants
\r
3363 var XPATH_FIRST_ORDERED_NODE_TYPE = 9;
\r
3366 * A URDF Model can be used to parse a given URDF into the appropriate elements.
\r
3369 * @param options - object with following keys:
\r
3370 * * xml - the XML element to parse
\r
3371 * * string - the XML element to parse as a string
\r
3373 function UrdfModel(options) {
\r
3374 options = options || {};
\r
3375 var xmlDoc = options.xml;
\r
3376 var string = options.string;
\r
3377 this.materials = {};
\r
3381 // Check if we are using a string or an XML element
\r
3383 // Parse the string
\r
3384 var parser = new DOMParser();
\r
3385 xmlDoc = parser.parseFromString(string, 'text/xml');
\r
3388 // Initialize the model with the given XML node.
\r
3389 // Get the robot tag
\r
3390 var robotXml = xmlDoc.documentElement;
\r
3392 // Get the robot name
\r
3393 this.name = robotXml.getAttribute('name');
\r
3395 // Parse all the visual elements we need
\r
3396 for (var nodes = robotXml.childNodes, i = 0; i < nodes.length; i++) {
\r
3397 var node = nodes[i];
\r
3398 if (node.tagName === 'material') {
\r
3399 var material = new UrdfMaterial({
\r
3402 // Make sure this is unique
\r
3403 if (this.materials[material.name] !== void 0) {
\r
3404 if( this.materials[material.name].isLink() ) {
\r
3405 this.materials[material.name].assign( material );
\r
3407 console.warn('Material ' + material.name + 'is not unique.');
\r
3410 this.materials[material.name] = material;
\r
3412 } else if (node.tagName === 'link') {
\r
3413 var link = new UrdfLink({
\r
3416 // Make sure this is unique
\r
3417 if (this.links[link.name] !== void 0) {
\r
3418 console.warn('Link ' + link.name + ' is not unique.');
\r
3420 // Check for a material
\r
3421 for( var j=0; j<link.visuals.length; j++ )
\r
3423 var mat = link.visuals[j].material;
\r
3424 if ( mat !== null ) {
\r
3425 if (this.materials[mat.name] !== void 0) {
\r
3426 link.visuals[j].material = this.materials[mat.name];
\r
3428 this.materials[mat.name] = mat;
\r
3434 this.links[link.name] = link;
\r
3436 } else if (node.tagName === 'joint') {
\r
3437 var joint = new UrdfJoint({
\r
3440 this.joints[joint.name] = joint;
\r
3445 module.exports = UrdfModel;
\r
3447 },{"./UrdfJoint":30,"./UrdfLink":31,"./UrdfMaterial":32,"xmldom":42}],35:[function(require,module,exports){
\r
3450 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3451 * @author Russell Toris - rctoris@wpi.edu
\r
3454 var UrdfTypes = require('./UrdfTypes');
\r
3457 * A Sphere element in a URDF.
\r
3460 * @param options - object with following keys:
\r
3461 * * xml - the XML element to parse
\r
3463 function UrdfSphere(options) {
\r
3464 this.type = UrdfTypes.URDF_SPHERE;
\r
3465 this.radius = parseFloat(options.xml.getAttribute('radius'));
\r
3468 module.exports = UrdfSphere;
\r
3469 },{"./UrdfTypes":36}],36:[function(require,module,exports){
\r
3470 module.exports = {
\r
3473 URDF_CYLINDER : 2,
\r
3477 },{}],37:[function(require,module,exports){
\r
3480 * @author Benjamin Pitzer - ben.pitzer@gmail.com
\r
3481 * @author Russell Toris - rctoris@wpi.edu
\r
3484 var Pose = require('../math/Pose');
\r
3485 var Vector3 = require('../math/Vector3');
\r
3486 var Quaternion = require('../math/Quaternion');
\r
3488 var UrdfCylinder = require('./UrdfCylinder');
\r
3489 var UrdfBox = require('./UrdfBox');
\r
3490 var UrdfMaterial = require('./UrdfMaterial');
\r
3491 var UrdfMesh = require('./UrdfMesh');
\r
3492 var UrdfSphere = require('./UrdfSphere');
\r
3495 * A Visual element in a URDF.
\r
3498 * @param options - object with following keys:
\r
3499 * * xml - the XML element to parse
\r
3501 function UrdfVisual(options) {
\r
3502 var xml = options.xml;
\r
3503 this.origin = null;
\r
3504 this.geometry = null;
\r
3505 this.material = null;
\r
3508 var origins = xml.getElementsByTagName('origin');
\r
3509 if (origins.length === 0) {
\r
3510 // use the identity as the default
\r
3511 this.origin = new Pose();
\r
3514 var xyz = origins[0].getAttribute('xyz');
\r
3515 var position = new Vector3();
\r
3517 xyz = xyz.split(' ');
\r
3518 position = new Vector3({
\r
3519 x : parseFloat(xyz[0]),
\r
3520 y : parseFloat(xyz[1]),
\r
3521 z : parseFloat(xyz[2])
\r
3526 var rpy = origins[0].getAttribute('rpy');
\r
3527 var orientation = new Quaternion();
\r
3529 rpy = rpy.split(' ');
\r
3530 // Convert from RPY
\r
3531 var roll = parseFloat(rpy[0]);
\r
3532 var pitch = parseFloat(rpy[1]);
\r
3533 var yaw = parseFloat(rpy[2]);
\r
3534 var phi = roll / 2.0;
\r
3535 var the = pitch / 2.0;
\r
3536 var psi = yaw / 2.0;
\r
3537 var x = Math.sin(phi) * Math.cos(the) * Math.cos(psi) - Math.cos(phi) * Math.sin(the)
\r
3539 var y = Math.cos(phi) * Math.sin(the) * Math.cos(psi) + Math.sin(phi) * Math.cos(the)
\r
3541 var z = Math.cos(phi) * Math.cos(the) * Math.sin(psi) - Math.sin(phi) * Math.sin(the)
\r
3543 var w = Math.cos(phi) * Math.cos(the) * Math.cos(psi) + Math.sin(phi) * Math.sin(the)
\r
3546 orientation = new Quaternion({
\r
3552 orientation.normalize();
\r
3554 this.origin = new Pose({
\r
3555 position : position,
\r
3556 orientation : orientation
\r
3561 var geoms = xml.getElementsByTagName('geometry');
\r
3562 if (geoms.length > 0) {
\r
3563 var geom = geoms[0];
\r
3565 // Check for the shape
\r
3566 for (var i = 0; i < geom.childNodes.length; i++) {
\r
3567 var node = geom.childNodes[i];
\r
3568 if (node.nodeType === 1) {
\r
3574 var type = shape.nodeName;
\r
3575 if (type === 'sphere') {
\r
3576 this.geometry = new UrdfSphere({
\r
3579 } else if (type === 'box') {
\r
3580 this.geometry = new UrdfBox({
\r
3583 } else if (type === 'cylinder') {
\r
3584 this.geometry = new UrdfCylinder({
\r
3587 } else if (type === 'mesh') {
\r
3588 this.geometry = new UrdfMesh({
\r
3592 console.warn('Unknown geometry type ' + type);
\r
3597 var materials = xml.getElementsByTagName('material');
\r
3598 if (materials.length > 0) {
\r
3599 this.material = new UrdfMaterial({
\r
3600 xml : materials[0]
\r
3605 module.exports = UrdfVisual;
\r
3606 },{"../math/Pose":19,"../math/Quaternion":20,"../math/Vector3":22,"./UrdfBox":27,"./UrdfCylinder":29,"./UrdfMaterial":32,"./UrdfMesh":33,"./UrdfSphere":35}],38:[function(require,module,exports){
\r
3607 module.exports = require('object-assign')({
\r
3608 UrdfBox: require('./UrdfBox'),
\r
3609 UrdfColor: require('./UrdfColor'),
\r
3610 UrdfCylinder: require('./UrdfCylinder'),
\r
3611 UrdfLink: require('./UrdfLink'),
\r
3612 UrdfMaterial: require('./UrdfMaterial'),
\r
3613 UrdfMesh: require('./UrdfMesh'),
\r
3614 UrdfModel: require('./UrdfModel'),
\r
3615 UrdfSphere: require('./UrdfSphere'),
\r
3616 UrdfVisual: require('./UrdfVisual')
\r
3617 }, require('./UrdfTypes'));
\r
3619 },{"./UrdfBox":27,"./UrdfColor":28,"./UrdfCylinder":29,"./UrdfLink":31,"./UrdfMaterial":32,"./UrdfMesh":33,"./UrdfModel":34,"./UrdfSphere":35,"./UrdfTypes":36,"./UrdfVisual":37,"object-assign":2}],39:[function(require,module,exports){
\r
3620 (function (global){
\r
3621 module.exports = global.WebSocket;
\r
3622 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
\r
3623 },{}],40:[function(require,module,exports){
\r
3624 /* global document */
\r
3625 module.exports = function Canvas() {
\r
3626 return document.createElement('canvas');
\r
3628 },{}],41:[function(require,module,exports){
\r
3629 (function (global){
\r
3632 * @author Graeme Yeates - github.com/megawac
\r
3637 var Canvas = require('canvas');
\r
3638 var Image = Canvas.Image || global.Image;
\r
3641 * If a message was compressed as a PNG image (a compression hack since
\r
3642 * gzipping over WebSockets * is not supported yet), this function places the
\r
3643 * "image" in a canvas element then decodes the * "image" as a Base64 string.
\r
3646 * @param data - object containing the PNG data.
\r
3647 * @param callback - function with params:
\r
3648 * * data - the uncompressed data
\r
3650 function decompressPng(data, callback) {
\r
3651 // Uncompresses the data before sending it through (use image/canvas to do so).
\r
3652 var image = new Image();
\r
3653 image.crossOrigin = "Anonymous";
\r
3654 // When the image loads, extracts the raw data (JSON message).
\r
3655 image.onload = function() {
\r
3656 // Creates a local canvas to draw on.
\r
3657 var canvas = new Canvas();
\r
3658 var context = canvas.getContext('2d');
\r
3660 // Sets width and height.
\r
3661 canvas.width = image.width;
\r
3662 canvas.height = image.height;
\r
3664 // Prevents anti-aliasing and loosing data
\r
3665 context.imageSmoothingEnabled = false;
\r
3666 context.webkitImageSmoothingEnabled = false;
\r
3667 context.mozImageSmoothingEnabled = false;
\r
3669 // Puts the data into the image.
\r
3670 context.drawImage(image, 0, 0);
\r
3671 // Grabs the raw, uncompressed data.
\r
3672 var imageData = context.getImageData(0, 0, image.width, image.height).data;
\r
3674 // Constructs the JSON.
\r
3675 var jsonData = '';
\r
3676 for (var i = 0; i < imageData.length; i += 4) {
\r
3678 jsonData += String.fromCharCode(imageData[i], imageData[i + 1], imageData[i + 2]);
\r
3680 callback(JSON.parse(jsonData));
\r
3682 // Sends the image data to load.
\r
3683 image.src = 'data:image/png;base64,' + data;
\r
3686 module.exports = decompressPng;
\r
3687 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
\r
3688 },{"canvas":40}],42:[function(require,module,exports){
\r
3689 (function (global){
\r
3690 exports.DOMImplementation = global.DOMImplementation;
\r
3691 exports.XMLSerializer = global.XMLSerializer;
\r
3692 exports.DOMParser = global.DOMParser;
\r
3693 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
\r