mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-11-09 21:51:36 +08:00
PX4 ROS2 msg conformity and explicit topics
- .msg files are PascalCase - topics are still either per msg or explicitly listed in TOPICS - compatible structs are still generated (eg struct msg_s), but ROS2 style px4::msg::Msg is also available
This commit is contained in:
@@ -1,444 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
################################################################################
|
||||
#
|
||||
# Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
|
||||
# Copyright (c) 2018-2021 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# This script can generate the client and agent code based on a set of topics
|
||||
# to sent and set to receive. It uses fastrtpsgen to generate the code from the
|
||||
# IDL for the topic messages. The PX4 msg definitions are used to create the IDL
|
||||
# used by fastrtpsgen using templates.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import shutil
|
||||
import px_generate_uorb_topic_files
|
||||
from uorb_rtps_classifier import Classifier
|
||||
import subprocess
|
||||
import glob
|
||||
import errno
|
||||
import re
|
||||
|
||||
try:
|
||||
from six.moves import input
|
||||
except ImportError as e:
|
||||
print("Failed to import six: " + e)
|
||||
print("")
|
||||
print("You may need to install it using:")
|
||||
print(" pip3 install --user six")
|
||||
print("")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
from packaging import version
|
||||
except ImportError as e:
|
||||
print("Failed to import packaging: " + str(e))
|
||||
print("")
|
||||
print("You may need to install it using:")
|
||||
print(" pip3 install --user packaging")
|
||||
print("")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
default_client_out = "src/modules/micrortps_bridge/micrortps_client"
|
||||
default_agent_out = "src/modules/micrortps_bridge/micrortps_agent"
|
||||
default_uorb_templates_dir = "templates/uorb_microcdr"
|
||||
default_urtps_templates_dir = "templates/urtps"
|
||||
default_urtps_topics_file = "tools/urtps_bridge_topics.yaml"
|
||||
default_package_name = px_generate_uorb_topic_files.PACKAGE
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument("-a", "--agent", dest='agent', action="store_true",
|
||||
help="Flag for generate the agent, by default is true if -c is not specified")
|
||||
parser.add_argument("-c", "--client", dest='client', action="store_true",
|
||||
help="Flag for generate the client, by default is true if -a is not specified")
|
||||
parser.add_argument("-i", "--generate-idl", dest='gen_idl',
|
||||
action="store_true", help="Flag for generate idl files for each msg")
|
||||
parser.add_argument("-j", "--idl-dir", dest='idl_dir',
|
||||
type=str, help="IDL files dir", default='')
|
||||
parser.add_argument("-m", "--mkdir-build", dest='mkdir_build',
|
||||
action="store_true", help="Flag to create 'build' dir")
|
||||
parser.add_argument("-l", "--generate-cmakelists", dest='cmakelists',
|
||||
action="store_true", help="Flag to generate a CMakeLists.txt file for the micro-RTPS agent")
|
||||
parser.add_argument("-t", "--topic-msg-dir", dest='msgdir', type=str,
|
||||
help="Topics message, by default using relative path 'msg/'", default="msg")
|
||||
parser.add_argument("-b", "--uorb-templates-dir", dest='uorb_templates', type=str,
|
||||
help="uORB templates, by default using relative path to msgdir 'templates/uorb_microcdr'", default=default_uorb_templates_dir)
|
||||
parser.add_argument("-q", "--urtps-templates-dir", dest='urtps_templates', type=str,
|
||||
help="uRTPS templates, by default using relative path to msgdir 'templates/urtps'", default=default_urtps_templates_dir)
|
||||
parser.add_argument("-y", "--rtps-ids-file", dest='yaml_file', type=str,
|
||||
help="Setup uRTPS bridge topics file path, by default using relative path to msgdir 'tools/urtps_bridge_topics.yaml'", default=default_urtps_topics_file)
|
||||
parser.add_argument("-p", "--package", dest='package', type=str,
|
||||
help="Msg package naming, by default px4", default=default_package_name)
|
||||
parser.add_argument("-o", "--agent-outdir", dest='agentdir', type=str,
|
||||
help="Agent output dir, by default using relative path 'src/modules/micrortps_bridge/micrortps_agent'", default=default_agent_out)
|
||||
parser.add_argument("-u", "--client-outdir", dest='clientdir', type=str,
|
||||
help="Client output dir, by default using relative path 'src/modules/micrortps_bridge/micrortps_client'", default=default_client_out)
|
||||
parser.add_argument("-f", "--fastrtpsgen-dir", dest='fastrtpsgen', type=str, nargs='?',
|
||||
help="fastrtpsgen installation dir, only needed if fastrtpsgen is not in PATH, by default empty", default="")
|
||||
parser.add_argument("-g", "--fastrtpsgen-include", dest='fastrtpsgen_include', type=str,
|
||||
help="directory(ies) to add to preprocessor include paths of fastrtpsgen, by default empty", default="")
|
||||
parser.add_argument("-r", "--ros2-distro", dest='ros2_distro', type=str, nargs='?',
|
||||
help="ROS2 distro, only required if generating the agent for usage with ROS2 nodes, by default empty", default="")
|
||||
parser.add_argument("--delete-tree", dest='del_tree',
|
||||
action="store_true", help="Delete dir tree output dir(s)")
|
||||
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
parser.print_usage()
|
||||
exit(-1)
|
||||
|
||||
# Parse arguments
|
||||
args = parser.parse_args()
|
||||
agent = args.agent
|
||||
client = args.client
|
||||
cmakelists = args.cmakelists
|
||||
del_tree = args.del_tree
|
||||
gen_idl = args.gen_idl
|
||||
mkdir_build = args.mkdir_build
|
||||
package = args.package
|
||||
|
||||
# Msg files path
|
||||
msg_dir = os.path.abspath(args.msgdir)
|
||||
px_generate_uorb_topic_files.append_to_include_path(
|
||||
{msg_dir}, px_generate_uorb_topic_files.INCL_DEFAULT, package)
|
||||
|
||||
# Agent files output path
|
||||
agent_out_dir = os.path.abspath(args.agentdir)
|
||||
|
||||
# Client files output path
|
||||
client_out_dir = os.path.abspath(args.clientdir)
|
||||
|
||||
# IDL files path
|
||||
idl_dir = args.idl_dir
|
||||
if idl_dir != '':
|
||||
idl_dir = os.path.abspath(args.idl_dir)
|
||||
else:
|
||||
idl_dir = os.path.join(agent_out_dir, "idl")
|
||||
|
||||
if args.fastrtpsgen is None or args.fastrtpsgen == '':
|
||||
# Assume fastrtpsgen is in PATH
|
||||
fastrtpsgen_path = 'fastrtpsgen'
|
||||
for dirname in os.environ['PATH'].split(':'):
|
||||
candidate = os.path.join(dirname, 'fastrtpsgen')
|
||||
if os.path.isfile(candidate):
|
||||
fastrtpsgen_path = candidate
|
||||
else:
|
||||
# Path to fastrtpsgen is explicitly specified
|
||||
if os.path.isdir(args.fastrtpsgen):
|
||||
fastrtpsgen_path = os.path.join(
|
||||
os.path.abspath(args.fastrtpsgen), 'fastrtpsgen')
|
||||
else:
|
||||
fastrtpsgen_path = args.fastrtpsgen
|
||||
|
||||
fastrtpsgen_include = args.fastrtpsgen_include
|
||||
if fastrtpsgen_include is not None and fastrtpsgen_include != '':
|
||||
fastrtpsgen_include = "-I " + \
|
||||
os.path.abspath(
|
||||
args.fastrtpsgen_include) + " "
|
||||
|
||||
# get FastRTPSGen version
|
||||
# .. note:: since Fast-RTPS 1.8.0 release, FastRTPSGen is a separated repository
|
||||
# and not included in the Fast-RTPS project.
|
||||
# The starting version since this separation is 1.0.0, which follows its own
|
||||
# versioning
|
||||
fastrtpsgen_version = version.Version("1.0.0")
|
||||
if(os.path.exists(fastrtpsgen_path)):
|
||||
try:
|
||||
fastrtpsgen_version_out = subprocess.check_output(
|
||||
[fastrtpsgen_path, "-version"]).decode("utf-8").strip()[-5:]
|
||||
except OSError:
|
||||
raise
|
||||
|
||||
try:
|
||||
fastrtpsgen_version = version.parse(fastrtpsgen_version_out)
|
||||
except version.InvalidVersion:
|
||||
raise Exception(
|
||||
"'fastrtpsgen -version' returned None or an invalid version")
|
||||
else:
|
||||
raise Exception(
|
||||
"FastRTPSGen not found. Specify the location of fastrtpsgen with the -f flag")
|
||||
|
||||
|
||||
# get ROS 2 version, if exists
|
||||
ros2_distro = ''
|
||||
ros_version = os.environ.get('ROS_VERSION')
|
||||
if ros_version == '2':
|
||||
if args.ros2_distro != '':
|
||||
ros2_distro = args.ros2_distro
|
||||
else:
|
||||
ros2_distro = os.environ.get('ROS_DISTRO')
|
||||
|
||||
# get FastRTPS version
|
||||
fastrtps_version = ''
|
||||
if not ros2_distro:
|
||||
# grab the version installed system wise
|
||||
fastrtps_version = subprocess.check_output(
|
||||
"ldconfig -v 2>/dev/null | grep libfastrtps", shell=True).decode("utf-8").strip().split('so.')[-1]
|
||||
else:
|
||||
# grab the version of the ros-<ros_distro>-fastrtps package
|
||||
fastrtps_version = re.search(r'Version:\s*([\dd.]+)', subprocess.check_output(
|
||||
"dpkg -s ros-" + ros2_distro + "-fastrtps 2>/dev/null | grep -i version", shell=True).decode("utf-8").strip()).group(1)
|
||||
|
||||
|
||||
# If nothing specified it's generated both
|
||||
if agent == False and client == False:
|
||||
agent = True
|
||||
client = True
|
||||
|
||||
if del_tree:
|
||||
if agent:
|
||||
_continue = str(input("\nFiles in " + agent_out_dir +
|
||||
" will be erased, continue?[Y/n]\n"))
|
||||
if _continue == "N" or _continue == "n":
|
||||
print("Aborting execution...")
|
||||
exit(-1)
|
||||
else:
|
||||
if agent and os.path.isdir(agent_out_dir):
|
||||
shutil.rmtree(agent_out_dir)
|
||||
|
||||
if client:
|
||||
_continue = str(input(
|
||||
"\nFiles in " + client_out_dir + " will be erased, continue?[Y/n]\n"))
|
||||
if _continue.strip() in ("N", "n"):
|
||||
print("Aborting execution...")
|
||||
exit(-1)
|
||||
else:
|
||||
if client and os.path.isdir(client_out_dir):
|
||||
shutil.rmtree(client_out_dir)
|
||||
|
||||
if agent and os.path.isdir(os.path.join(agent_out_dir, "idl")):
|
||||
shutil.rmtree(os.path.join(agent_out_dir, "idl"))
|
||||
|
||||
# uORB templates path
|
||||
uorb_templates_dir = (args.uorb_templates if os.path.isabs(args.uorb_templates)
|
||||
else os.path.join(msg_dir, args.uorb_templates))
|
||||
|
||||
# uRTPS templates path
|
||||
urtps_templates_dir = (args.urtps_templates if os.path.isabs(args.urtps_templates)
|
||||
else os.path.join(msg_dir, args.urtps_templates))
|
||||
|
||||
# parse yaml file into a map of ids and messages to send and receive
|
||||
classifier = (Classifier(os.path.abspath(args.yaml_file), msg_dir) if os.path.isabs(args.yaml_file)
|
||||
else Classifier(os.path.join(msg_dir, args.yaml_file), msg_dir))
|
||||
|
||||
|
||||
uRTPS_CLIENT_TEMPL_FILE = 'microRTPS_client.cpp.em'
|
||||
uRTPS_AGENT_TOPICS_H_TEMPL_FILE = 'RtpsTopics.h.em'
|
||||
uRTPS_AGENT_TOPICS_SRC_TEMPL_FILE = 'RtpsTopics.cpp.em'
|
||||
uRTPS_AGENT_TEMPL_FILE = 'microRTPS_agent.cpp.em'
|
||||
uRTPS_TIMESYNC_CPP_TEMPL_FILE = 'microRTPS_timesync.cpp.em'
|
||||
uRTPS_TIMESYNC_H_TEMPL_FILE = 'microRTPS_timesync.h.em'
|
||||
uRTPS_AGENT_CMAKELISTS_TEMPL_FILE = 'microRTPS_agent_CMakeLists.txt.em'
|
||||
uRTPS_PUBLISHER_SRC_TEMPL_FILE = 'Publisher.cpp.em'
|
||||
uRTPS_PUBLISHER_H_TEMPL_FILE = 'Publisher.h.em'
|
||||
uRTPS_SUBSCRIBER_SRC_TEMPL_FILE = 'Subscriber.cpp.em'
|
||||
uRTPS_SUBSCRIBER_H_TEMPL_FILE = 'Subscriber.h.em'
|
||||
|
||||
|
||||
def generate_agent(out_dir):
|
||||
global fastrtps_version
|
||||
|
||||
if classifier.msgs_to_send:
|
||||
for msg_file in classifier.msgs_to_send:
|
||||
if gen_idl:
|
||||
if out_dir != agent_out_dir:
|
||||
px_generate_uorb_topic_files.generate_idl_file(msg_file, msg_dir, "", os.path.join(out_dir, "/idl"), urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, fastrtps_version, ros2_distro, classifier.msg_list)
|
||||
else:
|
||||
px_generate_uorb_topic_files.generate_idl_file(msg_file, msg_dir, "", idl_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, fastrtps_version, ros2_distro, classifier.msg_list)
|
||||
px_generate_uorb_topic_files.generate_topic_file(msg_file, msg_dir, "", out_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_PUBLISHER_SRC_TEMPL_FILE)
|
||||
px_generate_uorb_topic_files.generate_topic_file(msg_file, msg_dir, "", out_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_PUBLISHER_H_TEMPL_FILE)
|
||||
|
||||
if classifier.alias_msgs_to_send:
|
||||
for msg_file in classifier.alias_msgs_to_send:
|
||||
msg_alias = msg_file[0]
|
||||
msg_name = msg_file[1]
|
||||
if gen_idl:
|
||||
if out_dir != agent_out_dir:
|
||||
px_generate_uorb_topic_files.generate_idl_file(msg_name, msg_dir, msg_alias, os.path.join(out_dir, "/idl"), urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, fastrtps_version, ros2_distro, classifier.msg_list)
|
||||
else:
|
||||
px_generate_uorb_topic_files.generate_idl_file(msg_name, msg_dir, msg_alias, idl_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, fastrtps_version, ros2_distro, classifier.msg_list)
|
||||
px_generate_uorb_topic_files.generate_topic_file(msg_name, msg_dir, msg_alias, out_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_PUBLISHER_SRC_TEMPL_FILE)
|
||||
px_generate_uorb_topic_files.generate_topic_file(msg_name, msg_dir, msg_alias, out_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_PUBLISHER_H_TEMPL_FILE)
|
||||
|
||||
if classifier.msgs_to_receive:
|
||||
for msg_file in classifier.msgs_to_receive:
|
||||
if gen_idl:
|
||||
if out_dir != agent_out_dir:
|
||||
px_generate_uorb_topic_files.generate_idl_file(msg_file, msg_dir, "", os.path.join(out_dir, "/idl"), urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, fastrtps_version, ros2_distro, classifier.msg_list)
|
||||
else:
|
||||
px_generate_uorb_topic_files.generate_idl_file(msg_file, msg_dir, "", idl_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, fastrtps_version, ros2_distro, classifier.msg_list)
|
||||
px_generate_uorb_topic_files.generate_topic_file(msg_file, msg_dir, "", out_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_SUBSCRIBER_SRC_TEMPL_FILE)
|
||||
px_generate_uorb_topic_files.generate_topic_file(msg_file, msg_dir, "", out_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_SUBSCRIBER_H_TEMPL_FILE)
|
||||
|
||||
if classifier.alias_msgs_to_receive:
|
||||
for msg_file in classifier.alias_msgs_to_receive:
|
||||
msg_alias = msg_file[0]
|
||||
msg_name = msg_file[1]
|
||||
if gen_idl:
|
||||
if out_dir != agent_out_dir:
|
||||
px_generate_uorb_topic_files.generate_idl_file(msg_name, msg_dir, msg_alias, os.path.join(out_dir, "/idl"), urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, fastrtps_version, ros2_distro, classifier.msg_list)
|
||||
else:
|
||||
px_generate_uorb_topic_files.generate_idl_file(msg_name, msg_dir, msg_alias, idl_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, fastrtps_version, ros2_distro, classifier.msg_list)
|
||||
px_generate_uorb_topic_files.generate_topic_file(msg_name, msg_dir, msg_alias, out_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_SUBSCRIBER_SRC_TEMPL_FILE)
|
||||
px_generate_uorb_topic_files.generate_topic_file(msg_name, msg_dir, msg_alias, out_dir, urtps_templates_dir,
|
||||
package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_SUBSCRIBER_H_TEMPL_FILE)
|
||||
|
||||
px_generate_uorb_topic_files.generate_uRTPS_general(classifier.msgs_to_send, classifier.alias_msgs_to_send, classifier.msgs_to_receive, classifier.alias_msgs_to_receive, msg_dir, out_dir,
|
||||
urtps_templates_dir, package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_AGENT_TEMPL_FILE)
|
||||
px_generate_uorb_topic_files.generate_uRTPS_general(classifier.msgs_to_send, classifier.alias_msgs_to_send, classifier.msgs_to_receive, classifier.alias_msgs_to_receive, msg_dir, out_dir,
|
||||
urtps_templates_dir, package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_TIMESYNC_CPP_TEMPL_FILE)
|
||||
px_generate_uorb_topic_files.generate_uRTPS_general(classifier.msgs_to_send, classifier.alias_msgs_to_send, classifier.msgs_to_receive, classifier.alias_msgs_to_receive, msg_dir, out_dir,
|
||||
urtps_templates_dir, package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_TIMESYNC_H_TEMPL_FILE)
|
||||
px_generate_uorb_topic_files.generate_uRTPS_general(classifier.msgs_to_send, classifier.alias_msgs_to_send, classifier.msgs_to_receive, classifier.alias_msgs_to_receive, msg_dir, out_dir,
|
||||
urtps_templates_dir, package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_AGENT_TOPICS_H_TEMPL_FILE)
|
||||
px_generate_uorb_topic_files.generate_uRTPS_general(classifier.msgs_to_send, classifier.alias_msgs_to_send, classifier.msgs_to_receive, classifier.alias_msgs_to_receive, msg_dir, out_dir,
|
||||
urtps_templates_dir, package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_AGENT_TOPICS_SRC_TEMPL_FILE)
|
||||
if cmakelists:
|
||||
px_generate_uorb_topic_files.generate_uRTPS_general(classifier.msgs_to_send, classifier.alias_msgs_to_send, classifier.msgs_to_receive, classifier.alias_msgs_to_receive, msg_dir, os.path.dirname(out_dir),
|
||||
urtps_templates_dir, package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_AGENT_CMAKELISTS_TEMPL_FILE)
|
||||
|
||||
# Final steps to install agent
|
||||
mkdir_p(os.path.join(out_dir, "fastrtpsgen"))
|
||||
prev_cwd_path = os.getcwd()
|
||||
os.chdir(os.path.join(out_dir, "fastrtpsgen"))
|
||||
if not glob.glob(os.path.join(idl_dir, "*.idl")):
|
||||
raise Exception("No IDL files found in %s" % idl_dir)
|
||||
|
||||
# If it is generating the bridge code for interfacing with ROS2, then set
|
||||
# the '-typeros2' option in fastrtpsgen.
|
||||
# .. note:: This is only available in FastRTPSGen 1.0.4 and above
|
||||
gen_ros2_typename = ""
|
||||
if ros2_distro and ros2_distro in ['dashing', 'eloquent', 'foxy', 'galactic', 'rolling'] and fastrtpsgen_version >= version.Version("1.0.4"):
|
||||
gen_ros2_typename = "-typeros2 "
|
||||
|
||||
idl_files = []
|
||||
for idl_file in glob.glob(os.path.join(idl_dir, "*.idl")):
|
||||
# Only run the generator for the topics that are actually marked to be
|
||||
# used by the bridge
|
||||
if os.path.splitext(os.path.basename(idl_file))[0] in classifier.msg_list:
|
||||
idl_files.append(idl_file)
|
||||
|
||||
try:
|
||||
ret = subprocess.check_call(fastrtpsgen_path + " -d " + out_dir +
|
||||
"/fastrtpsgen -example x64Linux2.6gcc " + gen_ros2_typename + fastrtpsgen_include + " ".join(str(idl_file) for idl_file in idl_files), shell=True)
|
||||
except OSError:
|
||||
raise
|
||||
|
||||
rm_wildcard(os.path.join(out_dir, "fastrtpsgen/*PubSubMain*"))
|
||||
rm_wildcard(os.path.join(out_dir, "fastrtpsgen/makefile*"))
|
||||
rm_wildcard(os.path.join(out_dir, "fastrtpsgen/*Publisher*"))
|
||||
rm_wildcard(os.path.join(out_dir, "fastrtpsgen/*Subscriber*"))
|
||||
for f in glob.glob(os.path.join(out_dir, "fastrtpsgen/*.cxx")):
|
||||
os.rename(f, f.replace(".cxx", ".cpp"))
|
||||
cp_wildcard(os.path.join(out_dir, "fastrtpsgen/*"), out_dir)
|
||||
if os.path.isdir(os.path.join(out_dir, "fastrtpsgen")):
|
||||
shutil.rmtree(os.path.join(out_dir, "fastrtpsgen"))
|
||||
cp_wildcard(os.path.join(urtps_templates_dir,
|
||||
"microRTPS_transport.*"), agent_out_dir)
|
||||
if cmakelists:
|
||||
os.rename(os.path.join(os.path.dirname(out_dir), "microRTPS_agent_CMakeLists.txt"),
|
||||
os.path.join(os.path.dirname(out_dir), "CMakeLists.txt"))
|
||||
if (mkdir_build):
|
||||
mkdir_p(os.path.join(os.path.dirname(out_dir), "build"))
|
||||
os.chdir(prev_cwd_path)
|
||||
return 0
|
||||
|
||||
|
||||
def rm_wildcard(pattern):
|
||||
for f in glob.glob(pattern):
|
||||
os.remove(f)
|
||||
|
||||
|
||||
def cp_wildcard(pattern, destdir):
|
||||
for f in glob.glob(pattern):
|
||||
shutil.copy(f, destdir)
|
||||
|
||||
|
||||
def mkdir_p(dirpath):
|
||||
try:
|
||||
os.makedirs(dirpath)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EEXIST and os.path.isdir(dirpath):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def generate_client(out_dir):
|
||||
global fastrtps_version
|
||||
|
||||
# Rename work in the default path
|
||||
if default_client_out != out_dir:
|
||||
def_file = os.path.join(default_client_out, "microRTPS_client.cpp")
|
||||
if os.path.isfile(def_file):
|
||||
os.rename(def_file, def_file.replace(".cpp", ".cpp_"))
|
||||
def_file = os.path.join(default_client_out, "microRTPS_transport.cpp")
|
||||
if os.path.isfile(def_file):
|
||||
os.rename(def_file, def_file.replace(".cpp", ".cpp_"))
|
||||
def_file = os.path.join(default_client_out, "microRTPS_transport.h")
|
||||
if os.path.isfile(def_file):
|
||||
os.rename(def_file, def_file.replace(".h", ".h_"))
|
||||
|
||||
px_generate_uorb_topic_files.generate_uRTPS_general(classifier.msgs_to_send, classifier.alias_msgs_to_send, classifier.msgs_to_receive, classifier.alias_msgs_to_receive, msg_dir,
|
||||
out_dir, uorb_templates_dir, package, px_generate_uorb_topic_files.INCL_DEFAULT, classifier.msg_list, fastrtps_version, ros2_distro, uRTPS_CLIENT_TEMPL_FILE)
|
||||
|
||||
# Final steps to install client
|
||||
cp_wildcard(os.path.join(urtps_templates_dir,
|
||||
"microRTPS_transport.*"), out_dir)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if agent:
|
||||
generate_agent(agent_out_dir)
|
||||
print(("\nAgent created in: " + agent_out_dir))
|
||||
|
||||
if client:
|
||||
generate_client(client_out_dir)
|
||||
print(("\nClient created in: " + client_out_dir))
|
||||
@@ -66,7 +66,7 @@ if __name__ == "__main__":
|
||||
with open(msg_filename, 'r') as source_file:
|
||||
msg_contents = source_file.read()
|
||||
|
||||
#Format markdown using msg name, comment, url, contents.
|
||||
#Format markdown using msg name, comment, url, contents.
|
||||
markdown_output="""# %s (UORB message)
|
||||
|
||||
%s
|
||||
@@ -93,9 +93,6 @@ if __name__ == "__main__":
|
||||
This list is [auto-generated](https://github.com/PX4/PX4-Autopilot/blob/master/msg/tools/generate_msg_docs.py) from the source code.
|
||||
:::
|
||||
|
||||
This topic lists the UORB messages available in PX4 (some of which may be may be shared by the [PX4-ROS 2 Bridge](../ros/ros2_comm.md)).
|
||||
Graphs showing how these are used [can be found here](../middleware/uorb_graph.md).
|
||||
|
||||
%s
|
||||
""" % (filelist_in_markdown)
|
||||
readme_file = os.path.join(output_dir, 'README.md')
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
"""
|
||||
px_generate_uorb_topic_files.py
|
||||
Generates c/cpp header/source files for uorb topics from .msg (ROS syntax)
|
||||
Generates c/cpp header/source files for uorb topics from .msg
|
||||
message files
|
||||
"""
|
||||
|
||||
@@ -42,6 +42,7 @@ import os
|
||||
import shutil
|
||||
import filecmp
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
try:
|
||||
@@ -76,93 +77,54 @@ except ImportError as e:
|
||||
|
||||
|
||||
__author__ = "Sergey Belash, Thomas Gubler, Beat Kueng"
|
||||
__copyright__ = "Copyright (C) 2013-2016 PX4 Development Team."
|
||||
__copyright__ = "Copyright (C) 2013-2021 PX4 Development Team."
|
||||
__license__ = "BSD"
|
||||
__email__ = "thomasgubler@gmail.com"
|
||||
|
||||
|
||||
TEMPLATE_FILE = ['msg.h.em', 'msg.cpp.em']
|
||||
TOPICS_LIST_TEMPLATE_FILE = ['uORBTopics.hpp.em', 'uORBTopics.cpp.em']
|
||||
OUTPUT_FILE_EXT = ['.h', '.cpp']
|
||||
TEMPLATE_FILE = ['msg.h.em']
|
||||
OUTPUT_FILE_EXT = ['.h']
|
||||
INCL_DEFAULT = ['std_msgs:./msg/std_msgs']
|
||||
PACKAGE = 'px4'
|
||||
TOPICS_TOKEN = '# TOPICS '
|
||||
IDL_TEMPLATE_FILE = 'msg.idl.em'
|
||||
|
||||
CONSTRAINED_FLASH = False
|
||||
|
||||
|
||||
class MsgScope:
|
||||
NONE = 0
|
||||
SEND = 1
|
||||
RECEIVE = 2
|
||||
|
||||
|
||||
def get_multi_topics(filename):
|
||||
"""
|
||||
Get TOPICS names from a "# TOPICS" line
|
||||
"""
|
||||
ofile = open(filename, 'r')
|
||||
text = ofile.read()
|
||||
result = []
|
||||
for each_line in text.split('\n'):
|
||||
if each_line.startswith(TOPICS_TOKEN):
|
||||
topic_names_str = each_line.strip()
|
||||
topic_names_str = topic_names_str.replace(TOPICS_TOKEN, "")
|
||||
result.extend(topic_names_str.split(" "))
|
||||
ofile.close()
|
||||
return result
|
||||
|
||||
|
||||
def get_msgs_list(msgdir):
|
||||
"""
|
||||
Makes list of msg files in the given directory
|
||||
"""
|
||||
return [fn for fn in os.listdir(msgdir) if fn.endswith(".msg")]
|
||||
|
||||
|
||||
def generate_output_from_file(format_idx, filename, outputdir, package, templatedir, includepath):
|
||||
def generate_output_from_file(filename, outputdir, package, templatedir, includepath):
|
||||
"""
|
||||
Converts a single .msg file to an uorb header/source file
|
||||
"""
|
||||
msg_context = genmsg.msg_loader.MsgContext.create_default()
|
||||
full_type_name = genmsg.gentools.compute_full_type_name(
|
||||
package, os.path.basename(filename))
|
||||
spec = genmsg.msg_loader.load_msg_from_file(
|
||||
msg_context, filename, full_type_name)
|
||||
full_type_name = genmsg.gentools.compute_full_type_name(package, os.path.basename(filename))
|
||||
|
||||
file_base_name = os.path.basename(filename).replace(".msg", "")
|
||||
|
||||
full_type_name_snake = re.sub(r'(?<!^)(?=[A-Z])', '_', file_base_name).lower()
|
||||
|
||||
spec = genmsg.msg_loader.load_msg_from_file(msg_context, filename, full_type_name)
|
||||
|
||||
field_name_and_type = {}
|
||||
for field in spec.parsed_fields():
|
||||
field_name_and_type.update({field.name: field.type})
|
||||
# assert if the timestamp field exists
|
||||
try:
|
||||
assert 'timestamp' in field_name_and_type
|
||||
except AssertionError:
|
||||
print("[ERROR] uORB topic files generator:\n\tgenerate_output_from_file:\tNo 'timestamp' field found in " +
|
||||
spec.short_name + " msg definition!")
|
||||
exit(1)
|
||||
# assert if the timestamp field is of type uint64
|
||||
try:
|
||||
assert field_name_and_type.get('timestamp') == 'uint64'
|
||||
except AssertionError:
|
||||
print("[ERROR] uORB topic files generator:\n\tgenerate_output_from_file:\t'timestamp' field in " + spec.short_name +
|
||||
" msg definition is not of type uint64 but rather of type " + field_name_and_type.get('timestamp') + "!")
|
||||
exit(1)
|
||||
topics = get_multi_topics(filename)
|
||||
|
||||
if includepath:
|
||||
search_path = genmsg.command_line.includepath_to_dict(includepath)
|
||||
else:
|
||||
search_path = {}
|
||||
|
||||
genmsg.msg_loader.load_depends(msg_context, spec, search_path)
|
||||
md5sum = genmsg.gentools.compute_md5(msg_context, spec)
|
||||
if len(topics) == 0:
|
||||
topics.append(spec.short_name)
|
||||
|
||||
em_globals = {
|
||||
"name_snake_case": full_type_name_snake,
|
||||
"file_name_in": filename,
|
||||
"md5sum": md5sum,
|
||||
"search_path": search_path,
|
||||
"msg_context": msg_context,
|
||||
"spec": spec,
|
||||
"topics": topics,
|
||||
"constrained_flash": CONSTRAINED_FLASH
|
||||
}
|
||||
|
||||
@@ -170,90 +132,12 @@ def generate_output_from_file(format_idx, filename, outputdir, package, template
|
||||
if not os.path.isdir(outputdir):
|
||||
os.makedirs(outputdir)
|
||||
|
||||
template_file = os.path.join(templatedir, TEMPLATE_FILE[format_idx])
|
||||
output_file = os.path.join(outputdir, spec.short_name +
|
||||
OUTPUT_FILE_EXT[format_idx])
|
||||
template_file = os.path.join(templatedir, TEMPLATE_FILE[0])
|
||||
output_file = os.path.join(outputdir, full_type_name_snake + OUTPUT_FILE_EXT[0])
|
||||
|
||||
return generate_by_template(output_file, template_file, em_globals)
|
||||
|
||||
|
||||
def generate_idl_file(filename_msg, msg_dir, alias, outputdir, templatedir, package, includepath, fastrtps_version, ros2_distro, msgs):
|
||||
"""
|
||||
Generates an .idl from .msg file
|
||||
"""
|
||||
msg = os.path.join(msg_dir, filename_msg + ".msg")
|
||||
|
||||
if (alias != ""):
|
||||
em_globals = get_em_globals(
|
||||
msg, alias, package, includepath, msgs, fastrtps_version, ros2_distro, MsgScope.NONE)
|
||||
spec_short_name = alias
|
||||
else:
|
||||
em_globals = get_em_globals(
|
||||
msg, "", package, includepath, msgs, fastrtps_version, ros2_distro, MsgScope.NONE)
|
||||
spec_short_name = em_globals["spec"].short_name
|
||||
|
||||
# Make sure output directory exists:
|
||||
if not os.path.isdir(outputdir):
|
||||
os.makedirs(outputdir)
|
||||
|
||||
template_file = os.path.join(templatedir, IDL_TEMPLATE_FILE)
|
||||
if version.parse(fastrtps_version) <= version.parse('1.7.2'):
|
||||
output_file = os.path.join(outputdir, IDL_TEMPLATE_FILE.replace(
|
||||
"msg.idl.em", str(spec_short_name + "_.idl")))
|
||||
else:
|
||||
output_file = os.path.join(outputdir, IDL_TEMPLATE_FILE.replace(
|
||||
"msg.idl.em", str(spec_short_name + ".idl")))
|
||||
|
||||
return generate_by_template(output_file, template_file, em_globals)
|
||||
|
||||
|
||||
def generate_uRTPS_general(filename_send_msgs, filename_alias_send_msgs, filename_receive_msgs, filename_alias_receive_msgs,
|
||||
msg_dir, outputdir, templatedir, package, includepath, msgs, fastrtps_version, ros2_distro, template_name):
|
||||
"""
|
||||
Generates source file by msg content
|
||||
"""
|
||||
send_msgs = list(os.path.join(msg_dir, msg + ".msg")
|
||||
for msg in filename_send_msgs)
|
||||
receive_msgs = list(os.path.join(msg_dir, msg + ".msg")
|
||||
for msg in filename_receive_msgs)
|
||||
|
||||
alias_send_msgs = list([os.path.join(
|
||||
msg_dir, msg[1] + ".msg"), msg[0]] for msg in filename_alias_send_msgs)
|
||||
|
||||
alias_receive_msgs = list([os.path.join(
|
||||
msg_dir, msg[1] + ".msg"), msg[0]] for msg in filename_alias_receive_msgs)
|
||||
|
||||
em_globals_list = []
|
||||
if send_msgs:
|
||||
em_globals_list.extend([get_em_globals(
|
||||
f, "", package, includepath, msgs, fastrtps_version, ros2_distro, MsgScope.SEND) for f in send_msgs])
|
||||
|
||||
if alias_send_msgs:
|
||||
em_globals_list.extend([get_em_globals(
|
||||
f[0], f[1], package, includepath, msgs, fastrtps_version, ros2_distro, MsgScope.SEND) for f in alias_send_msgs])
|
||||
|
||||
if receive_msgs:
|
||||
em_globals_list.extend([get_em_globals(
|
||||
f, "", package, includepath, msgs, fastrtps_version, ros2_distro, MsgScope.RECEIVE) for f in receive_msgs])
|
||||
|
||||
if alias_receive_msgs:
|
||||
em_globals_list.extend([get_em_globals(
|
||||
f[0], f[1], package, includepath, msgs, fastrtps_version, ros2_distro, MsgScope.RECEIVE) for f in alias_receive_msgs])
|
||||
|
||||
merged_em_globals = merge_em_globals_list(em_globals_list)
|
||||
|
||||
# Make sure output directory exists:
|
||||
if not os.path.isdir(outputdir):
|
||||
os.makedirs(outputdir)
|
||||
|
||||
template_file = os.path.join(templatedir, template_name)
|
||||
output_file = os.path.join(
|
||||
outputdir, template_name.replace(".em", ""))
|
||||
|
||||
return generate_by_template(output_file, template_file, merged_em_globals)
|
||||
|
||||
|
||||
def generate_topic_file(filename_msg, msg_dir, alias, outputdir, templatedir, package, includepath, msgs, fastrtps_version, ros2_distro, template_name):
|
||||
def generate_topic_file(filename_msg, msg_dir, alias, outputdir, templatedir, package, includepath, msgs, template_name):
|
||||
"""
|
||||
Generates a sources and headers from .msg file
|
||||
"""
|
||||
@@ -261,11 +145,11 @@ def generate_topic_file(filename_msg, msg_dir, alias, outputdir, templatedir, pa
|
||||
|
||||
if (alias):
|
||||
em_globals = get_em_globals(
|
||||
msg, alias, package, includepath, msgs, fastrtps_version, ros2_distro, MsgScope.NONE)
|
||||
msg, alias, package, includepath, msgs, MsgScope.NONE)
|
||||
spec_short_name = alias
|
||||
else:
|
||||
em_globals = get_em_globals(
|
||||
msg, "", package, includepath, msgs, fastrtps_version, ros2_distro, MsgScope.NONE)
|
||||
msg, "", package, includepath, msgs, MsgScope.NONE)
|
||||
spec_short_name = em_globals["spec"].short_name
|
||||
|
||||
# Make sure output directory exists:
|
||||
@@ -279,37 +163,34 @@ def generate_topic_file(filename_msg, msg_dir, alias, outputdir, templatedir, pa
|
||||
return generate_by_template(output_file, template_file, em_globals)
|
||||
|
||||
|
||||
def get_em_globals(filename_msg, alias, package, includepath, msgs, fastrtps_version, ros2_distro, scope):
|
||||
def get_em_globals(filename_msg, alias, package, includepath, msgs, scope):
|
||||
"""
|
||||
Generates em globals dictionary
|
||||
"""
|
||||
msg_context = genmsg.msg_loader.MsgContext.create_default()
|
||||
full_type_name = genmsg.gentools.compute_full_type_name(
|
||||
package, os.path.basename(filename_msg))
|
||||
spec = genmsg.msg_loader.load_msg_from_file(
|
||||
msg_context, filename_msg, full_type_name)
|
||||
topics = get_multi_topics(filename_msg)
|
||||
|
||||
full_type_name = genmsg.gentools.compute_full_type_name(package, os.path.basename(filename_msg))
|
||||
|
||||
spec = genmsg.msg_loader.load_msg_from_file(msg_context, filename_msg, full_type_name)
|
||||
|
||||
if includepath:
|
||||
search_path = genmsg.command_line.includepath_to_dict(includepath)
|
||||
else:
|
||||
search_path = {}
|
||||
|
||||
genmsg.msg_loader.load_depends(msg_context, spec, search_path)
|
||||
|
||||
md5sum = genmsg.gentools.compute_md5(msg_context, spec)
|
||||
if len(topics) == 0:
|
||||
topics.append(spec.short_name)
|
||||
|
||||
em_globals = {
|
||||
"file_name_in": filename_msg,
|
||||
"md5sum": md5sum,
|
||||
"search_path": search_path,
|
||||
"msg_context": msg_context,
|
||||
"spec": spec,
|
||||
"topics": topics,
|
||||
"msgs": msgs,
|
||||
"scope": scope,
|
||||
"package": package,
|
||||
"alias": alias,
|
||||
"fastrtps_version": fastrtps_version,
|
||||
"ros2_distro": ros2_distro
|
||||
"package": package
|
||||
}
|
||||
|
||||
return em_globals
|
||||
@@ -324,8 +205,7 @@ def merge_em_globals_list(em_globals_list):
|
||||
|
||||
merged_em_globals = {}
|
||||
for name in em_globals_list[0]:
|
||||
merged_em_globals[name] = [em_globals[name]
|
||||
for em_globals in em_globals_list]
|
||||
merged_em_globals[name] = [em_globals[name] for em_globals in em_globals_list]
|
||||
|
||||
return merged_em_globals
|
||||
|
||||
@@ -354,140 +234,13 @@ def generate_by_template(output_file, template_file, em_globals):
|
||||
ofile.close()
|
||||
return True
|
||||
|
||||
|
||||
def convert_dir(format_idx, inputdir, outputdir, package, templatedir):
|
||||
"""
|
||||
Converts all .msg files in inputdir to uORB header/source files
|
||||
"""
|
||||
|
||||
# Find the most recent modification time in input dir
|
||||
maxinputtime = 0
|
||||
for f in os.listdir(inputdir):
|
||||
fni = os.path.join(inputdir, f)
|
||||
if os.path.isfile(fni):
|
||||
it = os.path.getmtime(fni)
|
||||
if it > maxinputtime:
|
||||
maxinputtime = it
|
||||
|
||||
# Find the most recent modification time in output dir
|
||||
maxouttime = 0
|
||||
if os.path.isdir(outputdir):
|
||||
for f in os.listdir(outputdir):
|
||||
fni = os.path.join(outputdir, f)
|
||||
if os.path.isfile(fni):
|
||||
it = os.path.getmtime(fni)
|
||||
if it > maxouttime:
|
||||
maxouttime = it
|
||||
|
||||
# Do not generate if nothing changed on the input
|
||||
if (maxinputtime != 0 and maxouttime != 0 and maxinputtime < maxouttime):
|
||||
return False
|
||||
|
||||
includepath = INCL_DEFAULT + [':'.join([package, inputdir])]
|
||||
for f in os.listdir(inputdir):
|
||||
# Ignore hidden files
|
||||
if f.startswith("."):
|
||||
continue
|
||||
|
||||
fn = os.path.join(inputdir, f)
|
||||
# Only look at actual files
|
||||
if not os.path.isfile(fn):
|
||||
continue
|
||||
|
||||
if fn[-4:].lower() != '.msg':
|
||||
continue
|
||||
|
||||
generate_output_from_file(
|
||||
format_idx, fn, outputdir, package, templatedir, includepath)
|
||||
return True
|
||||
|
||||
|
||||
def copy_changed(inputdir, outputdir, prefix='', quiet=False):
|
||||
"""
|
||||
Copies files from inputdir to outputdir if they don't exist in
|
||||
ouputdir or if their content changed
|
||||
"""
|
||||
|
||||
# Make sure output directory exists:
|
||||
if not os.path.isdir(outputdir):
|
||||
os.makedirs(outputdir)
|
||||
|
||||
for input_file in os.listdir(inputdir):
|
||||
fni = os.path.join(inputdir, input_file)
|
||||
if os.path.isfile(fni):
|
||||
# Check if input_file exists in outpoutdir, copy the file if not
|
||||
fno = os.path.join(outputdir, prefix + input_file)
|
||||
if not os.path.isfile(fno):
|
||||
shutil.copy(fni, fno)
|
||||
if not quiet:
|
||||
print("{0}: new header file".format(fno))
|
||||
continue
|
||||
|
||||
if os.path.getmtime(fni) > os.path.getmtime(fno):
|
||||
# The file exists in inputdir and outputdir
|
||||
# only copy if contents do not match
|
||||
if not filecmp.cmp(fni, fno):
|
||||
shutil.copy(fni, fno)
|
||||
if not quiet:
|
||||
print("{0}: updated".format(input_file))
|
||||
continue
|
||||
|
||||
if not quiet:
|
||||
print("{0}: unchanged".format(input_file))
|
||||
|
||||
|
||||
def convert_dir_save(format_idx, inputdir, outputdir, package, templatedir, temporarydir, prefix, quiet=False):
|
||||
"""
|
||||
Converts all .msg files in inputdir to uORB header files
|
||||
Unchanged existing files are not overwritten.
|
||||
"""
|
||||
# Create new headers in temporary output directory
|
||||
convert_dir(format_idx, inputdir, temporarydir, package, templatedir)
|
||||
if generate_idx == 1:
|
||||
generate_topics_list_file(inputdir, temporarydir, TOPICS_LIST_TEMPLATE_FILE[1], templatedir)
|
||||
# Copy changed headers from temporary dir to output dir
|
||||
copy_changed(temporarydir, outputdir, prefix, quiet)
|
||||
|
||||
|
||||
def generate_topics_list_file(msgdir, outputdir, template_filename, templatedir):
|
||||
# generate cpp file with topics list
|
||||
msgs = get_msgs_list(msgdir)
|
||||
multi_topics = []
|
||||
for msg in msgs:
|
||||
msg_filename = os.path.join(msgdir, msg)
|
||||
multi_topics.extend(get_multi_topics(msg_filename))
|
||||
tl_globals = {"msgs": msgs, "multi_topics": multi_topics}
|
||||
tl_template_file = os.path.join(templatedir, template_filename)
|
||||
tl_out_file = os.path.join(outputdir, template_filename.replace(".em", ""))
|
||||
generate_by_template(tl_out_file, tl_template_file, tl_globals)
|
||||
|
||||
|
||||
def generate_topics_list_file_from_files(files, outputdir, template_filename, templatedir):
|
||||
# generate cpp file with topics list
|
||||
filenames = [os.path.basename(
|
||||
p) for p in files if os.path.basename(p).endswith(".msg")]
|
||||
multi_topics = []
|
||||
for msg_filename in files:
|
||||
multi_topics.extend(get_multi_topics(msg_filename))
|
||||
tl_globals = {"msgs": filenames, "multi_topics": multi_topics}
|
||||
tl_template_file = os.path.join(templatedir, template_filename)
|
||||
tl_out_file = os.path.join(outputdir, template_filename.replace(".em", ""))
|
||||
generate_by_template(tl_out_file, tl_template_file, tl_globals)
|
||||
|
||||
|
||||
def append_to_include_path(path_to_append, curr_include, package):
|
||||
for p in path_to_append:
|
||||
curr_include.append('%s:%s' % (package, p))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Convert msg files to uorb headers/sources')
|
||||
parser.add_argument('--headers', help='Generate header files',
|
||||
action='store_true')
|
||||
parser.add_argument('--sources', help='Generate source files',
|
||||
action='store_true')
|
||||
parser.add_argument('-d', dest='dir', help='directory with msg files')
|
||||
parser = argparse.ArgumentParser(description='Convert msg files to uorb headers')
|
||||
parser.add_argument('-f', dest='file',
|
||||
help="files to convert (use only without -d)",
|
||||
nargs="+")
|
||||
@@ -500,14 +253,9 @@ if __name__ == "__main__":
|
||||
help='package name')
|
||||
parser.add_argument('-o', dest='outputdir',
|
||||
help='output directory for header files')
|
||||
parser.add_argument('-t', dest='temporarydir',
|
||||
help='temporary directory')
|
||||
parser.add_argument('-p', dest='prefix', default='',
|
||||
help='string added as prefix to the output file '
|
||||
' name when converting directories')
|
||||
parser.add_argument('-q', dest='quiet', default=False, action='store_true',
|
||||
help='string added as prefix to the output file '
|
||||
' name when converting directories')
|
||||
parser.add_argument('--constrained-flash', dest='constrained_flash', default=False, action='store_true',
|
||||
help='set to save flash space')
|
||||
args = parser.parse_args()
|
||||
@@ -517,27 +265,6 @@ if __name__ == "__main__":
|
||||
|
||||
CONSTRAINED_FLASH = args.constrained_flash
|
||||
|
||||
if args.headers:
|
||||
generate_idx = 0
|
||||
elif args.sources:
|
||||
generate_idx = 1
|
||||
else:
|
||||
print('Error: either --headers or --sources must be specified')
|
||||
exit(-1)
|
||||
if args.file is not None:
|
||||
for f in args.file:
|
||||
generate_output_from_file(
|
||||
generate_idx, f, args.temporarydir, args.package, args.templatedir, INCL_DEFAULT)
|
||||
|
||||
generate_topics_list_file_from_files(args.file, args.outputdir, TOPICS_LIST_TEMPLATE_FILE[generate_idx], args.templatedir)
|
||||
copy_changed(args.temporarydir, args.outputdir, args.prefix, args.quiet)
|
||||
elif args.dir is not None:
|
||||
convert_dir_save(
|
||||
generate_idx,
|
||||
args.dir,
|
||||
args.outputdir,
|
||||
args.package,
|
||||
args.templatedir,
|
||||
args.temporarydir,
|
||||
args.prefix,
|
||||
args.quiet)
|
||||
generate_output_from_file(f, args.outputdir, args.package, args.templatedir, INCL_DEFAULT)
|
||||
|
||||
@@ -41,6 +41,7 @@ precompiled and thus message generation will be much faster
|
||||
|
||||
import os
|
||||
import errno
|
||||
import re
|
||||
|
||||
import genmsg.msgs
|
||||
|
||||
@@ -257,6 +258,7 @@ def print_field_def(field):
|
||||
type_prefix = ''
|
||||
if (sl_pos >= 0):
|
||||
type_name = type_name[sl_pos + 1:]
|
||||
type_name = re.sub(r'(?<!^)(?=[A-Z])', '_', type_name).lower() # PascalCase to snake_case
|
||||
type_prefix = 'struct '
|
||||
type_appendix = '_s'
|
||||
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
################################################################################
|
||||
#
|
||||
# Copyright (c) 2018-2021 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
import errno
|
||||
import os
|
||||
from typing import Dict, List, Tuple
|
||||
import yaml
|
||||
|
||||
|
||||
class Classifier():
|
||||
"""Class to classify RTPS msgs as to send, receive and set their IDs."""
|
||||
|
||||
def __init__(self, yaml_file, msg_folder) -> None:
|
||||
self.msg_folder = msg_folder
|
||||
self.msg_map = self.parse_yaml_msgs_file(yaml_file)
|
||||
|
||||
# Check if base types are defined correctly
|
||||
self.check_base_type()
|
||||
|
||||
# Get messages to send and to receive
|
||||
self.msgs_to_send: Dict[str, int] = dict()
|
||||
self.msgs_to_receive: Dict[str, int] = dict()
|
||||
self.alias_msgs_to_send: List[Tuple[str, str]] = []
|
||||
self.alias_msgs_to_receive: List[Tuple[str, str]] = []
|
||||
self.msg_list: List[str] = []
|
||||
|
||||
# Create message map
|
||||
self.setup_msg_map()
|
||||
|
||||
self.msg_files_send = self.set_msg_files_send()
|
||||
self.msg_files_receive = self.set_msg_files_receive()
|
||||
|
||||
def setup_msg_map(self) -> None:
|
||||
"""Setup dictionary with an ID map for the messages."""
|
||||
for topic in self.msg_map['rtps']:
|
||||
if 'send' in list(topic.keys()):
|
||||
if 'base' in list(topic.keys()):
|
||||
self.alias_msgs_to_send.append(
|
||||
(topic['msg'], topic['base']))
|
||||
else:
|
||||
self.msgs_to_send.update({topic['msg']: 0})
|
||||
if 'receive' in list(topic.keys()):
|
||||
if 'base' in list(topic.keys()):
|
||||
self.alias_msgs_to_receive.append(
|
||||
(topic['msg'], topic['base']))
|
||||
else:
|
||||
self.msgs_to_receive.update({topic['msg']: 0})
|
||||
self.msg_list.append(topic['msg'])
|
||||
|
||||
def set_msg_files_send(self) -> list:
|
||||
"""
|
||||
Append the path to the files which messages are marked to
|
||||
be sent.
|
||||
"""
|
||||
return [os.path.join(self.msg_folder, msg + ".msg")
|
||||
for msg in list(self.msgs_to_send.keys())]
|
||||
|
||||
def set_msg_files_receive(self) -> list:
|
||||
"""
|
||||
Append the path to the files which messages are marked to
|
||||
be received.
|
||||
"""
|
||||
return [os.path.join(self.msg_folder, msg + ".msg")
|
||||
for msg in list(self.msgs_to_receive.keys())]
|
||||
|
||||
def check_base_type(self) -> None:
|
||||
"""Check if alias message has correct base type."""
|
||||
registered_alias_msgs = list(
|
||||
topic['base'] for topic in self.msg_map['rtps'] if 'base' in list(topic.keys()))
|
||||
|
||||
base_types = []
|
||||
for topic in self.msg_map['rtps']:
|
||||
if 'base' not in list(topic.keys()):
|
||||
base_types.append(topic['msg'])
|
||||
|
||||
incorrect_base_types = list(
|
||||
set(registered_alias_msgs) - set(base_types))
|
||||
|
||||
base_types_suggestion = {}
|
||||
for incorrect in incorrect_base_types:
|
||||
base_types_suggestion.update({incorrect: difflib.get_close_matches(
|
||||
incorrect, base_types, n=1, cutoff=0.6)})
|
||||
|
||||
if len(base_types_suggestion) > 0:
|
||||
raise AssertionError(
|
||||
('\n' + '\n'.join('\t- The multi-topic message base type \'{}\' does not exist.{}'.format(k, (' Did you mean \'' + v[0] + '\'?' if v else '')) for k, v in list(base_types_suggestion.items()))))
|
||||
|
||||
@staticmethod
|
||||
def parse_yaml_msgs_file(yaml_file) -> dict:
|
||||
"""Parses a yaml file into a dict."""
|
||||
try:
|
||||
with open(yaml_file, 'r') as file:
|
||||
return yaml.safe_load(file)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
raise IOError(errno.ENOENT, os.strerror(
|
||||
errno.ENOENT), yaml_file)
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument("-s", "--send", dest='send',
|
||||
action="store_true", help="Get topics to be sent")
|
||||
parser.add_argument("-a", "--alias", dest='alias',
|
||||
action="store_true", help="Get alias topics")
|
||||
parser.add_argument("-r", "--receive", dest='receive',
|
||||
action="store_true", help="Get topics to be received")
|
||||
parser.add_argument("-i", "--ignore", dest='ignore',
|
||||
action="store_true", help="Get topics to be ignored")
|
||||
parser.add_argument("-p", "--path", dest='path',
|
||||
action="store_true", help="Get msgs and its paths")
|
||||
parser.add_argument("-m", "--topic-msg-dir", dest='msgdir', type=str,
|
||||
help="Topics message dir, by default msg/", default="msg")
|
||||
parser.add_argument("-y", "--rtps-ids-file", dest='yaml_file', type=str,
|
||||
help="RTPS msg IDs definition file absolute path, by default use relative path to msg, tools/urtps_bridge_topics.yaml",
|
||||
default='tools/urtps_bridge_topics.yaml')
|
||||
|
||||
# Parse arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
msg_dir = args.msgdir
|
||||
if args.msgdir == 'msg':
|
||||
msg_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
else:
|
||||
msg_dir = os.path.abspath(args.msgdir)
|
||||
classifier = (Classifier(os.path.abspath(args.yaml_file), msg_dir) if os.path.isabs(args.yaml_file)
|
||||
else Classifier(os.path.join(msg_dir, args.yaml_file), msg_dir))
|
||||
|
||||
if args.send:
|
||||
if args.path:
|
||||
print(('send files: ' + ', '.join(str(msg_file)
|
||||
for msg_file in classifier.msg_files_send) + '\n'))
|
||||
else:
|
||||
if args.alias:
|
||||
print((', '.join(str(msg)
|
||||
for msg in sorted(classifier.msgs_to_send)) + (' alias ' + ', '.join(msg[0]
|
||||
for msg in classifier.alias_msgs_to_send) if len(classifier.alias_msgs_to_send) > 0 else '') + '\n'))
|
||||
else:
|
||||
print((', '.join(str(msg)
|
||||
for msg in sorted(classifier.msgs_to_send))))
|
||||
if args.receive:
|
||||
if args.path:
|
||||
print(('receive files: ' + ', '.join(str(msg_file)
|
||||
for msg_file in classifier.msg_files_receive) + '\n'))
|
||||
else:
|
||||
if args.alias:
|
||||
print((', '.join(str(msg)
|
||||
for msg in sorted(classifier.msgs_to_receive)) + (' alias ' + ', '.join(msg[0]
|
||||
for msg in classifier.alias_msgs_to_receive) if len(classifier.alias_msgs_to_receive) > 0 else '') + '\n'))
|
||||
else:
|
||||
print((', '.join(str(msg)
|
||||
for msg in sorted(classifier.msgs_to_receive))))
|
||||
@@ -1,127 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to parse uORB message format to ROS msg format
|
||||
Adapted from https://github.com/eProsima/px4_to_ros/blob/master/px4_to_ros2_PoC/px4_msgs/scripts/copy_and_rename.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from shutil import copyfile
|
||||
|
||||
__author__ = 'PX4 Development Team'
|
||||
__copyright__ = \
|
||||
'''
|
||||
'
|
||||
' Copyright (c) 2018 PX4 Development Team. All rights reserved.
|
||||
'
|
||||
' Redistribution and use in source and binary forms, or without
|
||||
' modification, permitted provided that the following conditions
|
||||
' are met:
|
||||
'
|
||||
' 1. Redistributions of source code must retain the above copyright
|
||||
' notice, list of conditions and the following disclaimer.
|
||||
' 2. Redistributions in binary form must reproduce the above copyright
|
||||
' notice, list of conditions and the following disclaimer in
|
||||
' the documentation and/or other materials provided with the
|
||||
' distribution.
|
||||
' 3. Neither the name PX4 nor the names of its contributors may be
|
||||
' used to endorse or promote products derived from self software
|
||||
' without specific prior written permission.
|
||||
'
|
||||
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, NOT
|
||||
' LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
' FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
' COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
' INCIDENTAL, SPECIAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
' BUT NOT LIMITED TO, OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
' OF USE, DATA, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
' AND ON ANY THEORY OF LIABILITY, IN CONTRACT, STRICT
|
||||
' LIABILITY, TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
' ANY WAY OUT OF THE USE OF THIS SOFTWARE, IF ADVISED OF THE
|
||||
' POSSIBILITY OF SUCH DAMAGE.
|
||||
'
|
||||
'''
|
||||
__credits__ = ['Nuno Marques <nuno.marques@dronesolution.io>']
|
||||
__license__ = 'BSD-3-Clause'
|
||||
__version__ = '0.1.0'
|
||||
__maintainer__ = 'Nuno Marques'
|
||||
__email__ = 'nuno.marques@dronesolution.io'
|
||||
__status__ = 'Development'
|
||||
|
||||
input_dir = sys.argv[1]
|
||||
output_dir = sys.argv[2]
|
||||
|
||||
|
||||
def main():
|
||||
print("----------------------- \033[1mmicroRTPS bridge uORB to ROS messages\033[0m -----------------------")
|
||||
print("-------------------------------------------------------------------------------------------------------")
|
||||
|
||||
if not os.path.exists(os.path.abspath(output_dir)):
|
||||
os.mkdir(os.path.abspath(output_dir))
|
||||
else:
|
||||
ros_msg_dir = os.path.abspath(output_dir)
|
||||
msg_files = os.listdir(ros_msg_dir)
|
||||
for msg in msg_files:
|
||||
if msg.endswith(".msg"):
|
||||
os.remove(os.path.join(ros_msg_dir, msg))
|
||||
|
||||
msg_list = list()
|
||||
|
||||
for filename in os.listdir(input_dir):
|
||||
if '.msg' in filename:
|
||||
msg_list.append(filename.rstrip('.msg'))
|
||||
input_file = input_dir + filename
|
||||
|
||||
output_file = output_dir + \
|
||||
filename.partition(".")[0].title().replace('_', '') + ".msg"
|
||||
copyfile(input_file, output_file)
|
||||
|
||||
for filename in os.listdir(output_dir):
|
||||
if '.msg' in filename:
|
||||
input_file = output_dir + filename
|
||||
|
||||
fileUpdated = False
|
||||
|
||||
with open(input_file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
newlines = []
|
||||
alias_msgs = []
|
||||
alias_msg_files = []
|
||||
|
||||
for line in lines:
|
||||
for msg_type in msg_list:
|
||||
if ('px4/' + msg_type + ' ') in line:
|
||||
fileUpdated = True
|
||||
line = line.replace(('px4/' + msg_type),
|
||||
msg_type.partition(".")[0].title().replace('_', ''))
|
||||
|
||||
if re.findall('^' + msg_type + '[\s\[]', line.partition('#')[0]):
|
||||
fileUpdated = True
|
||||
line = line.replace(msg_type,
|
||||
msg_type.partition(".")[0].title().replace('_', ''))
|
||||
if '# TOPICS' in line:
|
||||
fileUpdated = True
|
||||
alias_msgs += line.split()
|
||||
alias_msgs.remove('#')
|
||||
alias_msgs.remove('TOPICS')
|
||||
line = line.replace(line, '')
|
||||
newlines.append(line)
|
||||
|
||||
for msg_file in alias_msgs:
|
||||
with open(output_dir + msg_file.partition(".")[0].title().replace('_', '') + ".msg", 'w+') as f:
|
||||
for line in newlines:
|
||||
f.write(line)
|
||||
|
||||
if fileUpdated:
|
||||
with open(input_file, 'w+') as f:
|
||||
for line in newlines:
|
||||
f.write(line)
|
||||
|
||||
print("--\t\t- Generated {} ROS message files in '{}'".format(len(os.listdir(output_dir)), os.path.abspath(output_dir)))
|
||||
print("-------------------------------------------------------------------------------------------------------")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,160 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to read an yaml file containing the microRTPS topics and update the naming convention to PascalCase
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import errno
|
||||
from pathlib import Path
|
||||
import os
|
||||
import six
|
||||
import yaml
|
||||
|
||||
__author__ = 'PX4 Development Team'
|
||||
__copyright__ = \
|
||||
'''
|
||||
'
|
||||
' Copyright (c) 2018-2021 PX4 Development Team. All rights reserved.
|
||||
'
|
||||
' Redistribution and use in source and binary forms, or without
|
||||
' modification, permitted provided that the following conditions
|
||||
' are met:
|
||||
'
|
||||
' 1. Redistributions of source code must retain the above copyright
|
||||
' notice, list of conditions and the following disclaimer.
|
||||
' 2. Redistributions in binary form must reproduce the above copyright
|
||||
' notice, list of conditions and the following disclaimer in
|
||||
' the documentation and/or other materials provided with the
|
||||
' distribution.
|
||||
' 3. Neither the name PX4 nor the names of its contributors may be
|
||||
' used to endorse or promote products derived from self software
|
||||
' without specific prior written permission.
|
||||
'
|
||||
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, NOT
|
||||
' LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
' FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
' COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
' INCIDENTAL, SPECIAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
' BUT NOT LIMITED TO, OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
' OF USE, DATA, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
' AND ON ANY THEORY OF LIABILITY, IN CONTRACT, STRICT
|
||||
' LIABILITY, TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
' ANY WAY OUT OF THE USE OF THIS SOFTWARE, IF ADVISED OF THE
|
||||
' POSSIBILITY OF SUCH DAMAGE.
|
||||
'
|
||||
'''
|
||||
__credits__ = ['Nuno Marques <nuno.marques@dronesolution.io>']
|
||||
__license__ = 'BSD-3-Clause'
|
||||
__version__ = '0.1.0'
|
||||
__maintainer__ = 'Nuno Marques'
|
||||
__email__ = 'nuno.marques@dronesolution.io'
|
||||
__status__ = 'Development'
|
||||
|
||||
verbose = False
|
||||
|
||||
|
||||
class IndenterDumper(yaml.Dumper):
|
||||
""" Custom dumper for yaml files that apply the correct indentation """
|
||||
|
||||
def increase_indent(self, flow=False, indentless=False):
|
||||
return super(IndenterDumper, self).increase_indent(flow, False)
|
||||
|
||||
|
||||
def load_yaml_file(file):
|
||||
"""
|
||||
Open yaml file and parse the data into a list of dict
|
||||
|
||||
:param file: the yaml file to load
|
||||
:returns: the list of dictionaries that represent the topics to send and receive
|
||||
:raises IOError: raises and error when the file is not found
|
||||
"""
|
||||
try:
|
||||
with open(file, 'r') as f:
|
||||
if verbose:
|
||||
print(("--\t\t- '%s' file loaded" % file))
|
||||
return yaml.safe_load(f)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), file)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def update_dict(list):
|
||||
"""
|
||||
Update the message naming on the dictionary to fit the PascalCase convention
|
||||
|
||||
:param file: the list of dicts to be updated
|
||||
"""
|
||||
if verbose:
|
||||
num_of_msgs = 0
|
||||
for i, dictionary in enumerate(list["rtps"]):
|
||||
list["rtps"][i] = {k: v.title().replace('_', '') if isinstance(
|
||||
v, six.string_types) else v for k, v in six.iteritems(dictionary)}
|
||||
if verbose:
|
||||
num_of_msgs += 1
|
||||
if verbose:
|
||||
print(("--\t\t- %d ROS message file names updated" % num_of_msgs))
|
||||
|
||||
|
||||
def update_yaml_file(list, in_file, out_file):
|
||||
"""
|
||||
Open the yaml file to dump the new list of dict toself.
|
||||
|
||||
:param list: the list of updated dicts
|
||||
:param file: the yaml file to load and write the new data
|
||||
:raises IOError: raises and error when the file is not found
|
||||
"""
|
||||
try:
|
||||
with open(out_file, 'w') as f:
|
||||
f.write("# AUTOGENERATED-FILE! DO NOT MODIFY IT DIRECTLY.\n#"
|
||||
" Edit instead the same file under PX4-Autopilot/msg/tools and"
|
||||
" use the \n# PX4-Autopilot/msg/tools/uorb_to_ros_urtps_topics.py"
|
||||
" to regenerate this file.\n")
|
||||
yaml.dump(list, f, Dumper=IndenterDumper, default_flow_style=False)
|
||||
if verbose:
|
||||
if in_file == out_file:
|
||||
print(("--\t\t- '%s' updated" % in_file))
|
||||
else:
|
||||
print(("--\t\t- '%s' created" % out_file))
|
||||
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), out_file)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Read an yaml file containing the microRTPS topics and update the naming convention to PascalCase')
|
||||
optional = parser._action_groups.pop()
|
||||
required = parser.add_argument_group('Required')
|
||||
required.add_argument("-i", "--input-file", dest="input_file",
|
||||
help="Yaml file to read", metavar="INFILE")
|
||||
optional.add_argument("-o", "--output-file", dest="output_file",
|
||||
help="Yaml file to dump. If not set, it is the same as the input",
|
||||
metavar="OUTFILE", default="")
|
||||
optional.add_argument("-q", "--quiet", action="store_false", dest="verbose",
|
||||
default=True, help="Don't print status messages to stdout")
|
||||
|
||||
args = parser.parse_args()
|
||||
global verbose
|
||||
verbose = args.verbose
|
||||
in_file = Path(args.input_file)
|
||||
out_file = Path(args.output_file) if (
|
||||
Path(args.output_file) != in_file and Path(args.output_file) != "") else in_file
|
||||
|
||||
if verbose:
|
||||
print("---------------------- \033[1mmicroRTPS bridge yaml PX4 to ROS topics\033[0m ----------------------")
|
||||
print("-------------------------------------------------------------------------------------------------------")
|
||||
|
||||
list = load_yaml_file(in_file)
|
||||
update_dict(list)
|
||||
update_yaml_file(list, in_file, out_file)
|
||||
if verbose:
|
||||
print("-------------------------------------------------------------------------------------------------------")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,91 +0,0 @@
|
||||
#####
|
||||
#
|
||||
# This file maps all the topics that are to be used on the microRTPS bridge.
|
||||
# When one wants to add a new topic to the bridge, it should add it to this file
|
||||
# and mark it to be sent or received from the link.
|
||||
# For alias/multi-topic messages (i.e. the ones found on the '#TOPICS' of the
|
||||
# uORB messages), these can be also added, requiring an extra entry ('base') to
|
||||
# define the base message.
|
||||
#
|
||||
# IMPORTANT NOTICE: The IDs of the messages sent on the bridge get generated
|
||||
# according to the order of the messages in this file. To keep consistency and
|
||||
# backwards compatibility, it is recommended that any new message that one wants
|
||||
# to be streamed in the bridge gets added to the end of the list. Any changes
|
||||
# in the middle of the list (additions, removals, replacements) will change also
|
||||
# the current message IDS, which might result with incompatibilities with
|
||||
# previous PX4 versions (where the list with this format got introduced or
|
||||
# subsisted).
|
||||
#
|
||||
# Any updates to this file should be mirrored in both sides of the bridge (i.e.,
|
||||
# PX4 and px4_ros_com), when using it with ROS2. That can be easily done using
|
||||
# the 'msg/tools/uorb_to_ros_urtps_topics.py' script to regenerate this same
|
||||
# file under 'px4_ros_com/templates/''. The same is not applicable/required if
|
||||
# using this bridge with "raw" RTPS/DDS applications, since the microRTPS agent
|
||||
# to be used and stored in 'build/<px4_target>/src/modules/micrortps_bridge/''
|
||||
# gets generated using this same list.
|
||||
#
|
||||
#####
|
||||
rtps:
|
||||
# topic ID 1
|
||||
- msg: debug_array
|
||||
receive: true
|
||||
# topic ID 2
|
||||
- msg: debug_key_value
|
||||
receive: true
|
||||
# topic ID 3
|
||||
- msg: debug_value
|
||||
receive: true
|
||||
# ...
|
||||
- msg: debug_vect
|
||||
receive: true
|
||||
- msg: offboard_control_mode
|
||||
receive: true
|
||||
- msg: optical_flow
|
||||
receive: true
|
||||
- msg: position_setpoint
|
||||
receive: true
|
||||
- msg: position_setpoint_triplet
|
||||
receive: true
|
||||
- msg: telemetry_status
|
||||
receive: true
|
||||
- msg: timesync
|
||||
receive: true
|
||||
send: true
|
||||
- msg: trajectory_waypoint
|
||||
send: true
|
||||
- msg: vehicle_command
|
||||
receive: true
|
||||
- msg: vehicle_control_mode
|
||||
send: true
|
||||
- msg: vehicle_local_position_setpoint
|
||||
receive: true
|
||||
- msg: trajectory_setpoint # multi-topic / alias of vehicle_local_position_setpoint
|
||||
base: vehicle_local_position_setpoint
|
||||
receive: true
|
||||
- msg: vehicle_odometry
|
||||
send: true
|
||||
- msg: vehicle_mocap_odometry # multi-topic / alias of vehicle_odometry
|
||||
base: vehicle_odometry
|
||||
receive: true
|
||||
- msg: vehicle_visual_odometry # multi-topic / alias of vehicle_odometry
|
||||
base: vehicle_odometry
|
||||
receive: true
|
||||
- msg: vehicle_status
|
||||
send: true
|
||||
- msg: vehicle_trajectory_waypoint
|
||||
receive: true
|
||||
- msg: vehicle_trajectory_waypoint_desired # multi-topic / alias of vehicle_trajectory_waypoint
|
||||
base: vehicle_trajectory_waypoint
|
||||
send: true
|
||||
- msg: collision_constraints
|
||||
send: true
|
||||
- msg: onboard_computer_status
|
||||
receive: true
|
||||
- msg: trajectory_bezier
|
||||
receive: true
|
||||
- msg: vehicle_trajectory_bezier
|
||||
receive: true
|
||||
- msg: timesync_status
|
||||
send: true
|
||||
- msg: sensor_combined
|
||||
send: true
|
||||
Reference in New Issue
Block a user