boschresearch / fmi_adapter

Integrating functional mock-up units (FMUs) in ROS nodes
Apache License 2.0
46 stars 14 forks source link

Query simulation clock #3

Open githubfrond opened 4 years ago

githubfrond commented 4 years ago

Apologies Dr/Mr Lange, I am only new to GitHub and unsure how to communicate best with you. This is more of a feature suggestion than an issue. I hope I am not being too presumptuous by making suggestions. Feel free to ignore me :-) regards, Craig

Do your libraries include a facility to drive the /clock topic when the launch file sets the simulation parameter ?

If not, I can teach myself how to manually do this, but it would seem a natural extension to your library might be a modelica based facility that would allow this. This facility could allow one to execute the FMU's in faster/slower than real time for testing purposes, without the developer having to know how to construct an external ROS Clock Server.

ralph-lange commented 4 years ago

Hi Craig, just call me Ralph, please. Opening an issue for such a feature request is absolutely fine. Just to recap, to ensure that we have the same understanding:

Extending the fmi_adapter library and node with a function to run the simulation time is fairly easy. I regularly speed up the clock in my unit-tests:

std::shared_ptr<std::thread> runner(new std::thread([&enabledFlag]() {
  const ros::Duration SIM_STEP(0.010);
  const double SIM_SPEED = 5;  // 5x faster than real-time
  while (enabledFlag) {
    std::this_thread::sleep_for(
        std::chrono::nanoseconds(static_cast<std::int64_t>(SIM_STEP.nsec / SIM_SPEED)));
    ros::Time::setNow(ros::Time::now() + SIM_STEP);
  }
}));

I'm hesitating to put such functionality directly in the fmi_adapter library and node. As explained above, the library has no built-in functionality to trigger the simulation steps at all. The fmi_adapter node has such functionality, but for separation of concerns, I would place it in a separate node of the fmi_adapter package. Of course, I may provide a launch file that starts both nodes together. What do you think about this architecture? Best regards, Ralph

ralph-lange commented 4 years ago

@githubfrond, a question about your use-case: Is the FMI-based simulation dominating the computing time, i.e. should be simulation time be slowed down depending on the FMI-based simulation? In this case if fully agree with you that the simulation clock (topic /clock) should be published directly from the fmi_adapter node and not be factored out in a separate node.

githubfrond commented 4 years ago

Hi Ralph, that seems like a perfect approach. That would also provide example code to those interested in doing anything more complicated. Unfortunately the ROS website itself has only disjointed information about clocks, so such sample code would be useful. Thank you for the link, and all your feedback.

While researching this topic I came across an interesting comment though. The author was looking for a method for each FMU to indicate it had finished updating it's outputs for the current time step. The idea being that the publisher to the clock could watch these signals from all FMUs, and only increment the clock once all FMUs indicate completion. What are your thoughts about this concept?

I hope you and those close to you are well. Thanks for all your feedback, and the excellent adapter. Looking forward to developments. Best regards, Craig

On Thursday, March 19, 2020, Ralph Lange notifications@github.com wrote:

Hi Craig, just call me Ralph, please. Opening an issue for such a feature request is absolutely fine. Just to recap, to ensure that we have the same understanding:

  • When using the fmi_adapter library only (i.e. the class fmi_adapter::FMIAdapter from include/fmi_adapter/FMIAdapter.h), you’ll have to trigger the simulation steps from your application code. In this case, you have full control over the simulation speed.
  • When using the fmi_adapter node (see src/fmi_adapter_node.cpp), the simulation is triggered automatically using a normal ROS timer ( http://wiki.ros.org/roscpp/Overview/Timers http://wiki.ros.org/roscpp/Overview/Timers). The step-size can be adjusted by the parameter update_period. The ROS Timer uses the ROS Clock, from /clock, when available. Hence, the fmi_adapter node will automatically run according to simulation time.

Extending the fmi_adapter library and node with a function to run the simulation time is fairly easy. I regularly speed up the clock in my unit-tests:

std::shared_ptr runner(new std::thread([&enabledFlag]() {

const ros::Duration SIM_STEP(0.010);

const double SIM_SPEED = 5; // 5x faster than real-time

while (enabledFlag) {

std::this_thread::sleep_for(

    std::chrono::nanoseconds(static_cast<std::int64_t>(SIM_STEP.nsec / SIM_SPEED)));

ros::Time::setNow(ros::Time::now() + SIM_STEP);

}

}));

I'm hesitating to put such functionality directly in the fmi_adapter library and node. As explained above, the library has no built-in functionality to trigger the simulation steps at all. The fmi_adapter node has such functionality, but for separation of concerns, I would place it in a separate node of the fmi_adapter package. Of course, I may provide a launch file that starts both nodes together. What do you think about this architecture? Best regards, Ralph

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/boschresearch/fmi_adapter/issues/3#issuecomment-601029856, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOZMFLHPXQ3OS3D6ZFKL24TRIHDCXANCNFSM4LO6GBGA .

githubfrond commented 4 years ago

Hi Ralph, in answer to your query, I am looking at using ROS in a rather unusual way. I am modelling a system that is comprised of various conceptually separate subsystems, each of which I can model individually. I'm using ROS to interconnect the different subsystem models in the overall system model, and this allows me to easily assemble subsystems, switch out different compments, or simply switch off/on different components without having to re-architect the overall model. Hence, at this stage, all of my work is in simulation time...no wallclocks.

githubfrond commented 4 years ago

Hi Ralph, I have created two launch files now, similar to your suggestion. One in Python with /use_sim_time FALSE which picks up the wall clock and accelerates time to push into the /clock topic, and the second is my collection of FMU built from your adapater tools and connected up with /use_sim_time TRUE so that they respond to the /clock. Now I am trying to learn how to adjust both ROS normal update period, as well as how to suitably adjust the step sizes used natively by the FMU. I'll let you know if I have trouble understanding the documentation. Thanks for your patience. Craig

ralph-lange commented 4 years ago

Hi Craig, I created a super-simple node named sim_clock_node, which runs the given FMU at maximum speed and advances the ROS time on /clock accordingly. Please find it in the branch prototype/sim_clock_node at https://github.com/boschresearch/fmi_adapter/blob/prototype/sim_clock_node/fmi_adapter/src/fmi_adapter_sim_clock_node.cpp. The implementation does not provide any mechanisms to synchronize or wait for other fmi_adapter nodes or normal ROS nodes. A good solution for such synchronization should consider dependencies between the different FMUs, potential cycles, different step sizes, and many more aspects. That's exactly the task of a master algorithm according to the FMI standard. For the use-case of simulating multiple subsystems together, it might be useful to look into relevant FMI tools or frameworks before building a similar framework based on ROS from scratch. (Please note that the FMI standard does not define the master algorithm itself, but only the interface between an FMU and any master algorithm.)