pamoja for TypeScript - v0.2.0
    Preparing search index...

    Module @pamoja/ros2

    Ergonomic facade over the generated ROS 2 binding.

    What makes a topic name legal, what it becomes on the DDS wire, the RIHS type hash that identifies a message definition, and the CDR encoding the payload itself is written in.

    None of it needs a ROS 2 installation. A gateway written in TypeScript can validate a name, derive the DDS topic and the Zenoh key an rmw_zenoh peer subscribes on, and encode a geometry_msgs/msg/Twist with no ROS distribution anywhere near it. Driving a live graph does need one, so that stays in the Rust crate.

    @pamoja/ros2

    ROS 2 names, RIHS01 type hashes, CDR encoding, and rmw_zenoh key assembly, with no ROS 2 installed. One capability of pamoja, one memory-safe Rust core with bindings for TypeScript, Python, and C#.

    read the guide documentation API reference

    npm install @pamoja/ros2
    

    This pulls in @pamoja/native, the compiled engine. npm install pamoja is the whole framework in one package.

    The test that runs in CI, spliced here as it ran.

    From bindings/node/guides/ros2.ts:

    import { EntityKind, name } from '@pamoja/ros2'

    // A name is slash-separated tokens of letters, digits, and underscores. A token may not start
    // with a digit, and a name may not end in a slash, hold an empty token, or double an
    // underscore.
    const camera = '/robot1/camera_left/image_raw'
    if (name.isValid(camera)) {
    console.log(`valid ${camera}`)
    }
    for (const [candidate, why] of [
    ['/2foo', 'a token starts with a digit'],
    ['/cmd_vel/', 'it ends in a slash'],
    ['/robot1//odom', 'it has an empty token'],
    ['/robot1/cmd__vel', 'it doubles an underscore'],
    ]) {
    if (!name.isValid(candidate)) {
    console.log(`invalid ${candidate}, since ${why}`)
    }
    }

    // A name with no leading slash is relative, and one that starts with a tilde is private. Both
    // are valid, and both resolve against the node before they reach the wire, so neither is
    // fully qualified.
    for (const [label, candidate, against] of [
    ['relative', 'cmd_vel', "the node's namespace"],
    ['private', '~/setpoint', "the node's own name"],
    ]) {
    if (name.isValid(candidate) && !name.isFullyQualified(candidate)) {
    console.log(`${label.padEnd(10)}${candidate} is valid, and resolves against ${against} first`)
    }
    }

    // Only a fully qualified name reaches the wire. DDS puts a prefix before it that says what
    // kind of endpoint it is, and a service travels on two topics, each ending in the suffix the
    // middleware appends.
    const published = name.ddsTopic('/robot1/cmd_vel', EntityKind.Topic)
    const asked = name.ddsTopic('/robot1/add_two_ints', EntityKind.ServiceRequest)
    const answered = name.ddsTopic('/robot1/add_two_ints', EntityKind.ServiceResponse)
    console.log(`topic /robot1/cmd_vel travels on ${published}`)
    console.log(`request /robot1/add_two_ints asks on ${asked}`)
    console.log(`reply and answers on ${answered}`)

    // A message type maps to a DDS type name the same way, so both ends agree on what is carried
    // before a byte is exchanged. A name that is not package/namespace/Type maps to nothing
    // rather than to something plausible.
    for (const rosType of ['std_msgs/msg/String', 'example_interfaces/srv/AddTwoInts', 'std_msgs/String']) {
    const carried = name.ddsTypeName(rosType)
    if (carried !== null) {
    console.log(`type ${rosType} is named ${carried}`)
    } else {
    console.log(`malformed ${rosType} is not package/namespace/Type, so it has no DDS type name`)
    }
    }
    Language Package Reference
    Rust pamoja-ros2 reference, docs.rs, install
    TypeScript @pamoja/ros2 reference, install
    Python pamoja-ros2 reference, install
    C# Pamoja.Ros2 reference, install

    MIT

    CdrReader
    CdrWriter
    Ros2Twist
    Ros2Vector3
    EntityKind
    cdr
    EntityKind
    name
    typeHash