Skip to content

Commit 20be5ed

Browse files
feat: expose rotation axis info in UrdfJoint
1 parent 380b526 commit 20be5ed

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

src/urdf/UrdfJoint.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { UrdfAttrs, type UrdfDefaultOptions } from './UrdfTypes.js';
7-
import { Pose } from '../math/index.js';
7+
import { Pose, Vector3 } from '../math/index.js';
88
import { parseUrdfOrigin } from './UrdfUtils.js';
99
import type { Nullable } from '../types/interface-types.js';
1010

@@ -20,7 +20,11 @@ export default class UrdfJoint {
2020
minval = NaN;
2121
maxval = NaN;
2222
origin: Pose = new Pose();
23-
23+
axis: Vector3 = new Vector3({
24+
x: 1,
25+
y: 0,
26+
z: 0
27+
});
2428

2529
constructor({xml}: UrdfDefaultOptions) {
2630
this.name = xml.getAttribute(UrdfAttrs.Name) ?? 'unknown_name';
@@ -47,5 +51,18 @@ export default class UrdfJoint {
4751
if (origins.length > 0) {
4852
this.origin = parseUrdfOrigin(origins[0]);
4953
}
54+
55+
const axis = xml.getElementsByTagName(UrdfAttrs.Axis);
56+
if (axis.length > 0) {
57+
const xyzValue = axis[0].getAttribute(UrdfAttrs.Xyz)?.split(' ');
58+
if (xyzValue && xyzValue.length === 3) {
59+
const [x, y, z] = xyzValue.map(parseFloat);
60+
this.axis = new Vector3({
61+
x,
62+
y,
63+
z,
64+
});
65+
}
66+
}
5067
}
5168
}

src/urdf/UrdfTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export enum UrdfAttrs {
3030
Geometry = 'geometry',
3131
Material = 'material',
3232
Scale = 'scale',
33+
Axis = 'axis',
3334
}
3435

3536
export interface UrdfDefaultOptions {

test/urdfjoint.test.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { DOMParser } from '@xmldom/xmldom';
3+
import UrdfJoint from '../src/urdf/UrdfJoint';
4+
5+
describe('UrdfJoint', () => {
6+
it('should parse axis correctly from URDF', () => {
7+
const jointWithAxisUrdf = `
8+
<joint name="test_joint" type="revolute">
9+
<parent link="link1"/>
10+
<child link="link2"/>
11+
<axis xyz="0 1 0"/>
12+
</joint>`;
13+
const parser = new DOMParser();
14+
const xml = parser.parseFromString(jointWithAxisUrdf, 'text/xml').documentElement;
15+
const joint = new UrdfJoint({ xml });
16+
expect(joint.axis.x).toBe(0);
17+
expect(joint.axis.y).toBe(1);
18+
expect(joint.axis.z).toBe(0);
19+
});
20+
21+
it('should default axis to (1,0,0) if not present', () => {
22+
const jointNoAxisUrdf = `
23+
<joint name="test_joint" type="revolute">
24+
<parent link="link1"/>
25+
<child link="link2"/>
26+
</joint>
27+
`;
28+
const parser = new DOMParser();
29+
const xml = parser.parseFromString(jointNoAxisUrdf, 'text/xml').documentElement;
30+
const joint = new UrdfJoint({ xml });
31+
expect(joint.axis.x).toBe(1);
32+
expect(joint.axis.y).toBe(0);
33+
expect(joint.axis.z).toBe(0);
34+
});
35+
36+
it('should default axis to (1,0,0) if axis xyz is malformed', () => {
37+
const jointMalformedAxisUrdf = `
38+
<joint name="test_joint" type="revolute">
39+
<parent link="link1"/>
40+
<child link="link2"/>
41+
<axis xyz="malformed data"/>
42+
</joint>
43+
`;
44+
const parser = new DOMParser();
45+
const xml = parser.parseFromString(jointMalformedAxisUrdf, 'text/xml').documentElement;
46+
const joint = new UrdfJoint({ xml });
47+
expect(joint.axis.x).toBe(1);
48+
expect(joint.axis.y).toBe(0);
49+
expect(joint.axis.z).toBe(0);
50+
});
51+
});

0 commit comments

Comments
 (0)