Although this repository is integrated within VisLab's projects, it holds the result of my (Miguel Aragão) master thesis.
The main goal of the yarp-bottle-generator is for it to be able to generate code that gets data from several sources (YARP ports or ROS topics) and builds a bottle to be sent to some specific ROS topic or YARP port.
The final user will only have to customize a configuration file according to his needs.
For now there are 3 main structures that the user can customize: the multiplexers (i.e. hubs), the converters and the output builder (described in a ROS message style). Please read the documentation on how to customize your own configuration file in order to understand how they work and what you can achieve with them.
The repository has two major dependencies:
The code was written in C++ so any environment able to compile it (and compatible with the dependencies) should be fine.
Open a terminal:
cd /path/to/destination/folder git clone https://github.com/vislab-tecnico-lisboa/yarp-bottle-generator.git
In order to run the generator you'll need to export the $BOTTLE_GENERATOR_DIR. Add the export to a script or execute it each time you want to run the generator:
export BOTTLE_GENERATOR_DIR = /path/to/destination/folder/yarp-bottle-generator
Open a terminal:
cd $BOTTLE_GENERATOR_DIR mkdir build cd build cmake .. make
Optionally you can copy the executable to your bin folder (and be able to run it from everywhere):
sudo make install
Open a terminal:
yarpBottleGenerator
in order to see the command arguments:
args: [0]: configuration file name [1]: generated code file name
In case you didn't run sudo make install
you might need to run the last command from your build folder:
cd $BOTTLE_GENERATOR_DIR/build ./yarpBottleGenerator <configuration file> <filename_generated_code.cpp>
The configuration file must be located in the app folder of the repository, and the generated code will be located in a folder inside the results folder of the repository. The filename of the generated code should have the .cpp extension.
Open a terminal:
cd $BOTTLE_GENERATOR_DIR/results/<filename_generated_code> mkdir build cd build cmake .. make
That's it! In case you didn't change the generated code yourself this should compile with no errors. Please open an issue in case you are having problems compiling unchanged generated code.
Feel free to edit the code to add some extra functionality at your own risk. Please open an issue if you think those changes should be automated to other users. I'll be available to help you with any doubts and problems.
Don't forget this is a YARP executable so you'll need to have a yarpserver
running in order to run the code and if you are interacting with ROS, the runtime converter yarpidl_rosmsg
must be running as well.
Open a terminal:
yarpserver yarpidl_rosmsg
Execute your existing YARP modules and/or ROS nodes, and the code generated by yarp-bottle-generator.
The interesting stuff starts now!
I recommend you to read the previous paragraphs to understand how to setup the envinronment and run the code in case you didn't do it already.
I'll split this documentation in 3 parts: general, multiplexers and message builder. In the current state of the development YOU'LL HAVE TO CONFIGURE ALL THE 4 PARTS in order to correctly customize your own configuration file.
In the folder $BOTTLE_GENERATOR_DIR/app
, create a text file that you have to edit in order to run the generator with your own configuration.
This part has 1 section: [general]
.
It has 3 variables: output_name
, to_ros
and num_mux
.
output_name
: The name of the output topic/port. The bottle will be sent to this topic/port.
to_ros
: This variable expects true or false, true when the module is supposed to send a message to a ROS topic and false when the output is a YARP port.
from_ros_topics
: This flag serves to decide if the input entities are ports or topics. Currently the supported data types are the ones translated by the run-time converter yarpidl_rosmsg
.
num_mux
: The number of multiplexers (i.e. Hubs) you want to create.
[general] output_name = /topic_name to_ros = true num_mux = 3
This part has 0 or more sections: [mux1]...[muxn]
.
The generator expects an equal number of multiplexers and converters so the variables to configure the converter are in each multiplexer section (the last 2 variables are the ones that configure the converter).
They have 4 variables: num_ports
, ports
, function
and verbose
.
num_ports
: The number of input ports/topics on the multiplexer.
ports
: The name of all the input ports/topics. Each input name should be separated by a comma (in the end the number of commas should be equal to num_ports - 1
). All white spaces will be excluded from the input names.
function
: The name of one of the available functions (list of functions above). Each function expects specific arguments so be careful to specify a function compatible with the data contained on the multiplexer.
List of functions:
none
: This is a dummy function that has no effect on the multiplexer data. Use it when you want your converter to have no effect at all.none_double
: Expects double
values (or at least something that can be casted to double
) so the multiplexer should only contain compatible values. Similar to the none
function because it doesn't affect the multiplexer data. The main difference is that when the verbose
variable is set to true
it prints each of the values of the multiplexer.deg_to_rad
: Expects double
values (or at least something that can be casted to double
) so the multiplexer should only contain compatible values. It converts each entry of the multiplexer from degrees to radians.verbose
: This variable expects two possible values: true
or false
. In case you set it to true
, the converter will print all the information about the data that passes through it. Not all the functions will have stuff to print but there is no problem setting this variable to true
in those cases.
[mux1] num_ports = 4 ports = we , are , 4 , ports function = none verbose = false [mux2] num_ports = 2 ports = just , 2 function = none_double verbose = true [mux3] num_ports = 1 # Yes! Altough it's a multiplexer it can accept only 1 port/topic as the input... ports = dummy_mux_port function = deg_to_rad verbose = false
This part has 1 or more sections: [message]
, [unique_name_1]...[unique_name_n]
.
It differs from the other parts because although sections might have completely different names the variables will have the same functionality and syntax on all of them. The only mandatory section is the message
and the other ones can be named at your taste although it has to be an unique name.
In case you have set the output as a YARP port you can organize your message the way you want but in case you set the output as a ROS topic each of this sections should match a ROS message. Why more than one section? Because ROS messages can have variables of non-primitive types. A non-primitive type will be represented by another section. Too confusing? Please check the instructions above.
They have 1 or more variables: num_fields
and 1_stuff...n_stuff
.
The fields should be organized ON THE SAME ORDER AS THEY ARE ON THE ROS MESSAGE!
num_fields
: The number of fields of the ROS message. Both primitive and non-primitive variables should count as 1 field.
[field index]_type
: The field index should be the index of the field on the ROS message from 1 to num_fields
. It expects one of the types available (list of types above). Each type might expect more variables following the same syntax (also explained on the list above): [field index]_msg
and/or [field index]_mux
.
List of types:
single_value
: Expects [field index]_msg
variable. You can specify one hard coded value for this field. Strings should be added between "[string_value]"
.timestamp
: Doesn't expect any other variable. It adds a timestamp to the bottle.counter
: Doesn't expect any other variable. It adds an iteration index to the bottle.list
: Expects [field index]_msg
variable. You can specify a hard coded list of values for this field. Each value should be separated by a comma. All white spaces will be excluded. Each string should be added between "[string_value]"
.mux
: Expects [field index]_mux
variable. The name of the mux section you want to use to fill this field. Each value from the multiplexer will be pushed to the bottle.That's it! In the end you'll have a bottle with the right structure to be sent to a ROS topic.
Be careful to match the data with what ROS expects to receive... If you set a list
type and ROS is waiting for a vector of integers your [field index]_msg
should be something like [field index]_msg = 1 , 2 , 3 , 4
. In case you specify something like [field index]_msg = "hey" , "there"
the conversion will fail because it cannot cast the values to integers.
// ROS message examples: Example1.msg, Example2.msg and std_msgs/Header.msg //// // begin Example1.msg // std_msgs/Header header // string[] first_last_name // float64[] readings // end Example1.msg //// //// // begin Example2.msg // float64 random_number // end Example2.msg //// //// // begin Header.msg // uint32 seq // time stamp // string frame_id // Example2 other_example // end Header.msg //// // Imagine that the output topic is waiting for a message of the type Example1.msg. // That means our `[message]` section should match the Example1.msg [message] num_fields = 3 1_type = msg 1_msg = header_message 2_type = list 2_msg = "Miguel" , "Aragão" 3_type = mux 3_mux = mux2 [header_message] num_fiels = 4 1_type = counter 2_type = timestamp 3_type = single_value 3_msg = "0" 4_type = msg 4_msg = random_number_message [random_number_message] num_fields = 1 1_type = single_value 1_msg = 31.45
You're ready to customize your own configuration file! On the $BOTTLE_GENERATOR_DIR/app
you'll find examples of the .ini
files. Create your own file for your particular use-case.
Customize it yourself and I'll be glad to help you on any problem you might have!
Please open an issue for doubts and all kinds of feedback.