Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ros2 implementation based on ros2model #33

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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**) - **nadia.hammoudeh.garcia@ipa.fraunhofer.de**

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
Loading