Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | jazzy |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | kilted |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file
CONTRIBUTING
Repository Summary
| Checkout URI | https://github.com/nineyards-robotics/jig.git |
| VCS Type | git |
| VCS Version | humble |
| Last Updated | 2026-03-28 |
| Dev Status | MAINTAINED |
| Released | UNRELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Packages
| Name | Version |
|---|---|
| jig | 0.0.0 |
| jig_example | 0.0.0 |
README
jig
Declarative ROS 2 node scaffolding with built-in best practice
Jig transforms simple YAML interface definitions into strongly-typed C++ and Python ROS 2 lifecycle node scaffolding. Define your publishers, subscribers, services, actions and parameters in one simple file and Jig will handle the rest.
Quick Start
Jig uses a convention-over-configuration approach with automatic build system integration. Here’s how to create a complete ROS 2 package in minutes:
1. Create Package Structure
Your package should follow this structure:
my_package/
├── nodes/
│ └── my_node/
│ ├── interface.yaml # Interface definition
│ ├── my_node.hpp # Header (C++ only)
│ └── my_node.cpp # Implementation (.cpp for C++, .py for Python)
├── CMakeLists.txt
└── package.xml
2. Define Your Node Interface
Create nodes/my_node/interface.yaml:
parameters:
important_parameter:
type: string
default_value: "oh hi mark"
description: "A very important string."
publishers:
- topic: some_topic
type: std_msgs/msg/String
qos:
history: 10
reliability: RELIABLE
subscribers:
- topic: other_topic
type: std_msgs/msg/Bool
qos:
history: 5
reliability: BEST_EFFORT
services:
- name: my_service
type: example_interfaces/srv/AddTwoInts
3. Implement Your Node
C++ Example
First, create the header (nodes/my_node/my_node.hpp):
Design Pattern: Jig uses a lifecycle
Sessionclass rather than subclassingrclcpp_lifecycle::LifecycleNode. This separation makes testing easier (you can test logic without spinning up ROS), keeps state explicit, and allows callbacks to be simple free functions. TheSessionis created during theon_configurelifecycle transition and destroyed oncleanup/shutdown. To define theSessionof your node, you subclass the auto-generated<NodeName>Sessionstruct and add your own variables to it. The auto-generatedSessionclass will contain a reference to the lifecycle node instance, as well as all publishers, subscribers, services, actions and parameters.
#pragma once
#include <memory>
#include <my_package/my_node_interface.hpp>
namespace my_package::my_node {
// Extend the generated session with custom state
struct Session : MyNodeSession<Session> {
using MyNodeSession::MyNodeSession;
// Add any custom state here
int my_counter = 0;
};
// Forward declare on_configure function
CallbackReturn on_configure(std::shared_ptr<Session> sn);
// Define the node class using the generated base
// This must match the pattern: package::node_name::NodeName
using MyNode = MyNodeBase<Session, on_configure>;
} // namespace my_package::my_node
Then implement it (nodes/my_node/my_node.cpp):
Design Pattern: Jig uses a free function
on_configure()approach instead of subclassingrclcpp_lifecycle::LifecycleNode. Theon_configure()function receives a fully-constructed session with all publishers, subscribers, and parameters ready to use. This functional approach, coupled with the session object, makes nodes easier to reason about, simpler to write and more testable. By storing a reference to the lifecycle node in the session, we create a “has-a” relationship with the Node rather than “is-a”, cleanly separating ROS communication from your implementation logic.
```cpp #include “my_node.hpp”
namespace my_package::my_node {
void msg_callback(std::shared_ptr
File truncated at 100 lines see the full file