ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Could I introduce multiple subscribers in the diff_drive_controller plugin to gather this extra data from the ROS side?

I would not try to fudge this into the diff_drive_controller.

In the end, ros_control is a resource management framework. The job of the controller manager, together with the hardware_interface is to make sure no two plugins claim the same resources at the same time. In most cases, concurrent read is OK, but concurrent write is not. Typical examples of such plugins are the controllers in ros_controllers, which implement the type of controllers most people think of when hearing the words "control" (ie: PID and similar concepts from Control Engineering).

This additional data may not really make sense to be represented in the joint space so I’m unsure if a custom hardware interface such as the ones written for force-torque sensors, IMUs etc might make sense here.

It's actually perfectly fine to have your hardware_interface make resources available which do not fall in that category (and which are probably not "in the joint space" (whatever you mean by that)), but which are to be used to communicate different kinds of abstractions between the ROS / ros_control side and whatever representations the underlying hardware is comfortable with.

So you could do the following:

  • define ROS-agnostic data structures to encode the types of information you'd like to exchange between your ROS application and the external hw
  • come up with a "resource" which would naturally be the one maintaining/holding onto/owning instances of those data structures (so a "Cartesian frame resource" could be responsible for maintaining a list of Cartesian coordinat frames which can be read/written from/to the underlying hw). This is really just to be able to reason about your abstraction. You could introduce a "PLC resource", but I would probably go for something a bit more fine-grained, and more abstract (there is no reason any of the data you describe has to come from a PLC for instance)
  • add *Interface and *Handle pairs for those resources (this is ros_control specific, look at the various implementations available in ros_control already)
  • implement the necessary infrastructure to your hardware_interface and expose it using the *Interface and *Handle you've defined earlier (so add a way for your hardware_interface to read/write the list of Cartesian frames from/to your PLC and update whatever internal data structure you use to store that inside the hardware_interface)
  • write controllers which claim the newly added Interfaces to get access to the data structures inside the hardware_interface and which use Publishers and Subscribers to provide access to those resources (but in a real-time safe way, refer to the existing controllers to see how that can be done). These are of course not necessarily really "controllers", but that's just ros_control nomenclature
  • update your controller configuration (probably a .yaml file somewhere) to load the controllers you've written, making sure to provide them with the configuration they need

At this point you have a hardware_interface which loads the diff_drive_controller and in addition a bunch of other controllers (really: plugins) which together expose an interface to the resources of your PLC (which would include actuators, sensors and other types of (derived) data).

Those controllers together expose a set of topics (and/or services and actions) which allow your ROS application access to the resources of your PLC (and if you'd want to, the other way around).

Some advantages of doing it this way:

  1. locality of changes: the interfaces, handles and messages/services/actions for a particular resource are all self-contained, and changes to them do not necessarily have to affect your hardware_interface
  2. separation of concerns: the controllers are responsible for providing a ROS interface to the resources of your remote hw. The hardware_interface is responsible for communication with the hw itself
  3. extensibility: to expose additional resources, implement additional plugins when needed (for new resource types), or instantiate additional controllers (for existing types)
  4. configurability: don't want/need to expose resource type X? Simply don't load the controller
  5. reusability: happen to have a hardware_interface which doesn't talk to a PLC, but is capable of exposing the same Interface? You can now reuse the plugin/controller you wrote earlier

There are a few more, but these are the bigger ones.

How do I go about achieving this in a way that can be easily extended for newer data that I might want to send to the hardware (PLC)?

This should now be obvious: by creating more plugins (ie: controllers).

[..] am I over complicating this?

Well, adding abstractions tends to increase complexity (almost paradoxical this statement), and if you look at the nr of steps I listed to add the infrastructure to your hardware_interfacewhich would "properly" expose the additional information you want from your PLC, you could say it's a bit convoluted.

In the end however I believe the benefits outweigh the costs, and experience also tells me it's worth the initial investment (adding support for new data types typically comes down to copy-paste almost). Especially re-use of controller plugins is a really nice way to end up with a flexible system, and the almost stand-alone nature of those plugins makes them relatively easy to manage and test as well.

Could I introduce multiple subscribers in the diff_drive_controller plugin to gather this extra data from the ROS side?

I would not try to fudge this into the diff_drive_controller.

That would make no sense to me: diff_drive_controller has a very narrowly defined scope and responsibility. Would it make sense for it to know/have to deal with the current waypoint or the goal status?

Now I plan to send some extra information to the PLC, such as current waypoint, pose, goal status etc as part of the “telegram” (in the Write method). [..]. This information is internally published on various topics from different nodes and has to be inserted into the PC-PLC real time communication.

In the end, ros_control is a resource management framework. The job of the controller manager, together with the hardware_interface is to make sure no two plugins claim the same resources at the same time. In most cases, concurrent read is OK, but concurrent write is not. Typical examples of such plugins are the controllers in ros_controllers, which implement the type of controllers most people think of when hearing the words "control" (ie: PID and similar concepts from Control Engineering).

This additional data may not really make sense to be represented in the joint space so I’m unsure if a custom hardware interface such as the ones written for force-torque sensors, IMUs etc might make sense here.

It's actually perfectly fine to have your hardware_interface make resources available which do not fall in that category (and which are probably not "in the joint space" (whatever you mean by that)), but which are to be used to communicate different kinds of abstractions between the ROS / ros_control side and whatever representations the underlying hardware is comfortable with.

So you could do the following:

  • define ROS-agnostic data structures to encode the types of information you'd like to exchange between your ROS application and the external hw
  • come up with a "resource" which would naturally be the one maintaining/holding onto/owning instances of those data structures (so (example: a "Cartesian frame resource" could be responsible for maintaining a list of Cartesian coordinat coordinate frames which can be read/written from/to the underlying hw). This is really just to be able to reason about your abstraction. You could introduce a "PLC resource", but I would probably go for something a bit more fine-grained, and more abstract (there is no reason any of the data you describe has to come from a PLC for instance)
  • add *Interface and *Handle pairs for those resources (this is ros_control specific, look at the various implementations available in ros_control already)
  • implement add the necessary infrastructure to your hardware_interface and expose it using the *Interface and *Handle you've defined earlier (so add a way for your hardware_interface to read/write the list of Cartesian frames from/to your PLC and update whatever internal data structure you use to store that inside the hardware_interface)
  • write controllers which claim the newly added InterfaceHandles to get access to the data structures inside the hardware_interface and which use Publishers and Subscribers to provide access to those resources (but in a real-time safe way, refer to the existing controllers to see how that can be done). These are of course not necessarily really "controllers", but that's just ros_control nomenclature
  • update your controller configuration (probably a .yaml file somewhere) to load the controllers you've written, making sure to provide them with the configuration they need

At this point you have a hardware_interface which loads the diff_drive_controller and in addition a bunch of other controllers (really: plugins) which together expose an interface to the resources of your PLC (which would include actuators, sensors and other types of (derived) data).

Those controllers together expose a set of topics (and/or services and actions) which allow your ROS application access to the resources of your PLC (and if you'd want to, the other way around).

Some advantages of doing it this way:

  1. locality of changes: the interfaces, handles and messages/services/actions for a particular resource are all self-contained, and changes to them do not necessarily have to affect your hardware_interface
  2. separation of concerns: the controllers are responsible for providing a ROS interface to the resources of your remote hw. The hardware_interface is responsible for communication with the hw itself
  3. extensibility: to expose additional resources, implement additional plugins when needed (for new resource types), or instantiate additional controllers (for existing types)
  4. configurability: don't want/need to expose resource type X? Simply don't load the controller
  5. reusability: happen to have a hardware_interface which doesn't talk to a PLC, but is capable of exposing the same Interface? You can now reuse the plugin/controller you wrote earlier

There are a few more, but these are the bigger ones.

How do I go about achieving this in a way that can be easily extended for newer data that I might want to send to the hardware (PLC)?

This should now be obvious: by creating more plugins (ie: controllers).

[..] am I over complicating this?

Well, adding abstractions tends to increase complexity (almost paradoxical this statement), and if you look at the nr of steps I listed to add the infrastructure to your hardware_interfacewhich would "properly" expose the additional information you want from your PLC, you could say it's a bit convoluted.

In the end however I believe the benefits outweigh the costs, and experience also tells me it's worth the initial investment (adding support for new data types typically comes down to copy-paste almost). Especially re-use of controller plugins is a really nice way to end up with a flexible system, and the almost stand-alone nature of those plugins makes them relatively easy to manage and test as well.

Could I introduce multiple subscribers in the diff_drive_controller plugin to gather this extra data from the ROS side?

I would not try to fudge this into the diff_drive_controller.

That would make no sense to me: diff_drive_controller has a very narrowly defined scope and responsibility. Would it make sense for it to know/have to deal with the current waypoint or the goal status?

Now I plan to send some extra information to the PLC, such as current waypoint, pose, goal status etc as part of the “telegram” (in the Write method). [..]. This information is internally published on various topics from different nodes and has to be inserted into the PC-PLC real time communication.

In the end, ros_control is a resource management framework. The job of the controller manager, together with the hardware_interface is to make sure no two plugins claim the same resources at the same time. In most cases, concurrent read is OK, but concurrent write is not. Typical examples of such plugins are the controllers in ros_controllers, which implement the type of controllers most people think of when hearing the words "control" (ie: PID and similar concepts from Control Engineering).Engineering). But there is nothing which limits ros_control controllers to those kinds of controllers.

This additional data may not really make sense to be represented in the joint space so I’m unsure if a custom hardware interface such as the ones written for force-torque sensors, IMUs etc might make sense here.

It's actually perfectly fine to have your hardware_interface make resources available which do not fall in that category (and which are probably not "in the joint space" (whatever you mean by that)), but which are to be used to communicate different kinds of abstractions between the ROS / ros_control side and whatever representations the underlying hardware is comfortable with.

So you could do the following:

  • define ROS-agnostic data structures to encode the types of information you'd like to exchange between your ROS application and the external hw
  • come up with a "resource" which would naturally be the one maintaining/holding onto/owning instances of those data structures (example: a "Cartesian frame resource" could be responsible for maintaining a list of Cartesian coordinate frames which can be read/written from/to the underlying hw). This is really just to be able to reason about your abstraction. You could introduce a "PLC resource", but I would probably go for something a bit more fine-grained, and more abstract (there is no reason any of the data you describe has to come from a PLC for instance)
  • add *Interface and *Handle pairs for those resources (this is ros_control specific, look at the various implementations available in ros_control already)
  • add the necessary infrastructure to your hardware_interface and expose it using the *Interface and *Handle you've defined earlier (so add a way for your hardware_interface to read/write the list of Cartesian frames from/to your PLC and update whatever internal data structure you use to store that inside the hardware_interface)
  • write controllers which claim the newly added Handles to get access to the data structures inside the hardware_interface and which use Publishers and Subscribers to provide access to those resources (but in a real-time safe way, refer to the existing controllers to see how that can be done). These are of course not necessarily really "controllers", but that's just ros_control nomenclature
  • update your controller configuration (probably a .yaml file somewhere) to load the controllers you've written, making sure to provide them with the configuration they need

At this point you have a hardware_interface which loads the diff_drive_controller and in addition a bunch of other controllers (really: plugins) which together expose an interface to the resources of your PLC (which would include actuators, sensors and other types of (derived) data).

Those controllers together expose a set of topics (and/or services and actions) which allow your ROS application access to the resources of your PLC (and if you'd want to, the other way around).

Some advantages of doing it this way:

  1. locality of changes: the interfaces, handles and messages/services/actions for a particular resource are all self-contained, and changes to them do not necessarily have to affect your hardware_interface
  2. separation of concerns: the controllers are responsible for providing a ROS interface to the resources of your remote hw. The hardware_interface is responsible for communication with the hw itself
  3. extensibility: to expose additional resources, implement additional plugins when needed (for new resource types), or instantiate additional controllers (for existing types)
  4. configurability: don't want/need to expose resource type X? Simply don't load the controller
  5. reusability: happen to have a hardware_interface which doesn't talk to a PLC, but is capable of exposing the same Interface? You can now reuse the plugin/controller you wrote earlier

There are a few more, but these are the bigger ones.

How do I go about achieving this in a way that can be easily extended for newer data that I might want to send to the hardware (PLC)?

This should now be obvious: by creating more plugins (ie: controllers).

[..] am I over complicating this?

Well, adding abstractions tends to increase complexity (almost paradoxical this statement), and if you look at the nr of steps I listed to add the infrastructure to your hardware_interfacewhich would "properly" expose the additional information you want from your PLC, you could say it's a bit convoluted.

In the end however I believe the benefits outweigh the costs, and experience also tells me it's worth the initial investment (adding support for new data types typically comes down to copy-paste almost). Especially re-use of controller plugins is a really nice way to end up with a flexible system, and the almost stand-alone nature of those plugins makes them relatively easy to manage and test as well.

Could I introduce multiple subscribers in the diff_drive_controller plugin to gather this extra data from the ROS side?

I would not try to fudge this into the diff_drive_controller.

That would make no sense to me: diff_drive_controller has a very narrowly defined scope and responsibility. Would it make sense for it to know/have to deal with the current waypoint or the goal status?

Now I plan to send some extra information to the PLC, such as current waypoint, pose, goal status etc as part of the “telegram” (in the Write method). [..]. This information is internally published on various topics from different nodes and has to be inserted into the PC-PLC real time communication.

In the end, ros_control is a resource management framework. The job of the controller manager, together with the hardware_interface is to make sure no two plugins claim the same resources at the same time. In most cases, concurrent read is OK, but concurrent write is not. Typical examples of such plugins are the controllers in ros_controllers, which implement the type of controllers most people think of when hearing the words "control" (ie: PID and similar concepts from Control Engineering). But there is nothing which limits ros_control controllers to those kinds of controllers.

This additional data may not really make sense to be represented in the joint space so I’m unsure if a custom hardware interface such as the ones written for force-torque sensors, IMUs etc might make sense here.

It's actually perfectly fine to have your hardware_interface make resources available which do not fall in that category (and which are probably not "in the joint space" (whatever you mean by that)), but which are to be used to communicate different kinds of abstractions between the ROS / ros_control side and whatever representations the underlying hardware is comfortable with.

So you could do the following:

  • define ROS-agnostic data structures to encode the types of information you'd like to exchange between your ROS application and the external hw
  • come up with a "resource" which would naturally be the one maintaining/holding onto/owning instances of those data structures (example: a "Cartesian frame resource" could be responsible for maintaining a list of Cartesian coordinate frames which can be read/written from/to the underlying hw). This is really just to be able to reason about your abstraction. You could introduce a "PLC resource", but I would probably go for something a bit more fine-grained, and more abstract (there is no reason any of the data you describe has to come from a PLC for instance)
  • add *Interface and *Handle pairs for those resources (this is ros_control specific, look at the various implementations available in ros_control already)
  • add the necessary infrastructure to your hardware_interface and expose it using the *Interface and *Handle you've defined earlier (so add a way for your hardware_interface to read/write the list of Cartesian frames from/to your PLC and update whatever internal data structure you use to store that inside the hardware_interface)
  • write controllers which claim the newly added Handles to get access to the data structures inside the hardware_interface and which use Publishers and Subscribers to provide access to those resources (but in a real-time safe way, refer to the existing controllers to see how that can be done). These are of course not necessarily really "controllers", but that's just ros_control nomenclature
  • update your controller configuration (probably a .yaml file somewhere) to load the controllers you've written, making sure to provide them with the configuration they need

At this point you have a hardware_interface which loads the diff_drive_controller and in addition a bunch of other controllers (really: plugins) which together expose an interface to the resources of your PLC (which would include actuators, sensors and other types of (derived) data).

Those controllers together expose a set of topics (and/or services and actions) which allow your ROS application access to the resources of your PLC (and if you'd want to, the other way around).

Some advantages of doing it this way:

  1. locality of changes: the interfaces, handles and messages/services/actions for a particular resource are all self-contained, and changes to them do not necessarily have to affect your hardware_interface
  2. separation of concerns: the controllers are responsible for providing a ROS interface to the resources of your remote hw. The hardware_interface is responsible for communication with the hw itself
  3. extensibility: to expose additional resources, implement additional plugins when needed (for new resource types), or instantiate additional controllers (for existing types)
  4. configurability: don't want/need to expose resource type X? Simply don't load the controller
  5. reusability: happen to have a hardware_interface which doesn't talk to a PLC, but is capable of exposing the same Interface? You can now reuse the plugin/controller you wrote earlier

There are a few more, but these are the bigger ones.

How do I go about achieving this in a way that can be easily extended for newer data that I might want to send to the hardware (PLC)?

This should now be obvious: by adding additional *Interface and *Handle classes, adding support for those to your hardware_interface and then creating more plugins (ie: controllers).controllers). But only if needed: if you already have a controller which is capable of working with the resource you'd like to expose, you wouldn't need a new one of course.

[..] am I over complicating this?

Well, adding abstractions tends to increase complexity (almost paradoxical this statement), and if you look at the nr of steps I listed to add the infrastructure to your hardware_interfacewhich would "properly" expose the additional information you want from your PLC, you could say it's a bit convoluted.

In the end however I believe the benefits outweigh the costs, and experience also tells me it's worth the initial investment (adding support for new data types typically comes down to copy-paste almost). Especially re-use of controller plugins is a really nice way to end up with a flexible system, and the almost stand-alone nature of those plugins makes them relatively easy to manage and test as well.