diff --git a/package-lock.json b/package-lock.json index 6c808eb..bffe290 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2782,9 +2782,9 @@ "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" }, "caniuse-lite": { - "version": "1.0.30001109", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001109.tgz", - "integrity": "sha512-4JIXRodHzdS3HdK8nSgIqXYLExOvG+D2/EenSvcub2Kp3QEADjo2v2oUn5g0n0D+UNwG9BtwKOyGcSq2qvQXvQ==", + "version": "1.0.30001296", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001296.tgz", + "integrity": "sha512-WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q==", "dev": true }, "caseless": { @@ -4335,9 +4335,9 @@ } }, "engine.io-client": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz", - "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.3.tgz", + "integrity": "sha512-PXIgpzb1brtBzh8Q6vCjzCMeu4nfEPmaDm+L3Qb2sVHwLkxC1qRiBMSjOB0NJNjZ0hbPNUKQa+s8J2XxLOIEeQ==", "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", @@ -4348,7 +4348,7 @@ "parseqs": "0.0.5", "parseuri": "0.0.5", "ws": "~6.1.0", - "xmlhttprequest-ssl": "~1.5.4", + "xmlhttprequest-ssl": "~1.6.3", "yeast": "0.1.2" }, "dependencies": { @@ -11801,9 +11801,9 @@ "integrity": "sha512-ryT4RVDlSlwrRtCFgtH5PTRrAC+JGfzFxXJ1E5Wdfu2xVVcoeBkl2ocVp4XgOhzWJQWiSaHyq30VmSBhBPcigQ==" }, "three-spritetext": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/three-spritetext/-/three-spritetext-1.6.2.tgz", - "integrity": "sha512-VALj40t81Z6x/fDnY/tts8QU+mBl77bxoynBbcn/DW4oxfzZSwjaOfkQOe0jYpLoK2vtP0bAULvGgwIYnsN6oQ==" + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/three-spritetext/-/three-spritetext-1.6.3.tgz", + "integrity": "sha512-AE9AzUvY3xpQryTy+H5ylYkaWs+ZgsPqbF7yGXPEjthX5n/coIxobSVZAcPCTyl77DnM0Ub/YH7gLI54Eyg+dQ==" }, "through": { "version": "2.3.8", @@ -13346,9 +13346,9 @@ } }, "ws": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz", - "integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==" + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", + "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==" }, "x-is-string": { "version": "0.1.0", @@ -13361,9 +13361,9 @@ "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==" }, "xmlhttprequest-ssl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz", + "integrity": "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==" }, "xstream": { "version": "11.14.0", diff --git a/package.json b/package.json index d671bb3..1316376 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "three": "^0.117.0" }, "scripts": { - "start": "webpack-dev-server --config webpack.app.dev.js --host 192.168.64.6", + "start": "webpack-dev-server --config webpack.app.dev.js --host 10.82.207.213", "build": "webpack --config webpack.app.prod.js", "build-lib": "webpack --config webpack.lib.prod.js", "lint": "eslint src/**/*.{js,jsx} --fix", diff --git a/path.py b/path.py new file mode 100644 index 0000000..fd4866f --- /dev/null +++ b/path.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +import rospy + +from nav_msgs.msg import Path +from nav_msgs.msg import Odometry +from geometry_msgs.msg import PoseStamped + +path = Path() + +def odom_cb(data): + global path + path.header = data.header + pose = PoseStamped() + pose.header = data.header + pose.pose = data.pose.pose + path.poses.append(pose) + path_pub.publish(path) + +rospy.init_node('path_node') + +odom_sub = rospy.Subscriber('/odom', Odometry, odom_cb) +path_pub = rospy.Publisher('/path', Path, queue_size=10) + +if __name__ == '__main__': + rospy.spin() diff --git a/src/panels/addModal/index.jsx b/src/panels/addModal/index.jsx index 22a3f82..a8023d6 100644 --- a/src/panels/addModal/index.jsx +++ b/src/panels/addModal/index.jsx @@ -54,6 +54,7 @@ class AddModal extends React.Component { ros, rosParams, rosTopics, + rosVersion, } = this.props; const { selectedViz, tabType } = this.state; return ( @@ -87,12 +88,14 @@ class AddModal extends React.Component { rosTopics={rosTopics} rosParams={rosParams} closeModal={closeModal} + rosVersion={rosVersion} /> ) : ( )} diff --git a/src/panels/addModal/tabTopicName.jsx b/src/panels/addModal/tabTopicName.jsx index cd2a2de..af99a74 100644 --- a/src/panels/addModal/tabTopicName.jsx +++ b/src/panels/addModal/tabTopicName.jsx @@ -1,6 +1,7 @@ import React from 'react'; import _ from 'lodash'; import { vizOptions } from '../../utils/vizOptions'; +import { ros2vizOptions } from '../../utils/vizOptions'; import { ButtonPrimary, FlexGrow } from '../../components/styled'; import { AddVizForm, @@ -41,16 +42,17 @@ class TopicName extends React.Component { } render() { - const { closeModal, rosTopics } = this.props; + const { closeModal, rosTopics, rosVersion } = this.props; const { selectedViz } = this.state; return ( {_.map(_.sortBy(rosTopics, 'name'), ({ name, messageType }) => { - const vizOption = _.find(vizOptions, v => + const vizOption = _.find(rosVersion === 1 ? vizOptions : ros2vizOptions, v => _.includes(v.messageTypes, messageType), ); + console.log(vizOptions); return vizOption ? ( - {_.map(vizOptions, op => { + {_.map(rosVersion === 1 ? vizOptions : ros2vizOptions, op => { return ( { this.setState({ rosParams: _.map(rosParams, p => _.trimStart(p, '/')) }); }); + this.ros_version_service.callService(ROSLIB.ServiceRequest(), result => { + this.setState({ rosVersion: result.version }); + }); } componentWillUnmount() { @@ -319,6 +324,7 @@ class Wrapper extends React.Component { graphModalOpen, rosEndpoint, rosParams, + rosVersion, rosStatus, rosTopics, } = this.state; @@ -360,6 +366,7 @@ class Wrapper extends React.Component { ros={this.ros} rosTopics={rosTopics} rosParams={rosParams} + rosVersion={rosVersion} closeModal={this.toggleAddModal} addVisualization={this.addVisualization} /> @@ -380,6 +387,7 @@ class Wrapper extends React.Component { rosInstance={this.ros} rosTopics={rosTopics} rosStatus={rosStatus} + rosVersion={rosVersion} vizInstances={this.vizInstances} visualizations={visualizations} viewer={this.viewer} @@ -420,6 +428,7 @@ class Wrapper extends React.Component { key={vizItem.key} viewer={this.viewer} rosTopics={rosTopics} + rosVersion={rosVersion} rosInstance={this.ros} /> ))} diff --git a/src/panels/info/index.jsx b/src/panels/info/index.jsx index 6c86832..ebfc3db 100644 --- a/src/panels/info/index.jsx +++ b/src/panels/info/index.jsx @@ -27,15 +27,22 @@ import AddInfoPanelModal from './addInfoPanelModal'; const MESSAGE_BUFFER_MAX_LENGTH = 1000; const compressionTypes = new Set([ 'sensor_msgs/Image', + 'sensor_msgs/msg/Image', 'sensor_msgs/PointCloud2', + 'sensor_msgs/msg/PointCloud2', 'sensor_msgs/PointCloud', 'sensor_msgs/LaserScan', + 'sensor_msgs/msg/LaserScan', 'nav_msgs/Path', + 'nav_msgs/msg/Path', 'nav_msgs/OccupancyGrid', + 'nav_msgs/msg/OccupancyGrid', 'visualization_msgs/MarkerArray', + 'visualization_msgs/msg/MarkerArray', 'geometry_msgs/Polygon', 'geometry_msgs/PolygonStamped', 'geometry_msgs/PoseArray', + 'geometry_msgs/msg/PoseArray', ]); const getTopicOptions = messageType => { if (compressionTypes.has(messageType)) { diff --git a/src/panels/sidebar/index.jsx b/src/panels/sidebar/index.jsx index 1c85c26..98c2d84 100644 --- a/src/panels/sidebar/index.jsx +++ b/src/panels/sidebar/index.jsx @@ -3,6 +3,7 @@ import _ from 'lodash'; import { ROS_SOCKET_STATUSES } from '../../utils'; import { vizOptions } from '../../utils/vizOptions'; +import { ros2vizOptions } from '../../utils/vizOptions'; import GlobalOptions from './globalOptions'; import { ButtonPrimary, @@ -73,6 +74,7 @@ class Sidebar extends React.Component { rosInstance, rosStatus, rosTopics, + rosVersion, toggleAddModal, toggleConfigurationModal, toggleVisibility, @@ -120,7 +122,7 @@ class Sidebar extends React.Component { )} {_.map(visualizations, vizItem => { const vizObject = _.find( - vizOptions, + rosVersion === 1 ? vizOptions : ros2vizOptions, v => v.type === vizItem.vizType, ); if (!vizObject) { diff --git a/src/panels/sidebar/vizOptions/vizSpecificOption.jsx b/src/panels/sidebar/vizOptions/vizSpecificOption.jsx index 56ace4f..5cd7676 100644 --- a/src/panels/sidebar/vizOptions/vizSpecificOption.jsx +++ b/src/panels/sidebar/vizOptions/vizSpecificOption.jsx @@ -15,22 +15,37 @@ import RobotModelLinksJoints from './robotModel'; const { VIZ_TYPE_IMAGE, + VIZ_TYPE_IMAGE2, VIZ_TYPE_INTERACTIVEMARKER, + VIZ_TYPE_INTERACTIVEMARKER2, VIZ_TYPE_LASERSCAN, + VIZ_TYPE_LASERSCAN2, VIZ_TYPE_MAP, + VIZ_TYPE_MAP2, VIZ_TYPE_MARKER, + VIZ_TYPE_MARKER2, VIZ_TYPE_MARKERARRAY, + VIZ_TYPE_MARKERARRAY2, VIZ_TYPE_ODOMETRY, + VIZ_TYPE_ODOMETRY2, VIZ_TYPE_PATH, + VIZ_TYPE_PATH2, VIZ_TYPE_POINT, + VIZ_TYPE_POINT2, VIZ_TYPE_POINTCLOUD, + VIZ_TYPE_ROS2POINTCLOUD, VIZ_TYPE_POLYGON, VIZ_TYPE_POSE, + VIZ_TYPE_POSE2, VIZ_TYPE_POSEARRAY, + VIZ_TYPE_POSEARRAY2, VIZ_TYPE_RANGE, + VIZ_TYPE_RANGE2, VIZ_TYPE_ROBOTMODEL, VIZ_TYPE_TF, + VIZ_TYPE_ROS2_TF, VIZ_TYPE_WRENCH, + VIZ_TYPE_WRENCH2, } = CONSTANTS; const VizSpecificOptions = ({ @@ -44,6 +59,8 @@ const VizSpecificOptions = ({ switch (vizType) { case VIZ_TYPE_IMAGE: return null; + case VIZ_TYPE_IMAGE2: + return null; case VIZ_TYPE_INTERACTIVEMARKER: return ( ); + case VIZ_TYPE_INTERACTIVEMARKER2: + return ( + + ); case VIZ_TYPE_LASERSCAN: return ( ); + case VIZ_TYPE_LASERSCAN2: + return ( + + ); case VIZ_TYPE_MAP: return ( ); + case VIZ_TYPE_MAP2: + return ( + + ); case VIZ_TYPE_MARKER: return ( ); + case VIZ_TYPE_MARKER2: + return ( + + ); case VIZ_TYPE_MARKERARRAY: return null; + case VIZ_TYPE_MARKERARRAY2: + return null; case VIZ_TYPE_ODOMETRY: return ( ); + case VIZ_TYPE_ODOMETRY2: + return ( + + ); case VIZ_TYPE_PATH: return ( ); + case VIZ_TYPE_PATH2: + return ( + + ); case VIZ_TYPE_POINT: return ( ); + case VIZ_TYPE_POINT2: + return ( + + ); case VIZ_TYPE_POINTCLOUD: return ( ); + case VIZ_TYPE_ROS2POINTCLOUD: + return ( + + ); case VIZ_TYPE_POLYGON: return null; case VIZ_TYPE_POSE: return ( ); + case VIZ_TYPE_POSE2: + return ( + + ); case VIZ_TYPE_POSEARRAY: return null; + case VIZ_TYPE_POSEARRAY2: + return null; case VIZ_TYPE_RANGE: return ( ); + case VIZ_TYPE_RANGE2: + return ( + + ); case VIZ_TYPE_ROBOTMODEL: return ; case VIZ_TYPE_TF: return null; + case VIZ_TYPE_ROS2_TF: + return null; case VIZ_TYPE_WRENCH: return ( ); + case VIZ_TYPE_WRENCH2: + return ( + + ); default: return null; } diff --git a/src/panels/visualizations/index.jsx b/src/panels/visualizations/index.jsx index d48b7d4..cc88f6a 100644 --- a/src/panels/visualizations/index.jsx +++ b/src/panels/visualizations/index.jsx @@ -4,6 +4,7 @@ import Amphion from 'amphion'; import _, { map } from 'lodash'; import { getTfTopics } from '../../utils'; +import { getROS2TfTopics } from '../../utils'; import { VizImageContainer, VizImageHeader } from '../../components/styled/viz'; import { VIZ_TYPE_DEPTHCLOUD_STREAM, @@ -13,19 +14,33 @@ import { getOrCreateRosTopicDataSource } from '../sources'; const { MESSAGE_TYPE_IMAGE, + MESSAGE_TYPE_IMAGE2, MESSAGE_TYPE_LASERSCAN, + MESSAGE_TYPE_LASERSCAN2, MESSAGE_TYPE_MARKER, + MESSAGE_TYPE_MARKER2, MESSAGE_TYPE_MARKERARRAY, + MESSAGE_TYPE_MARKERARRAY2, MESSAGE_TYPE_OCCUPANCYGRID, + MESSAGE_TYPE_OCCUPANCYGRID2, MESSAGE_TYPE_ODOMETRY, + MESSAGE_TYPE_ODOMETRY2, MESSAGE_TYPE_PATH, + MESSAGE_TYPE_PATH2, MESSAGE_TYPE_POINT, + MESSAGE_TYPE_POINT2, MESSAGE_TYPE_POINTCLOUD2, + MESSAGE_TYPE_ROS2POINTCLOUD2, MESSAGE_TYPE_POSEARRAY, + MESSAGE_TYPE_POSEARRAY2, MESSAGE_TYPE_POSESTAMPED, + MESSAGE_TYPE_POSESTAMPED2, MESSAGE_TYPE_RANGE, + MESSAGE_TYPE_RANGE2, MESSAGE_TYPE_TF2, + MESSAGE_TYPE_ROS2_TF2, MESSAGE_TYPE_WRENCH, + MESSAGE_TYPE_WRENCH2, VIZ_TYPE_IMAGE, VIZ_TYPE_INTERACTIVEMARKER, VIZ_TYPE_LASERSCAN, @@ -52,7 +67,8 @@ class Visualization extends React.PureComponent { this.resetVisualization = this.resetVisualization.bind(this); } - static getNewViz(vizType, ros, resourceName, viewer, options) { + static getNewViz(vizType, ros, resourceName, viewer, options, rosVersion) { + switch (vizType) { case VIZ_TYPE_IMAGE_STREAM: { return new Amphion.ImageStream(resourceName); @@ -61,10 +77,10 @@ class Visualization extends React.PureComponent { const imageSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_IMAGE, + messageType: rosVersion == 1 ? MESSAGE_TYPE_IMAGE : MESSAGE_TYPE_IMAGE2, queueSize: 1, queueLength: 0, - compression: 'cbor', + compression: rosVersion == 1 ? 'cbor' : '', }); return new Amphion.Image(imageSource, options); } @@ -82,8 +98,8 @@ class Visualization extends React.PureComponent { const laserScanSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_LASERSCAN, - compression: 'cbor', + messageType: rosVersion == 1 ? MESSAGE_TYPE_LASERSCAN : MESSAGE_TYPE_LASERSCAN2, + compression: rosVersion == 1 ? 'cbor' : '', }); return new Amphion.LaserScan(laserScanSource, options); } @@ -91,8 +107,8 @@ class Visualization extends React.PureComponent { const mapSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_OCCUPANCYGRID, - compression: 'cbor', + messageType: rosVersion == 1 ? MESSAGE_TYPE_OCCUPANCYGRID : MESSAGE_TYPE_OCCUPANCYGRID2, + compression: rosVersion == 1 ? 'cbor' : '', queueSize: 1, queueLength: 0, }); @@ -102,7 +118,7 @@ class Visualization extends React.PureComponent { const markerSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_MARKER, + messageType: rosVersion == 1 ? MESSAGE_TYPE_MARKER : MESSAGE_TYPE_MARKER2, }); return new Amphion.Marker(markerSource, options); } @@ -110,7 +126,7 @@ class Visualization extends React.PureComponent { const markerArraySource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_MARKERARRAY, + messageType: rosVersion == 1 ? MESSAGE_TYPE_MARKERARRAY: MESSAGE_TYPE_MARKERARRAY2, queueLength: 0, queueSize: 1, }); @@ -120,7 +136,7 @@ class Visualization extends React.PureComponent { const odometrySource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_ODOMETRY, + messageType: rosVersion == 1 ? MESSAGE_TYPE_ODOMETRY : MESSAGE_TYPE_ODOMETRY2, }); return new Amphion.Odometry(odometrySource, options); } @@ -128,7 +144,7 @@ class Visualization extends React.PureComponent { const pathSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_PATH, + messageType: rosVersion == 1 ? MESSAGE_TYPE_PATH : MESSAGE_TYPE_PATH2, }); return new Amphion.Path(pathSource, options); } @@ -136,7 +152,7 @@ class Visualization extends React.PureComponent { const pointSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_POINT, + messageType: rosVersion == 1 ? MESSAGE_TYPE_POINT : MESSAGE_TYPE_POINT2, }); return new Amphion.Point(pointSource, options); } @@ -144,8 +160,8 @@ class Visualization extends React.PureComponent { const pointcloudSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_POINTCLOUD2, - compression: 'cbor', + messageType: rosVersion == 1 ? MESSAGE_TYPE_POINTCLOUD2 : MESSAGE_TYPE_ROS2POINTCLOUD2, + compression: rosVersion == 1 ? 'cbor' : '', queueSize: 1, queueLength: 1, }); @@ -155,7 +171,7 @@ class Visualization extends React.PureComponent { const poseSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_POSESTAMPED, + messageType: rosVersion == 1 ? MESSAGE_TYPE_POSESTAMPED : MESSAGE_TYPE_POSESTAMPED2, }); return new Amphion.Pose(poseSource, options); } @@ -171,7 +187,7 @@ class Visualization extends React.PureComponent { const rangeSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_RANGE, + messageType: rosVersion == 1 ? MESSAGE_TYPE_RANGE : MESSAGE_TYPE_RANGE2, }); return new Amphion.Range(rangeSource, options); } @@ -181,7 +197,7 @@ class Visualization extends React.PureComponent { const tfSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_TF2, + messageType: rosVersion == 1 ? MESSAGE_TYPE_TF2 : MESSAGE_TYPE_ROS2_TF2, }); return new Amphion.Tf(tfSource, options); } @@ -189,13 +205,14 @@ class Visualization extends React.PureComponent { const wrenchSource = getOrCreateRosTopicDataSource({ ros, topicName: resourceName, - messageType: MESSAGE_TYPE_WRENCH, + messageType: rosVersion == 1 ? MESSAGE_TYPE_WRENCH : MESSAGE_TYPE_WRENCH2, }); return new Amphion.Wrench(wrenchSource, options); } default: return null; } + } componentDidMount() { @@ -208,11 +225,12 @@ class Visualization extends React.PureComponent { options, rosInstance, rosTopics, + rosVersion, } = this.props; if (vizType !== prevProps.options.vizType) { this.resetVisualization(); } - if (vizType === VIZ_TYPE_TF) { + if (vizType === VIZ_TYPE_TF && rosVersion === 1) { const currentTfTopics = getTfTopics(rosTopics); const prevTfTopics = getTfTopics(prevProps.rosTopics); if ( @@ -228,6 +246,22 @@ class Visualization extends React.PureComponent { ); this.vizInstance.changeSources(sources); } + } else if (vizType === VIZ_TYPE_TF && rosVersion === 2) { + const currentTfTopics = getROS2TfTopics(rosTopics); + const prevTfTopics = getROS2TfTopics(prevProps.rosTopics); + if ( + _.join(_.sortBy(_.map(currentTfTopics, 'name'))) !== + _.join(_.sortBy(_.map(prevTfTopics, 'name'))) + ) { + const sources = map(currentTfTopics, topic => + getOrCreateRosTopicDataSource({ + ros: rosInstance, + topicName: topic.name, + messageType: topic.messageType, + }), + ); + this.vizInstance.changeSources(sources); + } } else if (topicName !== prevProps.options.topicName) { if (this.vizInstance.changeTopic) { // TODO: remove this when all visualizations get ported @@ -257,6 +291,7 @@ class Visualization extends React.PureComponent { rosInstance, viewer, vizInstances, + rosVersion, } = this.props; if (this.vizInstance) { this.vizInstance.destroy(); @@ -269,6 +304,7 @@ class Visualization extends React.PureComponent { topicName, viewer, options, + rosVersion, ); if (!this.vizInstance) { return; diff --git a/src/utils/index.js b/src/utils/index.js index fe3d10a..af71815 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,6 +1,7 @@ import { CONSTANTS } from 'amphion'; import _ from 'lodash'; import { TF_MESSAGE_TYPES } from './vizOptions'; +import { ROS2_TF_MESSAGE_TYPES } from './vizOptions'; const { DEFAULT_OPTIONS_SCENE } = CONSTANTS; @@ -14,6 +15,9 @@ export const ROS_SOCKET_STATUSES = { export const getTfTopics = rosTopics => _.filter(rosTopics, t => _.includes(TF_MESSAGE_TYPES, t.messageType)); +export const getROS2TfTopics = rosTopics => + _.filter(rosTopics, t => _.includes(ROS2_TF_MESSAGE_TYPES, t.messageType)); + export const stopPropagation = e => e.stopPropagation(); export const downloadFile = (content, filename, options = {}) => { diff --git a/src/utils/sanitize.js b/src/utils/sanitize.js index 1329122..f37ff0c 100644 --- a/src/utils/sanitize.js +++ b/src/utils/sanitize.js @@ -4,23 +4,40 @@ const replacementMap = { 'sensor_msgs/Image': { key: 'data', }, + 'sensor_msgs/msg/Image': { + key: 'data', + }, 'visualization_msgs/MarkerArray': { key: 'markers', validation: it => size(it) <= 1000, }, + 'visualization_msgs/msg/MarkerArray': { + key: 'markers', + validation: it => size(it) <= 1000, + }, 'nav_msgs/OccupancyGrid': { key: 'data', }, + 'nav_msgs/msg/OccupancyGrid': { + key: 'data', + }, 'nav_msgs/Path': { key: 'poses', validation: it => size(it) <= 1000, }, + 'nav_msgs/msg/Path': { + key: 'poses', + validation: it => size(it) <= 1000, + }, 'sensor_msgs/PointCloud': { key: 'points', }, 'sensor_msgs/PointCloud2': { key: 'data', }, + 'sensor_msgs/msg/PointCloud2': { + key: 'data', + }, 'geometry_msgs/Polygon': { key: 'points', }, @@ -31,6 +48,10 @@ const replacementMap = { key: 'poses', validation: it => size(it) <= 1000, }, + 'geometry_msgs/msg/PoseArray': { + key: 'poses', + validation: it => size(it) <= 1000, + }, }; export const sanitizeMessage = (topic, message) => { diff --git a/src/utils/vizOptions.jsx b/src/utils/vizOptions.jsx index 615ca1d..ab79d8f 100644 --- a/src/utils/vizOptions.jsx +++ b/src/utils/vizOptions.jsx @@ -4,46 +4,80 @@ import { iconFillStyle, iconLineStyle } from './common'; const { MESSAGE_TYPE_IMAGE, + MESSAGE_TYPE_IMAGE2, MESSAGE_TYPE_INTERACTIVEMARKER, + MESSAGE_TYPE_INTERACTIVEMARKER2, MESSAGE_TYPE_INTERACTIVEMARKER_FEEDBACK, + MESSAGE_TYPE_INTERACTIVEMARKER_FEEDBACK2, MESSAGE_TYPE_INTERACTIVEMARKER_UPDATE, + MESSAGE_TYPE_INTERACTIVEMARKER_UPDATE2, MESSAGE_TYPE_LASERSCAN, + MESSAGE_TYPE_LASERSCAN2, MESSAGE_TYPE_MARKER, + MESSAGE_TYPE_MARKER2, MESSAGE_TYPE_MARKERARRAY, + MESSAGE_TYPE_MARKERARRAY2, MESSAGE_TYPE_OCCUPANCYGRID, + MESSAGE_TYPE_OCCUPANCYGRID2, MESSAGE_TYPE_ODOMETRY, + MESSAGE_TYPE_ODOMETRY2, MESSAGE_TYPE_PATH, + MESSAGE_TYPE_PATH2, MESSAGE_TYPE_POINTCLOUD2, + MESSAGE_TYPE_ROS2POINTCLOUD2, MESSAGE_TYPE_POINTSTAMPED, + MESSAGE_TYPE_POINTSTAMPED2, MESSAGE_TYPE_POSEARRAY, + MESSAGE_TYPE_POSEARRAY2, MESSAGE_TYPE_POSESTAMPED, + MESSAGE_TYPE_POSESTAMPED2, MESSAGE_TYPE_RANGE, + MESSAGE_TYPE_RANGE2, MESSAGE_TYPE_ROBOT_MODEL, MESSAGE_TYPE_TF, + MESSAGE_TYPE_ROS2_TF, MESSAGE_TYPE_TF2, + MESSAGE_TYPE_ROS2_TF2, MESSAGE_TYPE_WRENCHSTAMPED, + MESSAGE_TYPE_WRENCHSTAMPED2, VIZ_TYPE_IMAGE, + VIZ_TYPE_IMAGE2, VIZ_TYPE_INTERACTIVEMARKER, + VIZ_TYPE_INTERACTIVEMARKER2, VIZ_TYPE_LASERSCAN, + VIZ_TYPE_LASERSCAN2, VIZ_TYPE_MAP, + VIZ_TYPE_MAP2, VIZ_TYPE_MARKER, + VIZ_TYPE_MARKER2, VIZ_TYPE_MARKERARRAY, + VIZ_TYPE_MARKERARRAY2, VIZ_TYPE_ODOMETRY, + VIZ_TYPE_ODOMETRY2, VIZ_TYPE_PATH, + VIZ_TYPE_PATH2, VIZ_TYPE_POINT, + VIZ_TYPE_POINT2, VIZ_TYPE_POINTCLOUD, + VIZ_TYPE_ROS2POINTCLOUD, VIZ_TYPE_POSE, + VIZ_TYPE_POSE2, VIZ_TYPE_POSEARRAY, + VIZ_TYPE_POSEARRAY2, VIZ_TYPE_RANGE, + VIZ_TYPE_RANGE2, VIZ_TYPE_ROBOTMODEL, VIZ_TYPE_TF, + VIZ_TYPE_ROS2_TF, VIZ_TYPE_WRENCH, + VIZ_TYPE_WRENCH2, } = CONSTANTS; export const VIZ_TYPE_DEPTHCLOUD_STREAM = 'Depthcloud stream'; export const VIZ_TYPE_IMAGE_STREAM = 'Image stream'; export const TF_MESSAGE_TYPES = [MESSAGE_TYPE_TF, MESSAGE_TYPE_TF2]; +export const ROS2_TF_MESSAGE_TYPES = [MESSAGE_TYPE_ROS2_TF, MESSAGE_TYPE_ROS2_TF2]; const DOCS_ROOT_URL = 'https://github.com/rapyuta-robotics/zethus/wiki/'; @@ -563,3 +597,443 @@ export const vizOptions = [ docsLink: `${DOCS_ROOT_URL}Wrench`, }, ]; + +export const ros2vizOptions = [ + { + type: VIZ_TYPE_IMAGE, + icon: ( + + + + + + ), + messageTypes: [MESSAGE_TYPE_IMAGE2], + description: `Creates a container to visualize the image data represented by a sensor_msgs/msg/Image topic. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-image.png "")`, + docsLink: `${DOCS_ROOT_URL}Image`, + }, + { + type: VIZ_TYPE_IMAGE_STREAM, + icon: ( + + + + + + ), + messageTypes: [], + description: `Creates a container to visualize the image data as a video stream coming via + [web-video-server](http://wiki.ros.org/web_video_server). + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-image.png "")`, + docsLink: `${DOCS_ROOT_URL}ImageStream`, + }, + { + type: VIZ_TYPE_LASERSCAN, + icon: ( + + + + + + + + + ), + messageTypes: [MESSAGE_TYPE_LASERSCAN2], + description: `Adds a visualization represented by a sensor_msgs/msg/LaserScan topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-laserscan.png "")`, + docsLink: `${DOCS_ROOT_URL}Laser-Scan`, + }, + { + type: VIZ_TYPE_MAP, + icon: ( + + + + + + + + + + + + + + + ), + messageTypes: [MESSAGE_TYPE_OCCUPANCYGRID2], + description: `Adds a visualization represented by a nav_msgs/msg/OccupancyGrid topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-map.png "")`, + docsLink: `${DOCS_ROOT_URL}Map`, + }, + { + type: VIZ_TYPE_MARKER, + icon: ( + + + + + + ), + messageTypes: [MESSAGE_TYPE_MARKER2], + description: `Adds a visualization represented by a visualization_msgs/msg/Marker or visualization_msgs/msg/MarkerArray topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-marker.png "")`, + docsLink: `${DOCS_ROOT_URL}Marker`, + }, + { + type: VIZ_TYPE_MARKERARRAY, + icon: markerArrayIcon, + messageTypes: [MESSAGE_TYPE_MARKERARRAY2], + description: `Adds a visualization represented by a visualization_msgs/msg/Marker or visualization_msgs/msg/MarkerArray topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-markerarray.png "")`, + docsLink: `${DOCS_ROOT_URL}Marker-Array`, + }, + { + type: VIZ_TYPE_INTERACTIVEMARKER, + icon: markerArrayIcon, + messageTypes: [MESSAGE_TYPE_INTERACTIVEMARKER2], + additionalMessageTypes: [ + MESSAGE_TYPE_INTERACTIVEMARKER_UPDATE2, + MESSAGE_TYPE_INTERACTIVEMARKER_FEEDBACK2, + ], + description: `Adds an interactive visualization represented by a visualization_msgs/msg/InteractiveMarker topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-interactive-marker.png)`, + docsLink: `${DOCS_ROOT_URL}Interactive-Marker`, + }, + { + type: VIZ_TYPE_ODOMETRY, + icon: ( + + + + + + + + + + + ), + messageTypes: [MESSAGE_TYPE_ODOMETRY2], + description: `Adds a visualization represented by a nav_msgs/msg/Odometry topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-odometry.png "")`, + docsLink: `${DOCS_ROOT_URL}Odometry`, + isDisplay: false, + }, + { + type: VIZ_TYPE_PATH, + icon: ( + + + + + + ), + messageTypes: [MESSAGE_TYPE_PATH2], + description: `Adds a visualization represented by a nav_msgs/msg/Path topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-path.png "")`, + docsLink: `${DOCS_ROOT_URL}Path`, + }, + { + type: VIZ_TYPE_POINTCLOUD, + icon: ( + + + + + ), + messageTypes: [MESSAGE_TYPE_ROS2POINTCLOUD2], + description: `Adds a visualization represented by a sensor_msgs/msg/PointCloud2 topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-pointcloud.png "")`, + docsLink: `${DOCS_ROOT_URL}Point-Cloud-2`, + }, + { + type: VIZ_TYPE_POINT, + icon: ( + + + + ), + messageTypes: [MESSAGE_TYPE_POINTSTAMPED2], + description: `Adds a visualization represented by a geometry_msgs/msg/PointStamped topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-point.png "")`, + docsLink: `${DOCS_ROOT_URL}Point`, + }, + { + type: VIZ_TYPE_POSE, + icon: ( + + + + + + ), + messageTypes: [MESSAGE_TYPE_POSESTAMPED2], + description: `Adds a visualization represented by a geometry_msgs/msg/PoseStamped topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-pose.png "")`, + docsLink: `${DOCS_ROOT_URL}Pose`, + }, + { + type: VIZ_TYPE_POSEARRAY, + icon: ( + + + + + + + + + ), + messageTypes: [MESSAGE_TYPE_POSEARRAY2], + description: `Adds a visualization represented by a geometry_msgs/msg/PoseArray topic to the scene. An array of pose is added to the scene based on the Shape type selected. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-posearray.png "")`, + docsLink: `${DOCS_ROOT_URL}Pose-Array`, + }, + { + type: VIZ_TYPE_RANGE, + icon: ( + + + + ), + messageTypes: [MESSAGE_TYPE_RANGE2], + description: `Adds a visualization represented by a sensor_msgs/msg/Range topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-range.png "")`, + docsLink: `${DOCS_ROOT_URL}Range`, + }, + { + type: VIZ_TYPE_DEPTHCLOUD_STREAM, + icon: ( + + + + + ), + messageTypes: [], + description: `Visualizes depthcloud from the + [depthcloud_encoder](http://wiki.ros.org/depthcloud_encoder) + via [web-video-server](http://wiki.ros.org/web_video_server) stream`, + docsLink: `${DOCS_ROOT_URL}Depthcloud`, + }, + { + type: VIZ_TYPE_TF, + icon: ( + + + + + + + + + ), + messageTypes: ROS2_TF_MESSAGE_TYPES, + description: `Adds a visualization represented by a tf/tfMessage and tf2_msgs/msg/TFMessage topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-tf.png "")`, + docsLink: `${DOCS_ROOT_URL}Tf`, + }, + { + type: VIZ_TYPE_WRENCH, + icon: ( + + + + + + + + ), + messageTypes: [MESSAGE_TYPE_WRENCHSTAMPED2], + description: `Adds a visualization represented by a geometry_msgs/msg/WrenchStamped topic to the scene. + ![](${window.location.protocol}//${window.location.host}/zethus/app/image/viz/viz-wrench.png "")`, + docsLink: `${DOCS_ROOT_URL}Wrench`, + }, +]; \ No newline at end of file