## For instruction on writing tutorials ## http://www.ros.org/wiki/WritingTutorials #################################### ##FILL ME IN #################################### ## for a custom note with links: ## note = ## for the canned note of "This tutorial assumes that you have completed the previous tutorials:" just add the links ## note.0= ## descriptive title for the tutorial ## title = How to register and publish variables ## multi-line description to be displayed in search ## description = How to register and publish variables ## the next tutorial description (optional) ## next = ## links to next tutorial (optional) ## next.0.link= [[pal_statistics/Tutorials/Aggregate, store and visualise statistics]] ## next.1.link= ## what level user is this tutorial for ## level= IntermediateCategory ## keywords = pal_statistics, logging #################################### <> <> = Registration C++ = == The Code == The following example shows how to register and publish a temperature reading. {{{ #!cplusplus block=temperature_example #include void do_monitor_temperature() { double temperature; pal_statistics::RegistrationsRAII registrations; REGISTER_VARIABLE("/statistics_topic", "motor temperature", &temperature, ®istrations); while (ros::ok()) { temperature = read_temperature(); ros::Duration(0.1).sleep(); PUBLISH_STATISTICS("/statistics_topic"); } //Unregister variable UNREGISTER_VARIABLE("/statistics_topic", "motor temperature"); } }}} == The Code Explained == Now, let's break down the code piece by piece. <> To log a variable, it must be registered with a name to a topic, the address of the variable must be provided. When asked to publish all registered variables, their address will be accessed and and their values updated. <> This part of the code modifies the variable we have registered, and publishes them periodically. If the topic name is changed, it will attempt to publish variables registered to the new topic name, which will not include "motor temperature" <> Unregister the variable, '''this is critical'''. If a variable is destroyed, but it has not been unregistered, it may be attempted to read, which in the worst case scenario will cause a segmentation fault. = Automatic Unregister C++ = == The Code == Following on the previous example, we'll see how to have automatic unregistration when going out of scope. This is the recommended way of using pal_statistics, in the same way smart pointers are preferred over old C-style pointers. {{{ #!cplusplus block=temperature_example_raii #include void do_monitor_temperature() { double temperature; RegistrationsRAII registrations; REGISTER_VARIABLE("/statistics_topic", "motor temperature", &temperature, ®istrations); while (ros::ok()) { temperature = read_temperature(); ros::Duration(0.1).sleep(); PUBLISH_STATISTICS("/statistics_topic"); } //Unregister is automatic when registrations goes out of scope } }}} == The Code Explained == Now, let's break down the code piece by piece. <> We declare an object of type {{{RegistrationsRAII}}} after the declaration of our variables. This object when provided to the {{{REGISTER_VARIABLE}}} macro, will keep track of the registration done. When it is destroyed, it will unregister all variables associated to it. By declaring it after our variables, we ensure that it will be destroyed before the variables. = Advanced Registration C++ = == Non double variables == Any variable that can be cast to a double is suitable for registration. {{{ #!cplusplus block=temperature_example_raii unsigned int uint_variable = 0; bool bool_variable = false; RegistrationsRAII registrations; REGISTER_VARIABLE("/statistics_topic", "uint_variable", &uint_variable, ®istrations); REGISTER_VARIABLE("/statistics_topic", "bool_variable", &bool_variable, ®istrations); }}} == Registering functions == You can also register a function to be called: {{{ #!cplusplus std::vector container; REGISTER_VARIABLE("/statistics_topic", "container_size", boost::function(boost::bind(&std::vector::size, &container))); }}} As well as a lambda expression: {{{ #!cplusplus REGISTER_VARIABLE("/statistics_topic", "lambda_magic", boost::function([]() { return lambda_magic(); })); }}} = Real Time Usage = This framework has been designed for realtime operation. The following actions are RT safe (no memory allocs, waits, or other blocking or undeterministic behavior). * Publishing (using {{{PUBLISH_ASYNC_STATISTICS}}}) * Enable a variable * Disable a variable Everything else is not RT safe, but for completeness: * Register a variable * Unregister a variable * Start publish thread * Publish without using {{{PUBLISH_ASYNC_STATISTICS}}} == Real Time usage example == {{{ #!cplusplus block=temperature_example_raii #include void do_monitor_temperature() { // Initialization. Non RT Safe code double temperature; RegistrationsRAII registrations; REGISTER_VARIABLE("/statistics_topic", "motor temperature", &temperature, ®istrations); START_PUBLISH_THREAD("/statistics_topic"); // Main loop. RT Safe code only while (ros::ok()) { temperature = read_temperature(); PUBLISH_ASYNC_STATISTICS("/statistics_topic"); } } }}} Each call to {{{PUBLISH_ASYNC_STATISTICS}}} reads the value of the registered variables and passes it to the publish thread without blocking, the publish thread which will then wake up and publish all the data that hasn't been published yet. == Enable/Disable variable == This is an advanced feature, allowing a soft unregistration in a RT-safe way. Look at the code documentation for more information. = Python API = The Python API is more limited due to language constraints, and since it doesn't have to deal with Real Time issues. == Registering variables == {{{ #!python from pal_statistics import StatisticsRegistry # Create Registry for a topic registry = StatisticsRegistry("/statistics_topic") var1 = 123 registry.registerFunction("var1", (lambda: var1)) }}} Notice that in Python, there's no {{{registerVariable}}} method, because python will copy the value of variables of simple types such as numbers. Therefore we have to use a lambda to read the value of the address at a later time. It can still be used to register full functions that return some value: {{{ #!python registerFunction("my_function", self.my_function) }}} == Publishing registered variables == {{{ #!python registry.publish() }}} == Unregistering registered variables == {{{ registry.unregister("var1") }}} Also, when a registry is destroyed, the variables are automatically unregistered. ## AUTOGENERATED DO NOT DELETE ## TutorialCategory ## FILL IN THE STACK TUTORIAL CATEGORY HERE