Skip to content

Commit e97d67f

Browse files
authored
Add getClock to Node object (#592)
Adds an internal clock to rclnodejs nodes. In addition, this also makes the following changes: - Timer handles will now be children of the clock handle. This matches rclpy's implementation. - Parameter events will use the node's clock instead of creating a new one each time. - Exposes ClockType publicly. Actions will also require use of the node's clock. Fix #None
1 parent d3d5c2f commit e97d67f

File tree

7 files changed

+68
-15
lines changed

7 files changed

+68
-15
lines changed

index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const validator = require('./lib/validator.js');
3131
const Time = require('./lib/time.js');
3232
const TimeSource = require('./lib/time_source.js');
3333
const { Clock, ROSClock } = require('./lib/clock.js');
34+
const ClockType = require('./lib/clock_type.js');
3435
const Duration = require('./lib/duration.js');
3536
const Context = require('./lib/context.js');
3637

@@ -99,6 +100,9 @@ let rcl = {
99100
/** {@link ROSClock} class */
100101
ROSClock: ROSClock,
101102

103+
/** {@link ClockType} enum */
104+
ClockType: ClockType,
105+
102106
/** {@link Duration} class */
103107
Duration: Duration,
104108

lib/clock.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ class Clock {
3232
this._handle = rclnodejs.createClock(this._clockType);
3333
}
3434

35+
/**
36+
* @ignore
37+
*/
38+
get handle() {
39+
return this._handle;
40+
}
41+
3542
/**
3643
* Get ClockType of this Clock object.
3744
* @return {ClockType} Return the type of the clock.

lib/node.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const Publisher = require('./publisher.js');
3232
const QoS = require('./qos.js');
3333
const Service = require('./service.js');
3434
const Subscription = require('./subscription.js');
35+
const TimeSource = require('./time_source.js');
3536
const Timer = require('./timer.js');
3637

3738
const debug = require('debug')('rclnodejs:node');
@@ -91,6 +92,13 @@ class Node {
9192
}
9293
}
9394

95+
// Clock that has support for ROS time.
96+
// Note: parameter overrides and parameter event publisher need to be ready at this point
97+
// to be able to declare 'use_sim_time' if it was not declared yet.
98+
this._clock = new Clock.ROSClock();
99+
this._timeSource = new TimeSource(this);
100+
this._timeSource.attachClock(this._clock);
101+
94102
if (options.startParameterServices) {
95103
this._parameterService = new ParameterService(this);
96104
this._parameterService.start();
@@ -217,9 +225,15 @@ class Node {
217225
* @param {number} period - The number representing period in millisecond.
218226
* @param {function} callback - The callback to be called when timeout.
219227
* @param {Context} context - The context, default is Context.defaultContext().
228+
* @param {Clock} clock - The clock which the timer gets time from.
220229
* @return {Timer} - An instance of Timer.
221230
*/
222-
createTimer(period, callback, context = Context.defaultContext()) {
231+
createTimer(
232+
period,
233+
callback,
234+
context = Context.defaultContext(),
235+
clock = null
236+
) {
223237
if (typeof period !== 'number' || typeof callback !== 'function') {
224238
throw new TypeError('Invalid argument');
225239
}
@@ -237,7 +251,13 @@ class Node {
237251
);
238252
}
239253

240-
let timerHandle = rclnodejs.createTimer(period, context.handle());
254+
const timerClock = clock || this._clock;
255+
256+
let timerHandle = rclnodejs.createTimer(
257+
timerClock.handle,
258+
context.handle(),
259+
period
260+
);
241261
let timer = new Timer(timerHandle, period, callback);
242262
debug('Finish creating timer, period = %d.', period);
243263
this._timers.push(timer);
@@ -458,6 +478,7 @@ class Node {
458478
}
459479

460480
this.handle.release();
481+
this._clock = null;
461482
this._timers = [];
462483
this._publishers = [];
463484
this._subscriptions = [];
@@ -560,6 +581,14 @@ class Node {
560581
return this._logger;
561582
}
562583

584+
/**
585+
* Get the clock used by the node.
586+
* @returns {Clock} - The nodes clock.
587+
*/
588+
getClock() {
589+
return this._clock;
590+
}
591+
563592
/**
564593
* Get the list of published topics discovered by the provided node for the remote node name.
565594
* @param {string} nodeName - The name of the node.
@@ -1036,7 +1065,7 @@ class Node {
10361065
PARAMETER_EVENT_MSG_TYPE
10371066
))();
10381067

1039-
const secondsAndNanos = new Clock.ROSClock().now().secondsAndNanoseconds;
1068+
const secondsAndNanos = this._clock.now().secondsAndNanoseconds;
10401069
parameterEvent.stamp = {
10411070
sec: secondsAndNanos.seconds,
10421071
nanosec: secondsAndNanos.nanoseconds,

src/rcl_bindings.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -329,31 +329,27 @@ NAN_METHOD(TriggerGuardCondition) {
329329
}
330330

331331
NAN_METHOD(CreateTimer) {
332-
int64_t period_ms = Nan::To<int64_t>(info[0]).FromJust();
332+
RclHandle* clock_handle = RclHandle::Unwrap<RclHandle>(
333+
Nan::To<v8::Object>(info[0]).ToLocalChecked());
334+
rcl_clock_t* clock = reinterpret_cast<rcl_clock_t*>(clock_handle->ptr());
333335
RclHandle* context_handle = RclHandle::Unwrap<RclHandle>(
334336
Nan::To<v8::Object>(info[1]).ToLocalChecked());
335337
rcl_context_t* context =
336338
reinterpret_cast<rcl_context_t*>(context_handle->ptr());
339+
int64_t period_ms = Nan::To<int64_t>(info[2]).FromJust();
340+
337341
rcl_timer_t* timer =
338342
reinterpret_cast<rcl_timer_t*>(malloc(sizeof(rcl_timer_t)));
339343
*timer = rcl_get_zero_initialized_timer();
340-
rcl_clock_t* clock =
341-
reinterpret_cast<rcl_clock_t*>(malloc(sizeof(rcl_clock_t)));
342-
rcl_allocator_t allocator = rcl_get_default_allocator();
343-
THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
344-
rcl_clock_init(RCL_STEADY_TIME, clock, &allocator),
345-
rcl_get_error_string().str);
344+
346345
THROW_ERROR_IF_NOT_EQUAL(
347346
RCL_RET_OK,
348347
rcl_timer_init(timer, clock, context, RCL_MS_TO_NS(period_ms), nullptr,
349348
rcl_get_default_allocator()),
350349
rcl_get_error_string().str);
351350

352-
auto js_obj = RclHandle::NewInstance(timer, nullptr, [timer, clock] {
353-
rcl_ret_t ret_clock = rcl_clock_fini(clock);
354-
free(clock);
355-
rcl_ret_t ret_timer = rcl_timer_fini(timer);
356-
return ret_clock || ret_timer;
351+
auto js_obj = RclHandle::NewInstance(timer, clock_handle, [timer] {
352+
return rcl_timer_fini(timer);
357353
});
358354
info.GetReturnValue().Set(js_obj);
359355
}

test/test-node.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,12 @@ describe('rcl node methods testing', function() {
359359
assert.equal(logger.fatal('message fatal'), true);
360360
});
361361

362+
it('node.getClock', function() {
363+
var clock = node.getClock();
364+
assert.ok(clock);
365+
assert.strictEqual(clock.clockType, rclnodejs.ClockType.ROS_TIME);
366+
});
367+
362368
it('node.getNodeNames', function() {
363369
var nodeNames = node.getNodeNames();
364370

test/types/main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ node.namespace();
4848
// $ExpectType Logging
4949
node.getLogger();
5050

51+
// $ExpectType Clock
52+
node.getClock();
53+
5154
// $ExpectType void
5255
rclnodejs.spin(node);
5356

types/node.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// eslint camelcase: ["error", {ignoreImports: true}]
22

3+
import { Clock } from 'rclnodejs';
34
import { Logging } from 'rclnodejs';
45
import { Parameters } from 'rclnodejs';
56
import { rcl_interfaces as rclinterfaces } from 'rclnodejs';
@@ -165,6 +166,13 @@ declare module 'rclnodejs' {
165166
*/
166167
getLogger(): Logging;
167168

169+
/**
170+
* Get the clock used by the node.
171+
*
172+
* @returns The nodes clock.
173+
*/
174+
getClock(): Clock;
175+
168176
/**
169177
* Get the nodeOptions provided through the constructor.
170178
*/

0 commit comments

Comments
 (0)