Skip to content

Commit

Permalink
Add ros2 implementation based on ros2model
Browse files Browse the repository at this point in the history
  • Loading branch information
ipa-nhg committed Feb 27, 2024
1 parent c54d90c commit f429ba7
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 25 deletions.
13 changes: 2 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@

[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)

[![MELODIC build status](https://github.com/ipa320/ros-model-extractors/actions/workflows/build_melodic.yml/badge.svg)](https://github.com/ipa320/ros-model-extractors/actions/workflows/build_melodic.yml)
[![NOETIC ros-model-extractors](https://github.com/ipa320/ros-model-extractors/actions/workflows/build_noetic.yml/badge.svg)](https://github.com/ipa320/ros-model-extractors/actions/workflows/build_noetic.yml)
[![FOXY build status](https://github.com/ipa320/ros-model-extractors/actions/workflows/build_foxy.yml/badge.svg)](https://github.com/ipa320/ros-model-extractors/actions/workflows/build_foxy.yml)


Technical Maintainer: [**ipa-nhg**](https://github.com/ipa-nhg/) (**Nadia Hammoudeh Garcia**, **Fraunhofer IPA**) - **[email protected]**

This repository contains the HAROS framework plugin to automatically generate models according to the DSLs defined for RosModel.
Expand All @@ -17,6 +12,7 @@ This package also contains a set of ROS containers where you can easily do the a

As related work you can read the following paper: [Bootstrapping MDE development from ROS manual code: Part 2—Model generation and leveraging models at runtime](https://link.springer.com/article/10.1007/s10270-021-00873-2?wt_mc=Internal.Event.1.SEM.ArticleAuthorOnlineFirst&utm_source=ArticleAuthorOnlineFirst&utm_medium=email&utm_content=AA_en_06082018&ArticleAuthorOnlineFirst_20210420)

:bangbang: The updated version of the development is only being supported for ROS2, the RO1 implementation (old version) is available under [ros1 branch](https://github.com/ipa320/ros-model-extractors/tree/ros1)

### HowTo Use the docker container to run the ros-model plugin for HAROS

Expand All @@ -26,7 +22,7 @@ Build the HAROS docker image, for your desired ROS distro version:

```
cd path-to-ros-model-extractors-repo
[sudo] docker build --tag=haros_ROSDISTRO -f ROSDISTRO/Dockerfile .
[sudo] docker build --tag=haros_ROSDISTRO -f docker/ROSDISTRO/Dockerfile .
```

Call the ros-model extractor plugin, remember you have to also clone the repository to be analysed:
Expand All @@ -48,13 +44,8 @@ Additionally, the analysis offers the option to analyze all the nodes of a packa
```

Please check the available examples for the supported distros:

- [ROS1 melodic](melodic/README.md)
- [ROS1 noetic](noetic/README.md)
- [ROS2 foxy](foxy/README.md)
- [ROS2 humble](humble/README.md)

ToDo:
- Extractor of interfaces types (msgs, srvs and actions)
- Parser for launch files and analysis of the full system

2 changes: 1 addition & 1 deletion docker/haros_runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,4 @@ echo "###########"
done

## Clean and finish
#rm -rf ${5}/src/*
#find ${5}/src -maxdepth 1 -type d ! -iname ros2model -exec rm -rvf {} \;
5 changes: 2 additions & 3 deletions docker/humble/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ RUN usermod -a -G root extractor
RUN echo "extractor ALL=(ALL:ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/extractor
USER extractor
RUN mkdir -p /home/extractor/ws/src
#RUN git clone https://github.com/ipa320/ros2model.git /home/extractor/ws/src/ros2model
RUN git clone https://github.com/ipa-nhg/ros2model.git -b PythonInstallTemplatesFolder /home/extractor/ws/src/ros2model
RUN git clone https://github.com/ipa320/ros2model.git /home/extractor/ws/src/ros2model

RUN mkdir -p /home/extractor/results
RUN chown extractor:extractor /home/extractor/results
Expand Down Expand Up @@ -73,7 +72,7 @@ RUN source /opt/ros/$ROS_DISTRO/setup.bash;\
ENV PYTHON_VERSION 3
RUN echo 'source /home/extractor/ws/install/setup.bash' >> /home/extractor/.bashrc

RUN echo "test"
#RUN echo "test"
#COPY ${path_to_scripts}messages_generator_runner.sh /
#COPY ${path_to_scripts}generate_messages_model_helper.sh /
COPY docker/haros_runner.sh /
Expand Down
9 changes: 2 additions & 7 deletions docker/humble/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Install docker https://docs.docker.com/install/linux/docker-ce/ubuntu/
Build the HAROS docker image, for your desired ROS distro version:
```
cd path-to-ros-model-extractors-repo
[sudo] docker build --tag=haros_humble -f humble/Dockerfile .
[sudo] docker build --tag=haros_humble -f docker/humble/Dockerfile .
```

Call the ros-model extractor plugin, remember you have to also clone the repository to be analysed:
Expand All @@ -21,13 +21,8 @@ For example:
[sudo] docker run -it haros_humble:latest /haros_runner.sh turtlesim turtlesim_node node . /home/extractor/ws "https://github.com/ros/ros_tutorials -b humble"
[sudo] docker run -it haros_humble:latest /haros_runner.sh test_pkg test_node node . /home/extractor/ws "https://github.com/ipa-nhg/test_ros2_code_extractor -b ros2"
[sudo] docker run -it haros_humble:latest /haros_runner.sh cpp_basic --all node . /home/extractor/ws "https://github.com/ipa-nhg/cpp_basic_ros2"
[sudo] docker run -it haros_humble:latest /haros_runner.sh depthai_ros_driver --all node . /home/extractor/ws "https://github.com/luxonis/depthai-ros/" https://github.com/ros-perception/vision_msgs "https://github.com/ros-perception/image_common/ -b humble"
docker run -it haros_humble:latest /haros_runner.sh nav2_controller --all node . /home/extractor/ws https://github.com/ros-planning/navigation2 "https://github.com/ros-geographic-info/geographic_info/ -b ros2 "
docker run -it haros_humble:latest /haros_runner.sh examples_rclcpp_minimal_publisher --all node . /home/extractor/ws https://github.com/ros2/examples/
```

Expand Down
81 changes: 81 additions & 0 deletions ros_code_analysis/ros_code_analysis/ros1_python_extractor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python
#
# Copyright 2024 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
#
# Nadia Hammoudeh Garcia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from bonsai.analysis import CodeQuery, resolve_expression
from ros_common_extractor import RosCommonExtractor
import ros2model.core.metamodels.metamodel_ros as RosModelMetamodel

class Ros1PythonExtractor():
def extract_primitives(node, parser, analysis):
gs = parser.global_scope
node.source_tree = parser.global_scope
publishers=[]
subscribers=[]
serviceservers=[]
serviceclients=[]
actionservers=[]
actionclients=[]
parameters=[]

msgs_list = []
pkgs_list = []
for imp_name in parser.imported_names_list:
s = str(imp_name)
if "msg" in s or "srv" in s:
ss = s.split(".")
if len(ss) < 2:
continue
if ss[-1] == "msg" or ss[-1] == "srv":
pkgs_list.append(ss[0])
elif ss[1] == "msg" or ss[1] == "srv":
msgs_list.append((ss[0], ss[2]))
else:
log.debug(("Python import with 'msg' or 'srv', "
"but unable to process it: ")
+ s)
for call in CodeQuery(gs).all_calls.get():
if "rospy.Publisher" in str(call):
if len(call.arguments) > 1:
name = analysis._extract_topic(call, topic_pos=0)
msg_type = analysis._extract_message_type(call, '', msgs_list, pkgs_list)
pub = RosModelMetamodel.Publisher(name=name,type=msg_type.replace(".msg",""))
publishers.append(pub)
if "rospy.Subscriber" in str(call):
if len(call.arguments) > 1:
name = analysis._extract_topic(call, topic_pos=0)
msg_type = analysis._extract_message_type(call, '', msgs_list, pkgs_list)
sub = RosModelMetamodel.Subscriber(name=name,type=msg_type.replace(".msg",""))
subscribers.append(sub)
if "rospy.Service" in str(call):
if len(call.arguments) > 1:
name = analysis._extract_topic(call, topic_pos=0)
srv_type = analysis._extract_message_type(call, '', msgs_list)
ss = RosModelMetamodel.ServiceServer(name=name,type=srv_type.replace(".srv","").replace("Request",""))
serviceservers.append(ss)
if "rospy.ServiceProxy" in str(call):
if len(call.arguments) > 1:
name = analysis._extract_topic(call, topic_pos=0)
srv_type = analysis._extract_message_type(call, '', msgs_list)
sc = RosModelMetamodel.ServiceClient(name=name,type=srv_type.replace(".srv","").replace("Response",""))
serviceclients.append(sc)
if "rospy.set_param" in str(call):
param_name = analysis._extract_topic(call, topic_pos=0)
param_type = default_value = None
default_value = resolve_expression(call.arguments[1])
param = RosModelMetamodel.Parameter(name=param_name,type=param_type,value=default_value)
parameters.append(param)
9 changes: 6 additions & 3 deletions ros_code_analysis/ros_code_analysis/ros_model_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from bonsai.analysis import CodeQuery, resolve_expression
from ros2_cpp_extractor import Ros2CppExtractor
from ros1_cpp_extractor import Ros1CppExtractor
from ros1_python_extractor import Ros1PythonExtractor


try:
Expand Down Expand Up @@ -123,15 +124,18 @@ def extract_node(self, name, node_name, pkg_name, ns, ws, rossystem):
actionservers, actionclients,
parameters] = Ros1CppExtractor.extract_primitives(node, parser, analysis)
elif (node.language=="python"):
print("ROS1 python")
[publishers, subscribers,
serviceservers, serviceclients,
actionservers, actionclients,
parameters] = Ros1PythonExtractor.extract_primitives(node, parser, analysis)
elif os.environ.get("ROS_VERSION") == "2":
if (node.language=="cpp"):
[publishers, subscribers,
serviceservers, serviceclients,
actionservers, actionclients,
parameters] = Ros2CppExtractor.extract_primitives(node, parser, analysis)
elif (node.language=="python"):
print("ROS2 python")
print("ROS2 python...tbd...")
RosModel_node=RosModelMetamodel.Node(name=graph_name,
publisher=publishers, subscriber=subscribers,
serviceserver=serviceservers, serviceclient=serviceclients,
Expand All @@ -144,7 +148,6 @@ def extract_node(self, name, node_name, pkg_name, ns, ws, rossystem):
RosModel_node=RosModelMetamodel.Node(name=graph_name)
RosModel_artifact=RosModelMetamodel.Artifact(name=node_name, node=[RosModel_node])
RosModel_package=RosModelMetamodel.Package(name=self.args.package_name, artifact=[RosModel_artifact])
print(RosModel_package)
#Model file generator
node_generator = ComponentGenerator()
node_generator.generate_a_file(
Expand Down

0 comments on commit f429ba7

Please sign in to comment.