Add tutorial for type description service#1268
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds a comprehensive tutorial for the Type Description Service feature in rclnodejs. The tutorial provides detailed documentation on how to use the built-in ROS 2 introspection service that allows querying message and service type information from running nodes.
Key changes:
- Complete tutorial covering Type Description Service functionality, requirements, and usage patterns
- Multiple practical examples demonstrating basic usage, advanced features, and best practices
- Comprehensive troubleshooting guide and performance considerations
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| } | ||
|
|
||
| async discoverNodeTypes(nodeName) { | ||
| console.log(`\\nDiscovering types for node: ${nodeName}`); |
There was a problem hiding this comment.
The escaped newline character should be a literal newline. Replace \\n with \n.
| console.log(`\\nDiscovering types for node: ${nodeName}`); | |
| console.log(`\nDiscovering types for node: ${nodeName}`); |
| processTypeDescription(typeName, response) { | ||
| const typeDesc = response.type_description.type_description; | ||
|
|
||
| console.log(`\\n=== Type: ${typeName} ===`); |
There was a problem hiding this comment.
The escaped newline character should be a literal newline. Replace \\n with \n.
| console.log(`\\n=== Type: ${typeName} ===`); | |
| console.log(`\n=== Type: ${typeName} ===`); |
| } | ||
|
|
||
| printSummary() { | ||
| console.log(`\\n=== Discovery Summary ===`); |
There was a problem hiding this comment.
The escaped newline character should be a literal newline. Replace \\n with \n.
| console.log(`\\n=== Discovery Summary ===`); | |
| console.log(`\n=== Discovery Summary ===`); |
| let markdown = `# Type Documentation for Node: ${nodeName}\\n\\n`; | ||
| markdown += `Generated on: ${new Date().toISOString()}\\n\\n`; | ||
|
|
||
| this.documentation.forEach((doc) => { | ||
| markdown += `## ${doc.typeName}\\n\\n`; | ||
| markdown += `**Topic**: \`${doc.topicName}\`\\n\\n`; | ||
|
|
||
| if (doc.description.fields.length > 0) { | ||
| markdown += `### Fields\\n\\n`; | ||
| markdown += `| Field Name | Type | Default Value |\\n`; | ||
| markdown += `|------------|------|---------------|\\n`; | ||
|
|
||
| doc.description.fields.forEach((field) => { | ||
| const typeStr = this.formatFieldTypeForDoc(field.type); | ||
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` |\\n`; | ||
| }); | ||
| markdown += `\\n`; | ||
| } | ||
|
|
||
| if (doc.sources.length > 0) { | ||
| markdown += `### Source Definition\\n\\n`; | ||
| markdown += `\`\`\`${doc.sources[0].encoding}\\n`; | ||
| markdown += doc.sources[0].raw_file_contents; | ||
| markdown += `\`\`\`\\n\\n`; | ||
| } | ||
|
|
||
| markdown += `---\\n\\n`; |
There was a problem hiding this comment.
The escaped newline characters should be literal newlines. Replace \\n with \n.
| let markdown = `# Type Documentation for Node: ${nodeName}\\n\\n`; | |
| markdown += `Generated on: ${new Date().toISOString()}\\n\\n`; | |
| this.documentation.forEach((doc) => { | |
| markdown += `## ${doc.typeName}\\n\\n`; | |
| markdown += `**Topic**: \`${doc.topicName}\`\\n\\n`; | |
| if (doc.description.fields.length > 0) { | |
| markdown += `### Fields\\n\\n`; | |
| markdown += `| Field Name | Type | Default Value |\\n`; | |
| markdown += `|------------|------|---------------|\\n`; | |
| doc.description.fields.forEach((field) => { | |
| const typeStr = this.formatFieldTypeForDoc(field.type); | |
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` |\\n`; | |
| }); | |
| markdown += `\\n`; | |
| } | |
| if (doc.sources.length > 0) { | |
| markdown += `### Source Definition\\n\\n`; | |
| markdown += `\`\`\`${doc.sources[0].encoding}\\n`; | |
| markdown += doc.sources[0].raw_file_contents; | |
| markdown += `\`\`\`\\n\\n`; | |
| } | |
| markdown += `---\\n\\n`; | |
| let markdown = `# Type Documentation for Node: ${nodeName}\n\n`; | |
| markdown += `Generated on: ${new Date().toISOString()}\n\n`; | |
| this.documentation.forEach((doc) => { | |
| markdown += `## ${doc.typeName}\n\n`; | |
| markdown += `**Topic**: \`${doc.topicName}\`\n\n`; | |
| if (doc.description.fields.length > 0) { | |
| markdown += `### Fields\n\n`; | |
| markdown += `| Field Name | Type | Default Value |\n`; | |
| markdown += `|------------|------|---------------|\n`; | |
| doc.description.fields.forEach((field) => { | |
| const typeStr = this.formatFieldTypeForDoc(field.type); | |
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` |\n`; | |
| }); | |
| markdown += `\n`; | |
| } | |
| if (doc.sources.length > 0) { | |
| markdown += `### Source Definition\n\n`; | |
| markdown += `\`\`\`${doc.sources[0].encoding}\n`; | |
| markdown += doc.sources[0].raw_file_contents; | |
| markdown += `\`\`\`\n\n`; | |
| } | |
| markdown += `---\n\n`; |
| let markdown = `# Type Documentation for Node: ${nodeName}\\n\\n`; | ||
| markdown += `Generated on: ${new Date().toISOString()}\\n\\n`; | ||
|
|
||
| this.documentation.forEach((doc) => { | ||
| markdown += `## ${doc.typeName}\\n\\n`; | ||
| markdown += `**Topic**: \`${doc.topicName}\`\\n\\n`; | ||
|
|
||
| if (doc.description.fields.length > 0) { | ||
| markdown += `### Fields\\n\\n`; | ||
| markdown += `| Field Name | Type | Default Value |\\n`; | ||
| markdown += `|------------|------|---------------|\\n`; | ||
|
|
||
| doc.description.fields.forEach((field) => { | ||
| const typeStr = this.formatFieldTypeForDoc(field.type); | ||
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` |\\n`; | ||
| }); | ||
| markdown += `\\n`; | ||
| } | ||
|
|
||
| if (doc.sources.length > 0) { | ||
| markdown += `### Source Definition\\n\\n`; | ||
| markdown += `\`\`\`${doc.sources[0].encoding}\\n`; | ||
| markdown += doc.sources[0].raw_file_contents; | ||
| markdown += `\`\`\`\\n\\n`; | ||
| } | ||
|
|
||
| markdown += `---\\n\\n`; |
There was a problem hiding this comment.
The escaped newline characters should be literal newlines. Replace \\n with \n.
| let markdown = `# Type Documentation for Node: ${nodeName}\\n\\n`; | |
| markdown += `Generated on: ${new Date().toISOString()}\\n\\n`; | |
| this.documentation.forEach((doc) => { | |
| markdown += `## ${doc.typeName}\\n\\n`; | |
| markdown += `**Topic**: \`${doc.topicName}\`\\n\\n`; | |
| if (doc.description.fields.length > 0) { | |
| markdown += `### Fields\\n\\n`; | |
| markdown += `| Field Name | Type | Default Value |\\n`; | |
| markdown += `|------------|------|---------------|\\n`; | |
| doc.description.fields.forEach((field) => { | |
| const typeStr = this.formatFieldTypeForDoc(field.type); | |
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` |\\n`; | |
| }); | |
| markdown += `\\n`; | |
| } | |
| if (doc.sources.length > 0) { | |
| markdown += `### Source Definition\\n\\n`; | |
| markdown += `\`\`\`${doc.sources[0].encoding}\\n`; | |
| markdown += doc.sources[0].raw_file_contents; | |
| markdown += `\`\`\`\\n\\n`; | |
| } | |
| markdown += `---\\n\\n`; | |
| let markdown = `# Type Documentation for Node: ${nodeName}\n\n`; | |
| markdown += `Generated on: ${new Date().toISOString()}\n\n`; | |
| this.documentation.forEach((doc) => { | |
| markdown += `## ${doc.typeName}\n\n`; | |
| markdown += `**Topic**: \`${doc.topicName}\`\n\n`; | |
| if (doc.description.fields.length > 0) { | |
| markdown += `### Fields\n\n`; | |
| markdown += `| Field Name | Type | Default Value |\n`; | |
| markdown += `|------------|------|---------------|\n`; | |
| doc.description.fields.forEach((field) => { | |
| const typeStr = this.formatFieldTypeForDoc(field.type); | |
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` |\n`; | |
| }); | |
| markdown += `\n`; | |
| } | |
| if (doc.sources.length > 0) { | |
| markdown += `### Source Definition\n\n`; | |
| markdown += `\`\`\`${doc.sources[0].encoding}\n`; | |
| markdown += doc.sources[0].raw_file_contents; | |
| markdown += `\`\`\`\n\n`; | |
| } | |
| markdown += `---\n\n`; |
| markdown += `### Source Definition\\n\\n`; | ||
| markdown += `\`\`\`${doc.sources[0].encoding}\\n`; | ||
| markdown += doc.sources[0].raw_file_contents; | ||
| markdown += `\`\`\`\\n\\n`; |
There was a problem hiding this comment.
The escaped newline characters should be literal newlines. Replace \\n with \n.
| markdown += `\`\`\`\\n\\n`; | |
| markdown += `\`\`\`\n\n`; |
| let markdown = `# Type Documentation for Node: ${nodeName}\\n\\n`; | ||
| markdown += `Generated on: ${new Date().toISOString()}\\n\\n`; | ||
|
|
||
| this.documentation.forEach((doc) => { | ||
| markdown += `## ${doc.typeName}\\n\\n`; | ||
| markdown += `**Topic**: \`${doc.topicName}\`\\n\\n`; | ||
|
|
||
| if (doc.description.fields.length > 0) { | ||
| markdown += `### Fields\\n\\n`; | ||
| markdown += `| Field Name | Type | Default Value |\\n`; | ||
| markdown += `|------------|------|---------------|\\n`; | ||
|
|
||
| doc.description.fields.forEach((field) => { | ||
| const typeStr = this.formatFieldTypeForDoc(field.type); | ||
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` |\\n`; | ||
| }); | ||
| markdown += `\\n`; | ||
| } | ||
|
|
||
| if (doc.sources.length > 0) { | ||
| markdown += `### Source Definition\\n\\n`; | ||
| markdown += `\`\`\`${doc.sources[0].encoding}\\n`; | ||
| markdown += doc.sources[0].raw_file_contents; | ||
| markdown += `\`\`\`\\n\\n`; | ||
| } | ||
|
|
||
| markdown += `---\\n\\n`; |
There was a problem hiding this comment.
The escaped newline characters should be literal newlines. Replace \\n with \n.
| let markdown = `# Type Documentation for Node: ${nodeName}\\n\\n`; | |
| markdown += `Generated on: ${new Date().toISOString()}\\n\\n`; | |
| this.documentation.forEach((doc) => { | |
| markdown += `## ${doc.typeName}\\n\\n`; | |
| markdown += `**Topic**: \`${doc.topicName}\`\\n\\n`; | |
| if (doc.description.fields.length > 0) { | |
| markdown += `### Fields\\n\\n`; | |
| markdown += `| Field Name | Type | Default Value |\\n`; | |
| markdown += `|------------|------|---------------|\\n`; | |
| doc.description.fields.forEach((field) => { | |
| const typeStr = this.formatFieldTypeForDoc(field.type); | |
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` |\\n`; | |
| }); | |
| markdown += `\\n`; | |
| } | |
| if (doc.sources.length > 0) { | |
| markdown += `### Source Definition\\n\\n`; | |
| markdown += `\`\`\`${doc.sources[0].encoding}\\n`; | |
| markdown += doc.sources[0].raw_file_contents; | |
| markdown += `\`\`\`\\n\\n`; | |
| } | |
| markdown += `---\\n\\n`; | |
| let markdown = `# Type Documentation for Node: ${nodeName} | |
| `; | |
| markdown += `Generated on: ${new Date().toISOString()} | |
| `; | |
| this.documentation.forEach((doc) => { | |
| markdown += `## ${doc.typeName} | |
| `; | |
| markdown += `**Topic**: \`${doc.topicName}\` | |
| `; | |
| if (doc.description.fields.length > 0) { | |
| markdown += `### Fields | |
| `; | |
| markdown += `| Field Name | Type | Default Value | | |
| `; | |
| markdown += `|------------|------|---------------| | |
| `; | |
| doc.description.fields.forEach((field) => { | |
| const typeStr = this.formatFieldTypeForDoc(field.type); | |
| markdown += `| \`${field.name}\` | ${typeStr} | \`${field.default_value || 'N/A'}\` | | |
| `; | |
| }); | |
| markdown += ` | |
| `; | |
| } | |
| if (doc.sources.length > 0) { | |
| markdown += `### Source Definition | |
| `; | |
| markdown += `\`\`\`${doc.sources[0].encoding} | |
| `; | |
| markdown += doc.sources[0].raw_file_contents; | |
| markdown += `\`\`\` | |
| `; | |
| } | |
| markdown += `--- | |
| `; |
| console.log('\\n=== Type Hierarchy ==='); | ||
| this.typeHierarchy.forEach((typeInfo, typeName) => { | ||
| console.log(`\\n${typeName}:`); |
There was a problem hiding this comment.
The escaped newline character should be a literal newline. Replace \\n with \n.
| console.log('\\n=== Type Hierarchy ==='); | |
| this.typeHierarchy.forEach((typeInfo, typeName) => { | |
| console.log(`\\n${typeName}:`); | |
| console.log('\n=== Type Hierarchy ==='); | |
| this.typeHierarchy.forEach((typeInfo, typeName) => { | |
| console.log(`\n${typeName}:`); |
| console.log('\\n=== Type Hierarchy ==='); | ||
| this.typeHierarchy.forEach((typeInfo, typeName) => { | ||
| console.log(`\\n${typeName}:`); |
There was a problem hiding this comment.
The escaped newline character should be a literal newline. Replace \\n with \n.
| console.log('\\n=== Type Hierarchy ==='); | |
| this.typeHierarchy.forEach((typeInfo, typeName) => { | |
| console.log(`\\n${typeName}:`); | |
| console.log('\n=== Type Hierarchy ==='); | |
| this.typeHierarchy.forEach((typeInfo, typeName) => { | |
| console.log(`\n${typeName}:`); |
| const minTime = Math.min(...this.queryTimes); | ||
| const maxTime = Math.max(...this.queryTimes); | ||
|
|
||
| console.log('\\n=== Performance Results ==='); |
There was a problem hiding this comment.
The escaped newline character should be a literal newline. Replace \\n with \n.
| console.log('\\n=== Performance Results ==='); | |
| console.log('\n=== Performance Results ==='); |
This PR adds a comprehensive tutorial for the Type Description Service feature in rclnodejs. The tutorial provides detailed documentation on how to use the built-in ROS 2 introspection service that allows querying message and service type information from running nodes. Key changes: - Complete tutorial covering Type Description Service functionality, requirements, and usage patterns - Multiple practical examples demonstrating basic usage, advanced features, and best practices - Comprehensive troubleshooting guide and performance considerations Fix: #1267
This PR adds a comprehensive tutorial for the Type Description Service feature in rclnodejs. The tutorial provides detailed documentation on how to use the built-in ROS 2 introspection service that allows querying message and service type information from running nodes.
Key changes:
Fix: #1267