Skip to content

Commit 2413715

Browse files
author
Minggang Wang
committed
[rosidl_gen]Support generic multi-dimensional array
This patch enables the feature of generic multi-dimensional array along with two examples, one is publisher and the other is subscription. Please reference https://github.com/ros2/common_interfaces/blob/master/std_msgs/msg/MultiArrayLayout.msg to more information. Besides, we also refactor the message.dot template to make it more reasonable. Fix #108
1 parent 3249daa commit 2413715

File tree

4 files changed

+185
-53
lines changed

4 files changed

+185
-53
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2017 Intel Corporation. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
const rclnodejs = require('../index.js');
18+
19+
rclnodejs.init().then(() => {
20+
let MultiArrayDimension = rclnodejs.require('std_msgs').msg.MultiArrayDimension;
21+
let MultiArrayLayout = rclnodejs.require('std_msgs').msg.MultiArrayLayout;
22+
let Int32MultiArray = rclnodejs.require('std_msgs').msg.Int32MultiArray;
23+
24+
const node = rclnodejs.createNode('publisher_multiarray_node');
25+
const publisher = node.createPublisher(Int32MultiArray, 'Int32MultiArray');
26+
let count = 0;
27+
28+
setInterval(function() {
29+
// Please reference the usage of multi-array at
30+
// https://github.com/ros2/common_interfaces/blob/master/std_msgs/msg/MultiArrayLayout.msg
31+
let heightDimension = new MultiArrayDimension();
32+
heightDimension.label = 'height';
33+
heightDimension.size = 2;
34+
heightDimension.stride = 2 * 3 * 3;
35+
36+
let weightDimension = new MultiArrayDimension();
37+
weightDimension.label = 'weight';
38+
weightDimension.size = 3;
39+
weightDimension.stride = 3 * 3;
40+
41+
let channelDimension = new MultiArrayDimension();
42+
channelDimension.label = 'channel';
43+
channelDimension.size = 3;
44+
channelDimension.stride = 3;
45+
46+
let layout = new MultiArrayLayout();
47+
layout.dim.fill([heightDimension, weightDimension, channelDimension]);
48+
// eslint-disable-next-line
49+
layout.data_offset = 0;
50+
let multiArray = new Int32MultiArray();
51+
multiArray.layout = layout;
52+
multiArray.data = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6];
53+
54+
publisher.publish(multiArray);
55+
console.log(`Publish ${++count} messages.`);
56+
}, 1000);
57+
rclnodejs.spin(node);
58+
}).catch(e => {
59+
console.log(e);
60+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2017 Intel Corporation. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
const rclnodejs = require('../index.js');
18+
19+
rclnodejs.init().then(() => {
20+
let Int32MultiArray = rclnodejs.require('std_msgs').msg.Int32MultiArray;
21+
let node = rclnodejs.createNode('subscription_multiarray_node');
22+
23+
node.createSubscription(Int32MultiArray, 'Int32MultiArray', (multiArray) => {
24+
// Please reference the usage of multi-array at
25+
// https://github.com/ros2/common_interfaces/blob/master/std_msgs/msg/MultiArrayLayout.msg
26+
console.log('Iterate the multi array:');
27+
let dim = multiArray.layout.dim;
28+
let height = dim.data[0].size;
29+
let weight = dim.data[1].size;
30+
let weightStride = dim.data[1].stride;
31+
let channel = dim.data[2].size;
32+
let channelStride = dim.data[2].stride;
33+
// eslint-disable-next-line
34+
let offset = multiArray.layout.data_offset
35+
36+
for (let i = 0; i < height; i++) {
37+
for (let j = 0; j < weight; j++) {
38+
for (let k = 0; k < channel; k++) {
39+
console.log(`multiarray(${i},${j},${k}) = ${multiArray.data[offset + weightStride*i + channelStride*j + k]}`);
40+
}
41+
}
42+
}
43+
});
44+
rclnodejs.spin(node);
45+
}).catch(e => {
46+
console.log(e);
47+
});

rosidl_gen/templates/message.dot

Lines changed: 77 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ class {{=objectWrapper}} {
175175
this.serialize();
176176
}
177177

178+
static createFromRefObject(refObject) {
179+
let self = new {{=objectWrapper}}();
180+
self.copyRefObject(refObject);
181+
return self;
182+
}
183+
178184
static createArray() {
179185
return new {{=arrayWrapper}};
180186
}
@@ -197,32 +203,20 @@ class {{=objectWrapper}} {
197203

198204
serialize() {
199205
{{~ it.spec.fields :field}}
200-
{{? !field.type.isPrimitiveType || field.type.isArray || (field.type.type === 'string' && it.spec.msgName !== 'String')}}
206+
{{? !field.type.isPrimitiveType || field.type.isArray}}
207+
this._wrapperFields.{{=field.name}}.serialize();
208+
this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject;
209+
{{?? field.type.type === 'string' && it.spec.msgName !== 'String'}}
201210
this._refObject.{{=field.name}} = this._wrapperFields.{{=field.name}}.refObject;
202211
{{?}}
203212
{{~}}
204213
}
205214

206215
deserialize() {
207216
{{~ it.spec.fields :field}}
208-
{{? !field.type.isPrimitiveType && !field.type.isArray}}
209-
this._wrapperFields.{{=field.name}}._refObject = this._refObject.{{=field.name}};
210-
this._wrapperFields.{{=field.name}}.deserialize();
211-
{{?? !field.type.isPrimitiveType && field.type.isArray}}
212-
this._wrapperFields.{{=field.name}}._refObject = this._refObject.{{=field.name}};
213-
this._wrapperFields.{{=field.name}}.data.forEach((wrapper, index) => {
214-
wrapper._refObject = this._wrapperFields.{{=field.name}}._refArray[index];
215-
wrapper.deserialize();
216-
});
217-
{{?? field.type.isPrimitiveType && field.type.isArray}}
218-
let {{=field.name}}Primitives = this._refObject.{{=field.name}}.data;
219-
{{=field.name}}Primitives.length = this._refObject.{{=field.name}}.size;
220-
let {{=field.name}}Values = [];
221-
{{=field.name}}Primitives.toArray().forEach(value =>{
222-
{{=field.name}}Values.push(value.data);
223-
});
224-
this._wrapperFields.{{=field.name}}.setWrappers({{=field.name}}Values);
225-
{{?? !field.type.isArray && field.type.type === 'string' && it.spec.msgName !== 'String'}}
217+
{{? !field.type.isPrimitiveType || field.type.isArray}}
218+
this._wrapperFields.{{=field.name}}.copyRefObject(this._refObject.{{=field.name}});
219+
{{?? field.type.type === 'string' && it.spec.msgName !== 'String'}}
226220
this._wrapperFields.{{=field.name}}.data = this._refObject.{{=field.name}}.data;
227221
{{?}}
228222
{{~}}
@@ -237,7 +231,6 @@ class {{=objectWrapper}} {
237231
}
238232

239233
get refObject() {
240-
this.serialize();
241234
return this._refObject;
242235
}
243236

@@ -249,6 +242,8 @@ class {{=objectWrapper}} {
249242
values.push(wrapper.data);
250243
});
251244
return values;
245+
{{?? field.type.isArray && !field.type.isPrimitiveType}}
246+
return this._wrapperFields.{{=field.name}};
252247
{{?? !field.type.isPrimitiveType && !field.type.isArray}}
253248
return this._wrapperFields.{{=field.name}};
254249
{{?? !field.type.isArray && field.type.type === 'string' && it.spec.msgName !== 'String'}}
@@ -260,24 +255,33 @@ class {{=objectWrapper}} {
260255

261256
set {{=field.name}}(value) {
262257
{{? field.type.isArray && field.type.isPrimitiveType}}
263-
this._wrapperFields['{{=field.name}}'].setWrappers(value);
264-
{{?? !field.type.isArray && field.type.isPrimitiveType && field.type.type !== 'string'}}
265-
this._refObject.{{=field.name}} = value;
266-
{{?? it.spec.msgName === 'String'}}
267-
this._refObject.size = value.length;
268-
this._refObject.capacity = value.length + 1;
269-
this._refObject.data = value;
258+
this._wrapperFields['{{=field.name}}'].fill(value);
259+
{{?? field.type.isArray && !field.type.isPrimitiveType}}
260+
this._wrapperFields.{{=field.name}}.copy(value);
261+
{{?? !field.type.isPrimitiveType && !field.type.isArray}}
262+
this._wrapperFields.{{=field.name}}.copy(value);
270263
{{?? !field.type.isArray && field.type.type === 'string' && it.spec.msgName !== 'String'}}
271264
this._wrapperFields.{{=field.name}}.data = value;
272265
{{?? true}}
273-
if (! value instanceof {{=getWrapperNameByType(field.type)}}) {
274-
throw new TypeError('Invalid argument: should provide "{{=getWrapperNameByType(field.type)}}" to ".{{=field.name}}" setter');
275-
}
276-
this._wrapperFields.{{=field.name}}.copy(value);
266+
{{? it.spec.msgName === 'String'}}
267+
this._refObject.size = value.length;
268+
this._refObject.capacity = value.length + 1;
269+
{{?}}
270+
this._refObject.{{=field.name}} = value;
277271
{{?}}
278272
}
279273
{{~}}
280274

275+
copyRefObject(refObject) {
276+
this._refObject = new {{=refObjectType}}(refObject.toObject());
277+
278+
{{~ it.spec.fields :field}}
279+
{{? !field.type.isPrimitiveType || field.type.isArray || (field.type.type === 'string' && it.spec.msgName !== 'String')}}
280+
this._wrapperFields.{{=field.name}}.copyRefObject(this._refObject.{{=field.name}});
281+
{{?}}
282+
{{~}}
283+
}
284+
281285
copy(other) {
282286
this._refObject = new {{=refObjectType}}(other._refObject.toObject());
283287

@@ -293,34 +297,46 @@ class {{=objectWrapper}} {
293297
class {{=arrayWrapper}} {
294298
constructor(size = 0) {
295299
this._resize(size);
296-
this._refObject = new {{=refObjectArrayType}};
297-
this._refObject.size = size;
298-
this._refObject.capacity = size;
299300
}
300301

301302
toRawROS() {
302303
return this._refObject.ref();
303304
}
304305

305-
setWrappers(wrappers) {
306-
this._refArray = new {{=refArrayType}}(wrappers.length);
307-
this._wrappers = [];
308-
309-
wrappers.forEach((value, index) => {
310-
{{? primitiveBaseType.indexOf(it.spec.baseType.type) !== -1}}
306+
fill(values) {
307+
let length = values.length;
308+
this._resize(length);
309+
{{? isPrimitivePackage(it.spec.baseType)}}
310+
values.forEach((value, index) => {
311311
let wrapper = new {{=objectWrapper}}();
312312
wrapper.data = value;
313-
{{??}}
314-
let wrapper = new {{=objectWrapper}}(value);
315-
{{?}}
316-
this._wrappers.push(wrapper);
313+
this._wrappers[index] = wrapper;
314+
});
315+
{{?? !isPrimitivePackage(it.spec.baseType)}}
316+
values.forEach((value, index) => {
317+
this._wrappers[index].copy(value);
318+
});
319+
{{?}}
320+
}
321+
322+
serialize() {
323+
this._wrappers.forEach((wrapper, index) => {
324+
wrapper.serialize();
317325
this._refArray[index] = wrapper.refObject;
318326
});
319-
this._refObject.size = wrappers.length;
320-
this._refObject.capacity = wrappers.length;
327+
this._refObject.size = this._wrappers.length;
328+
this._refObject.capacity = this._wrappers.length;
321329
this._refObject.data = this._refArray.buffer;
322330
}
323331

332+
deserialize(refObject) {
333+
copyRefObject(refObject)
334+
}
335+
336+
get refObject() {
337+
return this._refObject;
338+
}
339+
324340
get data() {
325341
return this._wrappers;
326342
}
@@ -349,9 +365,6 @@ class {{=arrayWrapper}} {
349365
}
350366

351367
get refObject() {
352-
this._wrappers.forEach((wrapper, index) => {
353-
this._refArray[index] = wrapper.refObject;
354-
});
355368
return this._refObject;
356369
}
357370

@@ -360,16 +373,28 @@ class {{=arrayWrapper}} {
360373
throw new RangeError('Invalid argument: should provide a positive number');
361374
return;
362375
}
376+
this._refArray = new {{=refArrayType}}(size);
377+
this._refObject = new {{=refObjectArrayType}}();
378+
this._refObject.size = size;
379+
this._refObject.capacity = size;
363380

364-
this._refArray = new ArrayType({{=refObjectType}});
365-
this._refArray.size = size;
366-
this._refArray.capacity = size;
367381
this._wrappers = new Array();
368382
for (let i = 0; i < size; i++) {
369383
this._wrappers.push(new {{=objectWrapper}}());
370384
}
371385
}
372386

387+
copyRefObject(refObject) {
388+
this._refObject = refObject;
389+
let refObjectArray = this._refObject.data;
390+
refObjectArray.length = this._refObject.size;
391+
this._resize(this._refObject.size);
392+
393+
for (let index = 0; index < this._refObject.size; index++) {
394+
this._wrappers[index].copyRefObject(refObjectArray[index]);
395+
}
396+
}
397+
373398
copy(other) {
374399
if (! other instanceof {{=arrayWrapper}}) {
375400
throw new TypeError('Invalid argument: should provide "{{=arrayWrapper}}".');

test/test-compound-msg-type-check.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ describe('Compound types', function() {
6161
const Byte = rclnodejs.require('std_msgs').msg.Byte;
6262
const ByteArray = Byte.ArrayType;
6363
let msg = new ByteArray(3);
64-
msg.setWrappers([1, 2, 3]);
64+
msg.fill([1, 2, 3]);
6565

6666
assert.deepStrictEqual(msg.data.length, 3);
6767
assert.deepStrictEqual(msg.data[0].data, 1);

0 commit comments

Comments
 (0)