We have a software with a lot of parameters and have multiple versions of the same robot. Most the parameters are “general”, meaning they are the same for all of of the robots, some of them are “per series”, meaning each robot series will share the same values (e.g. joint limits, feature flags, etc…), and some of them are “per instance”, meaning each physical robot will have a unique value (e.g. calibration values).
I tried to architecture something that allows us this flexibility while not increasing the maintenance cost of changing a value.
We use ROS1 (for now). I created a hierarchy of YAML file and use YTT. YTT allows to “code” inside the YAML file, and most importantly for us, to merge and override values.
It roughly looks like this:
./acme_config
./global
./domain.yaml
./limits.yaml
./controllers.yaml
./series
./1.0
./limits.yaml
./1.1
./limits.yaml
./domain.yaml
# On the robot itself
/etc/acme
./calibration.yaml
./limits.yaml
I run YTT on this to output a single YAML file that I load using the rosparam
directive of roslaunch.
I’ve simplified a bit, for example YTT allow two layers, one called “data-values” that can then be accessed in the more regular YAML file, which I try to use to keep the values separated from the “structure” of the parameters. Also, I can make it so the 1.1 series inherits from the 1.0 series values.
What I don’t like about this architecture is that it adds distance between the parameters and their actual use in the rosnodes. Also, using the “data-values” I can handle backward-compatibility but it’s not always easy.
Did someone else encountered this problem? What are your findings? Any clue how ROS2 would make this easier/more difficult? I guess the Python launch files would add a bit of flexibility.