oxmpl-js 0.6.0

JavaScript/WASM Bindings for the OxMPL Library
Documentation
import oxmpl from 'oxmpl-js';
import { describe, expect, test } from 'vitest';

class CompoundGoal {
  constructor(space, target, radius) {
    this.space = space;
    this.target = target;
    this.radius = radius;
  }
  isSatisfied(state) {
    return this.space.distance(state, this.target) <= this.radius;
  }
  distanceGoal(state) {
    return Math.max(0, this.space.distance(state, this.target) - this.radius);
  }
  sampleGoal() {
    const tRV = this.target.getComponent(0);
    const tSO2 = this.target.getComponent(1);
    const rv = new oxmpl.base.RealVectorState(Array.from(tRV.values));
    const so2 = new oxmpl.base.SO2State(tSO2.value);
    const builder = new oxmpl.base.CompoundStateBuilder();
    builder.addRealVectorState(rv);
    builder.addSO2State(so2);
    return builder.build();
  }
}

describe('RRT Compound Integration Tests', () => {
  test('RRT problem in Compound Space', () => {
    const r2Space = new oxmpl.base.RealVectorStateSpace(2, [-5, 5, -5, 5]);
    const so2Space = new oxmpl.base.SO2StateSpace();
    const spaceBuilder = new oxmpl.base.CompoundStateSpaceBuilder();
    spaceBuilder.addRealVectorStateSpace(r2Space, 1.0);
    spaceBuilder.addSO2StateSpace(so2Space, 0.5);
    const space = spaceBuilder.build();

    const startBuilder = new oxmpl.base.CompoundStateBuilder();
    startBuilder.addRealVectorState(new oxmpl.base.RealVectorState([-2, 0]));
    startBuilder.addSO2State(new oxmpl.base.SO2State(0));
    const startState = startBuilder.build();

    const targetBuilder = new oxmpl.base.CompoundStateBuilder();
    targetBuilder.addRealVectorState(new oxmpl.base.RealVectorState([2, 0]));
    targetBuilder.addSO2State(new oxmpl.base.SO2State(Math.PI));
    const targetState = targetBuilder.build();

    const goalRegion = new CompoundGoal(space, targetState, 0.5);
    const goal = new oxmpl.base.Goal(goalRegion);

    const problemDef = oxmpl.base.ProblemDefinition.fromCompoundState(space, startState, goal);

    const validityCheckerFn = (state) => {
      const r2 = state.getComponent(0);
      const v = Array.from(r2.values);
      if (v[0] >= -0.5 && v[0] <= 0.5 && v[1] >= -2 && v[1] <= 2) return false;
      return true;
    };
    const validityChecker = new oxmpl.base.StateValidityChecker(validityCheckerFn);

    const planner_config = new oxmpl.base.PlannerConfig(0);
    const planner = new oxmpl.geometric.RRT(0.5, 0.1, problemDef, planner_config);
    planner.setup(validityChecker);

    const path = planner.solve(5.0);
    const states = path.getStates();
    expect(states.length).toBeGreaterThan(1);
    expect(space.distance(states[0], startState)).toBeLessThan(1e-9);
    expect(goalRegion.isSatisfied(states[states.length - 1])).toBe(true);
    for (const state of states) {
      expect(validityCheckerFn(state)).toBe(true);
    }
  });
});