Giter Club home page Giter Club logo

rosmsg's Introduction

@foxglove/rosmsg

ROS1 and ROS2 message definition parser

npm version

Introduction

The Robot Operating System (ROS) defines a simplified message description language for describing data types. This library parses those message definitions and can round trip them back into a canonical string format suitable for checksum generation. The parsed definitions are useful for serialization or deserialization when paired with other libraries.

This library supports both ROS1 and ROS 2 message definitions.

ROS 1 Definition Usage

import { parse, stringify } from "@foxglove/rosmsg";

const definitionStr = `# geometry_msgs/Pose
geometry_msgs/Point position
geometry_msgs/Quaternion orientation

===
MSG: geometry_msgs/Point
float64 x
float64 y
float64 z

===
MSG: geometry_msgs/Quaternion
float64 x
float64 y
float64 z
float64 w`;

const messageDefinition = parse(definitionStr);

// print the parsed message definition structure
console.log(JSON.stringify(messageDefinition, null, 2));

Prints:

[
  {
    "definitions": [
      {
        "type": "geometry_msgs/Point",
        "isArray": false,
        "name": "position",
        "isComplex": true
      },
      {
        "type": "geometry_msgs/Quaternion",
        "isArray": false,
        "name": "orientation",
        "isComplex": true
      }
    ]
  },
  {
    "name": "geometry_msgs/Point",
    "definitions": [
      {
        "type": "float64",
        "isArray": false,
        "name": "x",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "y",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "z",
        "isComplex": false
      }
    ]
  },
  {
    "name": "geometry_msgs/Quaternion",
    "definitions": [
      {
        "type": "float64",
        "isArray": false,
        "name": "x",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "y",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "z",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "w",
        "isComplex": false
      }
    ]
  }
]

ROS 2 Definition Usage

import { parse, stringify } from "@foxglove/rosmsg";

const definitionStr = `# geometry_msgs/msg/Pose
geometry_msgs/msg/Point position
geometry_msgs/msg/Quaternion orientation

===
MSG: geometry_msgs/msg/Point
float64 x
float64 y
float64 z

===
MSG: geometry_msgs/msg/Quaternion
float64 x
float64 y
float64 z
float64 w`;

const messageDefinition = parse(definitionStr, {ros2: true});

// stringify(messageDefinition) will return a canonical string, similar to
// _definitionStr_
// print the parsed message definition structure
console.log(JSON.stringify(messageDefinition, null, 2));

Prints:

[
  {
    "definitions": [
      {
        "type": "geometry_msgs/msg/Point",
        "isArray": false,
        "name": "position",
        "isComplex": true
      },
      {
        "type": "geometry_msgs/msg/Quaternion",
        "isArray": false,
        "name": "orientation",
        "isComplex": true
      }
    ]
  },
  {
    "name": "geometry_msgs/msg/Point",
    "definitions": [
      {
        "type": "float64",
        "isArray": false,
        "name": "x",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "y",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "z",
        "isComplex": false
      }
    ]
  },
  {
    "name": "geometry_msgs/msg/Quaternion",
    "definitions": [
      {
        "type": "float64",
        "isArray": false,
        "name": "x",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "y",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "z",
        "isComplex": false
      },
      {
        "type": "float64",
        "isArray": false,
        "name": "w",
        "isComplex": false
      }
    ]
  }
]

ROS 2 IDL Support

See (@foxglove/ros2idl-parser)[https://github.com/foxglove/omgidl/packages/ros2idl-parser] for our implementation of ros2idl schema support.

License

@foxglove/rosmsg is licensed under the MIT License.

Releasing

  1. Run yarn version --[major|minor|patch] to bump version
  2. Run git push && git push --tags to push new tag
  3. GitHub Actions will take care of the rest

Stay in touch

Join our Slack channel to ask questions, share feedback, and stay up to date on what our team is working on.

rosmsg's People

Contributors

achim-k avatar amacneil avatar defunctzombie avatar esthersweon avatar jhurliman avatar jtbandes avatar snosenzo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

rosmsg's Issues

Types with same name are mixed up

Description
When parsing multiple types with the same name, such as visualization_msgs/Marker and aruco_msgs/Marker, the library mixes them up when they are used as children of another type.

  • Version: 4.2.2 (I tested with several versions from 1.0.1 to 4.2.2 and the bug seems to be present in all of them)
  • Platform: Linux, ROS noetic (but this probably hits ROS2 too)

Steps To Reproduce

  let res = parse(`

MSG: visualization_msgs/Marker
int32 a

===
MSG: aruco_msgs/Marker
int32 b

===
MSG: visualization_msgs/MarkerArray
Marker[] a

===
MSG: aruco_msgs/MarkerArray
Marker[] b
  
  `, { ros2: false })

  console.log(JSON.stringify(res, undefined, 2));

Expected Behavior
aruco_msgs/MarkerArray should contain an array of aruco_msgs/Marker, not visualization_msgs/Marker.

[
  {
    "name": "visualization_msgs/Marker",
    "definitions": [
      {
        "type": "int32",
        "isArray": false,
        "name": "a",
        "isComplex": false
      }
    ]
  },
  {
    "name": "aruco_msgs/Marker",
    "definitions": [
      {
        "type": "int32",
        "isArray": false,
        "name": "b",
        "isComplex": false
      }
    ]
  },
  {
    "name": "visualization_msgs/MarkerArray",
    "definitions": [
      {
        "type": "visualization_msgs/Marker",
        "isArray": true,
        "name": "a",
        "isComplex": true
      }
    ]
  },
  {
    "name": "aruco_msgs/MarkerArray",
    "definitions": [
      {
        "type": "aruco_msgs/Marker",
        "isArray": true,
        "name": "b",
        "isComplex": true
      }
    ]
  }
]

Actual behavior
Both MarkerArray types contain an array of visualization_msgs/Marker.

[
  {
    "name": "visualization_msgs/Marker",
    "definitions": [
      {
        "type": "int32",
        "isArray": false,
        "name": "a",
        "isComplex": false
      }
    ]
  },
  {
    "name": "aruco_msgs/Marker",
    "definitions": [
      {
        "type": "int32",
        "isArray": false,
        "name": "b",
        "isComplex": false
      }
    ]
  },
  {
    "name": "visualization_msgs/MarkerArray",
    "definitions": [
      {
        "type": "visualization_msgs/Marker",
        "isArray": true,
        "name": "a",
        "isComplex": true
      }
    ]
  },
  {
    "name": "aruco_msgs/MarkerArray",
    "definitions": [
      {
        "type": "visualization_msgs/Marker",
        "isArray": true,
        "name": "b",
        "isComplex": true
      }
    ]
  }
]

Support IDL-defined message schemas

IDL is the "base" message schema format for ROS2, and it's possible that a user may produce an IDL schema for a message without first defining a .msg schema first.

I think the best approach for this would be to define a function that translates an IDL schema into a RosMsgField[], extending the set of supported types in RosMsgField as necessary.

There is already a lark grammar for parsing the ROS2 subset of IDL available here, which is nice because it gives us a clear subset of the full IDL spec to support.

Incorrectly Formated ROS 1 `definitionStr` in README.md

Description
Instead of geometry_msgs/msg/Pose, I believe it should be geometry_msgs/Pose, i.e., removing the additional msg/ in the middle.

const definitionStr = `# geometry_msgs/Pose
geometry_msgs/Point position
geometry_msgs/Quaternion orientation

===
MSG: geometry_msgs/Point
float64 x
float64 y
float64 z

===
MSG: geometry_msgs/Quaternion
float64 x
float64 y
float64 z
float64 w`;

Otherwise it will return:

webpack://@foxglove/rosmsg/./node_modules/nearley/lib/nearley.js:295
                var err = new Error(this.reportLexerError(e));
^
Error: invalid syntax at line 1 col 18:

  geometry_msgs/msg/Point position
                   ^
Unexpected input (lexer error). Instead, I was expecting to see one of the following:

A "[" based on:
    arrayType →  ● "[" _ "]"
    main → _ customType ● arrayType __ field _ main$ebnf$6 complex
A "[" based on:
    arrayType →  ● "[" _ number _ "]"
    main → _ customType ● arrayType __ field _ main$ebnf$6 complex
A space token based on:
    _$subexpression$1 →  ● %space
    _ →  ● _$subexpression$1
    arrayType →  ● _
    main → _ customType ● arrayType __ field _ main$ebnf$6 complex
A space token based on:
    __ →  ● %space
    main → _ customType arrayType ● __ field _ main$ebnf$6 complex

    at Parser.feed (webpack://@foxglove/rosmsg/./node_modules/nearley/lib/nearley.js:295:1)
    at webpack://@foxglove/rosmsg/./src/parse.ts:114:12
    at Array.forEach (<anonymous>)
    at buildType (webpack://@foxglove/rosmsg/./src/parse.ts:106:9)
    at webpack://@foxglove/rosmsg/./src/parse.ts:68:13
    at Array.forEach (<anonymous>)
    at parse (webpack://@foxglove/rosmsg/./src/parse.ts:57:12)
    at Object.<anonymous> (/home/shouheng/Development/repos/experiments/rosmsg.ts:22:32)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module.m._compile (/usr/lib/node_modules/ts-node/src/index.ts:1618:23) {
  offset: 1,
  token: undefined
}
  • Version:
  • Platform:

Steps To Reproduce

Expected Behavior

[QUESTION] - Typescript type generation from ros msg, srv or idl

Hello hello,

I'm looking at a way of generating typescript types for messages/services using .msg, .srv or .idl files. I'm not very familiar with ros or rosapi but I'm super impressed & excited by the tooling ya'll at foxglove have been created so I thought I'd raise it here.

What I was thinking was a CLI tool where you configure:

  • Output directory, eg) generated
  • rosbridge_suite rosapi endpoint eg) ws://localhost:9090

You would then call a CLI function eg) ros-ts-type generate -o ./generated -e ws://localhost:9090
This would:

  • Talk to the ros_api and get the interface of all messages and services (I'm not familiar with rosapi)
  • Convert each of these msg and srv interfaces to a typescript interface
  • Output these interfaces to the ./generated folder.

Does this workflow make sense?
What are the challenges in implementing such a thing?
Does foxglove have any other tooling which will help in acheiving this?

Allow parsing message definitions with unresolved type names

The parse() function only works on "full" message definitions, the type produced by gendeps --cat that include multiple message definitions separated by ======== lines and the MSG: prefix for non-root types. This library should also support parsing message definitions in the format ROS message definition libraries commonly store them on disk, with one type per file. An additional function to fix up type names after loading all the relevant definitions from disk is probably needed as well.

Docmentation for running gendeps2

Description

Sorry to bother you with this. I think we need simple documentation for people to run gendeps2 locally, especially for people like me who come from a C++/python background and know nothing about JavaScript/TypeScript.

  • Version: Current main branch 1b9df73
  • Platform: macOS Sonoma 14.2.1

Steps To Reproduce
Just want to use gendeps2 to generate similar files that are recorded at https://github.com/foxglove/rosmsg-msgs-common/tree/main

I have zero experience with JavaScript/TypeScript and related things. I did everything by quickly googling around. But apparently, I messed up some simple things. The following is what I did.

cd <a random place>
git clone https://github.com/foxglove/rosmsg.git
cd rosmsg
npm run build
cd ../
npm install ./rosmsg

After the above operations, I have gendeps2 available locally in my terminal. But when I do

gendeps2

I got the following error

node:internal/modules/cjs/loader:1146
  throw err;
  ^

Error: Cannot find module '../dist/gendeps2'
Require stack:
- /Users/yaoyuh/Projects/foxglove_packages/rosmsg/bin/gendeps2
    at Module._resolveFilename (node:internal/modules/cjs/loader:1143:15)
    at Module._load (node:internal/modules/cjs/loader:984:27)
    at Module.require (node:internal/modules/cjs/loader:1234:19)
    at require (node:internal/modules/helpers:176:18)
    at Object.<anonymous> (/Users/yaoyuh/Projects/foxglove_packages/rosmsg/bin/gendeps2:2:1)
    at Module._compile (node:internal/modules/cjs/loader:1375:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1434:10)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Module._load (node:internal/modules/cjs/loader:1022:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:142:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/Users/yaoyuh/Projects/foxglove_packages/rosmsg/bin/gendeps2' ]
}

I checked the source folder and there is a dist folder with the content of

buildRos2Type.d.ts
buildRos2Type.d.ts.map
gendeps2.d.ts
gendeps2.d.ts.map
index.d.ts
index.d.ts.map
index.js
index.js.map
md5.d.ts
md5.d.ts.map
parse.d.ts
parse.d.ts.map
stringify.d.ts
stringify.d.ts.map

Expected Behavior

I think I have done something stupid but I cannot tell by myself. However, what I'm expecting to see is the terminal complains like

"Usage: gendeps <msgdefs-dir> <msg-file>"

as designed at

console.error("Usage: gendeps <msgdefs-dir> <msg-file>");

My final goal is to use gendeps2 to generate .msg files that look like those recorded in foxglove/rosmsg-msgs-common, where a single .msg file contains all the content of its dependent messages.

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.