Figure above shows a system dependency graph for a sample system to demonstrate the working of RSIA.
Note there are no colored edges as this graph is directly exported from a ROS utility rqt_graph which visualizes system state at runtime.
Now, let's look at system dependency graph as generated by the RSIA.
Before going forward and looking at the impact analysis results, let's look at how to generate system dependency graph with rsia.
ROS requirement: The workspace should be sourced. To source the sample workspace. Follow these steps:
- Initiate workspace.
cd <rsia_repo>/examples/sample_ros_workspace/src
catkin_init_workspace
- Compile workspace (Note: Here, we don't follow ROS's command
catkin_make
but instead use these commands which catkin performs in the background with some changed parameters to enable DA)
cd <rsia_repo>/examples/sample_ros_workspace
mkdir build
cd build
cmake ../src -DCMAKE_INSTALL_PREFIX=../install -DCATKIN_DEVEL_PREFIX=../devel -DCMAKE_CXX_COMPILER=$llvm_base_dir/build_llvm/libexec/c++-analyzer
make
- Source workspace
source <rsia_repo>/examples/sample_ros_workspace/devel/setup.bash
For IA to generate of system dependency graph, first we need to generate component level dump for each component in the system. This is done through running DA on each component.
We will show an example of DA on sensor node in sample_system and rest are similar:
- Run DA_first_pass as:
cd <rsia_repo>/examples/sample_ros_workspace/build
$llvm_base_dir/build_llvm/bin/scan-build --use-analyzer=$llvm_base_dir/build_llvm/bin/clang -enable-checker debug.DumpRosPatterns make sensor_node --always-make
This will generate several log files within build/<packageName>
folder.
- Run DA_second_pass as:
cd <rsia_repo>/examples/sample_ros_workspace/build/sensor
DA_second_pass defaults
This will generate the following file:
- type: ROSNode
name: Node
label: /sensor
color: none
- type: ROSTopic
name: sensor
label: /sensor
color: none
- type: ROSEdge
source: Node
destination: sensor
color: green
label: none
Currently, developer manually changed the node name. Replace node name with the appropriate node name.
Repeat this process for other components. Namely:
- arm_planner
- arm_controller
- base_planner
- base_controller
We have also included already generated files for all these components under the folder IA_files.
We will show the example for already added component dump example files in IA_files folder. You can follow the example with your generated component files.
First, we need to generate a launch file. Please generate one as specified here or use this one. Similarly, generate other input files (AffComp.txt FileList.txt StopColors.txt).
Once all the input files are generated, we can run IA phase as:
./GraphTraversal launch_ia.yaml
To just generate system dependency graph: Make StopColors.txt and AffComp.txt empty and run IA_tool again.
- Traditional IA: Make StopColors.txt empty and put the changed component in AffComp.txt and run IA_tool.
- RSIA: Put green in StopColors.txt and put the changed component in AffComp.txt and run IA_tool. Note: green because we have modelled Independent edges as green, so the color choice is bound to our implementation.
Output: StopColor: green and AffComp: sensor
We can see that base_controller is not affected anymore because of an independent edge from base_planner component (ellipse) to base_planner topic (rectangle). This shows how RSIA can utilize rate information to reduce impact sets.
The reason why that link is Independent can be understood by looking at the source code of base_planner:
ros::Publisher base_planner_pub;
ros::Subscriber base_planner_sub;
void callback_subscriber(const std_msgs::Bool::ConstPtr& msg)
{
//some processing
}
void callback_timer(const ros::TimerEvent&)
{
std_msgs::Bool msg;
//some processing
base_planner_pub.publish(msg);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "base_controller");
ros::NodeHandle n;
base_planner_pub = n.advertise<std_msgs::Bool>("/base_planner",1000);
base_planner_sub = n.subscribe("/sensor", 1000, callback_subscriber);
//ros timer will ensure timly execution of the function callback_timer
ros::Timer timer1 = n.createTimer(ros::Duration(0.1), callback_timer);
//to wait for incoming messages and call the callback function as messages arrive.
ros::spin();
return 0;
}
Here, callback_timer
is executed at a fixed rate by ros::Timer
and since the component publishes through that callback, it is ensured that the message publishing rate is fixed of the incoming rate.