feat(slam): add cartographer_ros

This commit is contained in:
X-lanni
2025-07-04 14:39:48 +08:00
parent df9cee5779
commit 5cf886315d
825 changed files with 92220 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
**/Dockerfile*
**/.dockerignore
**/.git
**/.travis.yml
+19
View File
@@ -0,0 +1,19 @@
---
name: Bug report
about: Report a bug that you've found in this repository or in a release.
---
Please provide information for your bug report:
- if you're using cartographer_ros from source, provide the Git commit hash
(via `git log -1 --format="%H"`):
- if you're using a release package, provide the version
(e.g. via `apt show <package_name>`):
- provide all information that is needed to analyze and reproduce the bug
(logs, commands that have been used, ...)
PLEASE NOTE: we don't support custom forks or extensions.
If you need tuning advice, you can open a tuning issue instead.
@@ -0,0 +1,5 @@
---
name: General issue
about: Use this issue for general questions.
---
@@ -0,0 +1,30 @@
---
name: Help request for tuning
about: Describe tuning problems with your custom Cartographer setup to request help from the community.
---
To improve the chances that other Cartographer users can help you,
here are some guidelines for describing your tuning problem:
1. check the tuning guide on the documentation page and previous issues -
some problems might have been solved already by other people.
2. run `rosbag_validate` which does some checks on your sensor data. This
tool often finds issues that can explain poor performance and must be fixed
at recording time. Please post the full output of the tool into a
GitHub Gist at https://gist.github.com/, then link it in the issue even if
it does not report anything. You can run the tool like this:
rosrun cartographer_ros cartographer_rosbag_validate -bag_filename <bag filename>
3. post a link to a Git repository containing a branch of
`cartographer_ros` containing all the configuration, launch, and URDF files
required to reproduce your issue.
4. post a link to a bag file we can use to reproduce your issue. Put it on
Google Drive, Dropbox, any webserver or wherever it is publicly
downloadable.
5. remove this boilerplate text before submitting your issue.
PLEASE NOTE: tuning issues are not necessarily handled by the maintainers and
can be closed after a period of inactivity.
+2
View File
@@ -0,0 +1,2 @@
Want to contribute? Great! Make sure you've read and understood
[CONTRIBUTING.md](https://github.com/cartographer-project/cartographer_ros/blob/master/CONTRIBUTING.md).
+38
View File
@@ -0,0 +1,38 @@
# Copyright 2018 The Cartographer Authors
#
# 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.
sudo: required
services: docker
# Cache intermediate Docker layers. For a description of how this works, see:
# https://giorgos.sealabs.net/docker-cache-on-travis-and-docker-112.html
cache:
directories:
- /home/travis/docker/
env:
- ROS_RELEASE=kinetic DOCKER_CACHE_FILE=/home/travis/docker/kinetic-cache.tar.gz
- ROS_RELEASE=melodic DOCKER_CACHE_FILE=/home/travis/docker/melodic-cache.tar.gz
- ROS_RELEASE=noetic DOCKER_CACHE_FILE=/home/travis/docker/noetic-cache.tar.gz
before_install:
# $GITHUB_TOKEN must be a valid GitHub access token without access rights (https://github.com/settings/tokens).
# Either add your token to the 'env' section above or add it as an unencrypted variable in the Travis settings.
- scripts/check_access_token.sh $GITHUB_TOKEN
- scripts/load_docker_cache.sh
install: true
script:
- docker build ${TRAVIS_BUILD_DIR} -t cartographer_ros:${ROS_RELEASE} -f Dockerfile.${ROS_RELEASE} --build-arg github_token=${GITHUB_TOKEN}
- scripts/save_docker_cache.sh
+7
View File
@@ -0,0 +1,7 @@
# This is the list of Cartographer authors for copyright purposes.
#
# This does not necessarily list everyone who has contributed code, since in
# some cases, their employer may be the copyright holder. To see the full list
# of contributors, see the revision history in source control.
Google Inc.
and other contributors
+51
View File
@@ -0,0 +1,51 @@
Want to contribute? Great! First, read this page.
### Before you contribute
Any contribution that you make to this repository will
be under the Apache 2 License, as dictated by that
[license](http://www.apache.org/licenses/LICENSE-2.0):
```
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
```
### Developer Certificate of Origin
Contributors must sign-off each commit by adding a `Signed-off-by: ...`
line to commit messages to certify that they have the right to submit
the code they are contributing to the project according to the
[Developer Certificate of Origin (DCO)](https://developercertificate.org/).
You can sign-off a commit via `git commit -s`.
### Code reviews
All submissions, including submissions by project members, require review.
We use GitHub pull requests for this purpose. Make sure you've read,
understood and considered all the points below before creating your PR.
#### Style guide
C++ code should adhere to the
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html).
You can handle the formatting part of the style guide via `git clang-format`.
#### Best practices
When preparing your PR and also during the code review make sure to follow
[best practices](https://google.github.io/eng-practices/review/developer/).
Most importantly, keep your PR under 200 lines of code and address a single
concern.
#### Testing
- Add unit tests and documentation (these do not count toward your 200 lines).
- Run tests as appropriate, e.g. `docker build . -t cartographer:noetic -f Dockerfile.noetic`.
- Keep rebasing (or merging) of master branch to a minimum. It triggers Travis
runs for every update which blocks merging of other changes.
+80
View File
@@ -0,0 +1,80 @@
# Copyright 2016 The Cartographer Authors
#
# 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 osrf/ros:kinetic-desktop
ARG CARTOGRAPHER_VERSION=master
# We require a GitHub access token to be passed.
ARG github_token
# Xenial's base image doesn't ship with sudo.
RUN apt-get update && apt-get install -y sudo
# First, we invalidate the entire cache if cartographer-project/cartographer has
# changed. This file's content changes whenever master changes. See:
# http://stackoverflow.com/questions/36996046/how-to-prevent-dockerfile-caching-git-clone
ADD https://api.github.com/repos/cartographer-project/cartographer/git/refs/heads/master?access_token=$github_token \
cartographer_ros/cartographer_version.json
# wstool needs the updated rosinstall file to clone the correct repos.
COPY cartographer_ros.rosinstall cartographer_ros/
COPY scripts/prepare_catkin_workspace.sh cartographer_ros/scripts/
RUN CARTOGRAPHER_VERSION=$CARTOGRAPHER_VERSION \
cartographer_ros/scripts/prepare_catkin_workspace.sh
# rosdep needs the updated package.xml files to install the correct debs.
COPY cartographer_ros/package.xml catkin_ws/src/cartographer_ros/cartographer_ros/
COPY cartographer_ros_msgs/package.xml catkin_ws/src/cartographer_ros/cartographer_ros_msgs/
COPY cartographer_rviz/package.xml catkin_ws/src/cartographer_ros/cartographer_rviz/
COPY scripts/install_debs.sh cartographer_ros/scripts/
RUN cartographer_ros/scripts/install_debs.sh
# Install Abseil and proto3.
RUN /catkin_ws/src/cartographer/scripts/install_abseil.sh
RUN /catkin_ws/src/cartographer/scripts/install_proto3.sh
# Build, install, and test all packages individually to allow caching. The
# ordering of these steps must match the topological package ordering as
# determined by Catkin.
COPY scripts/install.sh cartographer_ros/scripts/
COPY scripts/catkin_test_results.sh cartographer_ros/scripts/
RUN cartographer_ros/scripts/install.sh --pkg cartographer && \
cartographer_ros/scripts/install.sh --pkg cartographer --make-args test
COPY cartographer_ros_msgs catkin_ws/src/cartographer_ros/cartographer_ros_msgs/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_ros_msgs && \
cartographer_ros/scripts/install.sh --pkg cartographer_ros_msgs \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_ros_msgs
COPY cartographer_ros catkin_ws/src/cartographer_ros/cartographer_ros/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_ros && \
cartographer_ros/scripts/install.sh --pkg cartographer_ros \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_ros
COPY cartographer_rviz catkin_ws/src/cartographer_ros/cartographer_rviz/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_rviz && \
cartographer_ros/scripts/install.sh --pkg cartographer_rviz \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_rviz
COPY scripts/ros_entrypoint.sh /
RUN rm -rf /var/lib/apt/lists/*
# A BTRFS bug may prevent us from cleaning up these directories.
# https://btrfs.wiki.kernel.org/index.php/Problem_FAQ#I_cannot_delete_an_empty_directory
RUN rm -rf cartographer_ros catkin_ws || true
+79
View File
@@ -0,0 +1,79 @@
# Copyright 2018 The Cartographer Authors
#
# 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 osrf/ros:melodic-desktop
ARG CARTOGRAPHER_VERSION=master
# We require a GitHub access token to be passed.
ARG github_token
# Bionic's base image doesn't ship with sudo.
RUN apt-get update && apt-get install -y sudo
# First, we invalidate the entire cache if cartographer-project/cartographer has
# changed. This file's content changes whenever master changes. See:
# http://stackoverflow.com/questions/36996046/how-to-prevent-dockerfile-caching-git-clone
ADD https://api.github.com/repos/cartographer-project/cartographer/git/refs/heads/master?access_token=$github_token \
cartographer_ros/cartographer_version.json
# wstool needs the updated rosinstall file to clone the correct repos.
COPY cartographer_ros.rosinstall cartographer_ros/
COPY scripts/prepare_catkin_workspace.sh cartographer_ros/scripts/
RUN CARTOGRAPHER_VERSION=$CARTOGRAPHER_VERSION \
cartographer_ros/scripts/prepare_catkin_workspace.sh
# rosdep needs the updated package.xml files to install the correct debs.
COPY cartographer_ros/package.xml catkin_ws/src/cartographer_ros/cartographer_ros/
COPY cartographer_ros_msgs/package.xml catkin_ws/src/cartographer_ros/cartographer_ros_msgs/
COPY cartographer_rviz/package.xml catkin_ws/src/cartographer_ros/cartographer_rviz/
COPY scripts/install_debs.sh cartographer_ros/scripts/
RUN cartographer_ros/scripts/install_debs.sh
# Install Abseil.
RUN /catkin_ws/src/cartographer/scripts/install_abseil.sh
# Build, install, and test all packages individually to allow caching. The
# ordering of these steps must match the topological package ordering as
# determined by Catkin.
COPY scripts/install.sh cartographer_ros/scripts/
COPY scripts/catkin_test_results.sh cartographer_ros/scripts/
RUN cartographer_ros/scripts/install.sh --pkg cartographer && \
cartographer_ros/scripts/install.sh --pkg cartographer --make-args test
COPY cartographer_ros_msgs catkin_ws/src/cartographer_ros/cartographer_ros_msgs/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_ros_msgs && \
cartographer_ros/scripts/install.sh --pkg cartographer_ros_msgs \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_ros_msgs
COPY cartographer_ros catkin_ws/src/cartographer_ros/cartographer_ros/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_ros && \
cartographer_ros/scripts/install.sh --pkg cartographer_ros \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_ros
COPY cartographer_rviz catkin_ws/src/cartographer_ros/cartographer_rviz/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_rviz && \
cartographer_ros/scripts/install.sh --pkg cartographer_rviz \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_rviz
COPY scripts/ros_entrypoint.sh /
RUN rm -rf /var/lib/apt/lists/*
# A BTRFS bug may prevent us from cleaning up these directories.
# https://btrfs.wiki.kernel.org/index.php/Problem_FAQ#I_cannot_delete_an_empty_directory
RUN rm -rf cartographer_ros catkin_ws || true
+83
View File
@@ -0,0 +1,83 @@
# Copyright 2020 The Cartographer Authors
#
# 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 osrf/ros:noetic-desktop
ARG CARTOGRAPHER_VERSION=master
# We require a GitHub access token to be passed.
ARG github_token
# Prevent any interaction required by apt-get.
# https://stackoverflow.com/questions/22466255
ARG DEBIAN_FRONTEND=noninteractive
# ROS Noetic's base image doesn't ship with sudo and git.
RUN apt-get update && apt-get install -y sudo git
# First, we invalidate the entire cache if cartographer-project/cartographer has
# changed. This file's content changes whenever master changes. See:
# http://stackoverflow.com/questions/36996046/how-to-prevent-dockerfile-caching-git-clone
ADD https://api.github.com/repos/cartographer-project/cartographer/git/refs/heads/master?access_token=$github_token \
cartographer_ros/cartographer_version.json
# wstool needs the updated rosinstall file to clone the correct repos.
COPY cartographer_ros.rosinstall cartographer_ros/
COPY scripts/prepare_catkin_workspace.sh cartographer_ros/scripts/
RUN CARTOGRAPHER_VERSION=$CARTOGRAPHER_VERSION \
cartographer_ros/scripts/prepare_catkin_workspace.sh
# rosdep needs the updated package.xml files to install the correct debs.
COPY cartographer_ros/package.xml catkin_ws/src/cartographer_ros/cartographer_ros/
COPY cartographer_ros_msgs/package.xml catkin_ws/src/cartographer_ros/cartographer_ros_msgs/
COPY cartographer_rviz/package.xml catkin_ws/src/cartographer_ros/cartographer_rviz/
COPY scripts/install_debs.sh cartographer_ros/scripts/
RUN cartographer_ros/scripts/install_debs.sh
# Install Abseil.
RUN /catkin_ws/src/cartographer/scripts/install_abseil.sh
# Build, install, and test all packages individually to allow caching. The
# ordering of these steps must match the topological package ordering as
# determined by Catkin.
COPY scripts/install.sh cartographer_ros/scripts/
COPY scripts/catkin_test_results.sh cartographer_ros/scripts/
RUN cartographer_ros/scripts/install.sh --pkg cartographer && \
cartographer_ros/scripts/install.sh --pkg cartographer --make-args test
COPY cartographer_ros_msgs catkin_ws/src/cartographer_ros/cartographer_ros_msgs/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_ros_msgs && \
cartographer_ros/scripts/install.sh --pkg cartographer_ros_msgs \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_ros_msgs
COPY cartographer_ros catkin_ws/src/cartographer_ros/cartographer_ros/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_ros && \
cartographer_ros/scripts/install.sh --pkg cartographer_ros \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_ros
COPY cartographer_rviz catkin_ws/src/cartographer_ros/cartographer_rviz/
RUN cartographer_ros/scripts/install.sh --pkg cartographer_rviz && \
cartographer_ros/scripts/install.sh --pkg cartographer_rviz \
--catkin-make-args run_tests && \
cartographer_ros/scripts/catkin_test_results.sh build_isolated/cartographer_rviz
COPY scripts/ros_entrypoint.sh /
RUN rm -rf /var/lib/apt/lists/*
# A BTRFS bug may prevent us from cleaning up these directories.
# https://btrfs.wiki.kernel.org/index.php/Problem_FAQ#I_cannot_delete_an_empty_directory
RUN rm -rf cartographer_ros catkin_ws || true
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+60
View File
@@ -0,0 +1,60 @@
.. Copyright 2016 The Cartographer Authors
.. 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.
============================
Cartographer ROS Integration
============================
|build| |docs| |license|
Purpose
=======
`Cartographer`_ is a system that provides real-time simultaneous localization
and mapping (`SLAM`_) in 2D and 3D across multiple platforms and sensor
configurations. This project provides Cartographer's ROS integration.
.. _Cartographer: https://github.com/cartographer-project/cartographer
.. _SLAM: https://en.wikipedia.org/wiki/Simultaneous_localization_and_mapping
Getting started
===============
* Learn to use Cartographer with ROS at `our Read the Docs site`_.
* You can ask a question by `creating an issue`_.
.. _our Read the Docs site: https://google-cartographer-ros.readthedocs.io
.. _creating an issue: https://github.com/cartographer-project/cartographer_ros/issues/new?labels=question
Contributing
============
You can find information about contributing to Cartographer's ROS integration
at `our Contribution page`_.
.. _our Contribution page: https://github.com/cartographer-project/cartographer_ros/blob/master/CONTRIBUTING.md
.. |build| image:: https://travis-ci.org/cartographer-project/cartographer_ros.svg?branch=master
:alt: Build Status
:scale: 100%
:target: https://travis-ci.org/cartographer-project/cartographer_ros
.. |docs| image:: https://readthedocs.org/projects/google-cartographer-ros/badge/?version=latest
:alt: Documentation Status
:scale: 100%
:target: https://google-cartographer-ros.readthedocs.io/en/latest/?badge=latest
.. |license| image:: https://img.shields.io/badge/License-Apache%202.0-blue.svg
:alt: Apache 2 license.
:scale: 100%
:target: https://github.com/cartographer-project/cartographer_ros/blob/master/LICENSE
+70
View File
@@ -0,0 +1,70 @@
# Copyright 2018 The Cartographer Authors
#
# 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.
jobs:
- job: Build
pool:
vmImage: 'vs2017-win2016'
timeoutInMinutes: 360
steps:
- script: |
choco sources add -n=roswin -s https://roswin.azurewebsites.net/api/v2/ --priority 1
rem Azure VM runs out of space on C:, so use D: for ros and rosdeps
mkdir D:\opt && mklink /J C:\opt D:\opt
choco upgrade %ROS_METAPACKAGE% -y
choco upgrade ros-melodic-perception -y
robocopy "." ".\src\cartographer_ros" /E /MOVE /XD "src" > NUL
git clone https://github.com/cartographer-project/cartographer src\cartographer
call "C:\opt\ros\melodic\x64\env.bat" rosdep install --from-paths src --ignore-src -r -y
env:
ROS_METAPACKAGE: 'ros-melodic-desktop'
displayName: Install prerequisites
- script: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "C:\opt\ros\melodic\x64\setup.bat"
call src\cartographer\scripts\remove_mingw_cygwin_from_path.bat
catkin_make_isolated --use-ninja --install --cmake-args -DCMAKE_BUILD_TYPE=Release
displayName: Build
- script: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "C:\opt\ros\melodic\x64\setup.bat"
call src\cartographer\scripts\remove_mingw_cygwin_from_path.bat
cd build_isolated\cartographer\install && ctest --no-compress-output -T Test
displayName: Run cartographer tests
- script: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "C:\opt\ros\melodic\x64\setup.bat"
call src\cartographer\scripts\remove_mingw_cygwin_from_path.bat
cd build_isolated\cartographer_ros && ninja tests && ctest --no-compress-output -T Test
displayName: Build and run cartographer_ros tests
condition: always()
- script: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "C:\opt\ros\melodic\x64\setup.bat"
call src\cartographer\scripts\remove_mingw_cygwin_from_path.bat
python src\cartographer\scripts\ctest_to_junit.py build_isolated\cartographer_ros
displayName: Convert tests to jUnit
condition: always()
- task: PublishTestResults@2
displayName: Publish test results
inputs:
testRunner: 'jUnit'
testResultsFiles: '**\jUnit.xml'
searchFolder: '$(Build.SourcesDirectory)\build_isolated\cartographer_ros\Testing'
condition: always()
@@ -0,0 +1,2 @@
- git: {local-name: cartographer, uri: 'https://github.com/cartographer-project/cartographer.git', version: 'master'}
- git: {local-name: cartographer_ros, uri: 'https://github.com/cartographer-project/cartographer_ros.git', version: 'master'}
@@ -0,0 +1,39 @@
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Changelog for package cartographer_ros
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2.0.9003 (2024-04-17)
---------------------
* Fix build on Rolling. (`#74 <https://github.com/ros2/cartographer_ros/issues/74>`_)
* Contributors: Chris Lalancette
2.0.9002 (2024-03-15)
---------------------
* Fix for newer Google logging.
* Fix warnings when building against recent ROS 2 releases.
* Contributors: Chris Lalancette
2.0.9001 (2023-04-13)
---------------------
* fix cmake to prevent multiple definitions (`#63 <https://github.com/ros2/cartographer_ros/issues/63>`_)
* Contributors: Wolf Vollprecht
2.0.9000 (2022-03-31)
---------------------
* Update to latest upstream, as well as new port to ROS 2.
1.0.0 (2018-06-01)
------------------
* https://github.com/googlecartographer/cartographer_ros/compare/0.3.0...1.0.0
0.3.0 (2017-11-23)
------------------
* https://github.com/googlecartographer/cartographer_ros/compare/0.2.0...0.3.0
0.2.0 (2017-06-19)
------------------
* https://github.com/googlecartographer/cartographer_ros/compare/0.1.0...0.2.0
0.1.0 (2017-05-18)
------------------
* First unstable development release
@@ -0,0 +1,333 @@
# Copyright 2016 The Cartographer Authors
# Copyright 2022 Wyca Robotics (for the ROS2 conversion)
#
# 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.
cmake_minimum_required(VERSION 3.5)
project(cartographer_ros)
find_package(ament_cmake REQUIRED)
# Default to C++17
set(CMAKE_CXX_STANDARD 17)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
find_package(absl REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(cartographer REQUIRED)
find_package(cartographer_ros_msgs REQUIRED)
find_package(Eigen3 REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(gflags REQUIRED)
find_package(glog REQUIRED)
find_package(nav_msgs REQUIRED)
find_package(PCL REQUIRED COMPONENTS common)
find_package(pcl_conversions REQUIRED)
find_package(rclcpp REQUIRED)
find_package(ros_environment REQUIRED)
find_package(rosbag2_cpp REQUIRED)
find_package(rosbag2_storage REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(tf2 REQUIRED)
find_package(tf2_eigen REQUIRED)
find_package(tf2_msgs REQUIRED)
find_package(tf2_ros REQUIRED)
find_package(urdf REQUIRED)
find_package(visualization_msgs REQUIRED)
# glog is not linked, however we look for it to detect the glog version
# and use a different code path if glog >= 0.7.0 is detected
find_package(glog CONFIG QUIET)
if(DEFINED glog_VERSION)
if(NOT glog_VERSION VERSION_LESS 0.7.0)
add_definitions(-DROS_CARTOGRAPHER_GLOG_GE_070)
endif()
endif()
include(FindPkgConfig)
pkg_search_module(CAIRO REQUIRED cairo>=1.12.16)
# Library
add_library(${PROJECT_NAME} STATIC
src/assets_writer.cpp
src/map_builder_bridge.cpp
src/msg_conversion.cpp
src/node_constants.cpp
src/node.cpp
src/node_options.cpp
src/offline_node.cpp
src/playable_bag.cpp
src/ros_log_sink.cpp
src/ros_map.cpp
src/ros_map_writing_points_processor.cpp
src/sensor_bridge.cpp
src/submap.cpp
src/tf_bridge.cpp
src/time_conversion.cpp
src/trajectory_options.cpp
src/urdf_reader.cpp
src/metrics/family_factory.cpp
src/metrics/internal/family.cpp
src/metrics/internal/histogram.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
${CAIRO_INCLUDE_DIRS}
${pcl_conversions_INCLUDE_DIRS}
)
if ("$ENV{ROS_DISTRO}" STRLESS "kilted")
# In Kilted, pcl_conversions was converted over to an INTERFACE target,
# but prior to it it is only available as the INCLUDE_DIRS. So we have this
# compatibility hack to deal with that difference.
target_include_directories(${PROJECT_NAME} PRIVATE ${pcl_conversions_INCLUDE_DIRS})
# In Kilted, urdf/model.h was deprecated in favor of urdf/model.hpp.
# Deal with the difference here so we have no warnings.
target_compile_definitions(${PROJECT_NAME} PRIVATE "-DUSE_URDF_H_FILES")
else()
target_link_libraries(${PROJECT_NAME} PRIVATE pcl_conversions::pcl_conversions)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC
absl::synchronization
${builtin_interfaces_TARGETS}
cartographer
${cartographer_ros_msgs_TARGETS}
${geometry_msgs_TARGETS}
${nav_msgs_TARGETS}
rclcpp::rclcpp
rosbag2_cpp::rosbag2_cpp
rosbag2_storage::rosbag2_storage
${sensor_msgs_TARGETS}
tf2_ros::tf2_ros
${visualization_msgs_TARGETS}
)
target_link_libraries(${PROJECT_NAME} PRIVATE
${CAIRO_LIBRARIES}
pcl_common
${std_msgs_TARGETS}
tf2::tf2
tf2_eigen::tf2_eigen
${tf2_msgs_TARGETS}
urdf::urdf
)
# Executables
add_executable(cartographer_node src/node_main.cpp)
target_include_directories(cartographer_node PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
)
target_link_libraries(cartographer_node PRIVATE
${PROJECT_NAME}
absl::memory
cartographer
gflags
rclcpp::rclcpp
tf2_ros::tf2_ros
)
add_executable(cartographer_occupancy_grid_node src/occupancy_grid_node_main.cpp)
target_include_directories(cartographer_occupancy_grid_node PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
${CAIRO_INCLUDE_DIRS}
)
target_link_libraries(cartographer_occupancy_grid_node PRIVATE
${PROJECT_NAME}
absl::synchronization
cartographer
${cartographer_ros_msgs_TARGETS}
Eigen3::Eigen
gflags
${nav_msgs_TARGETS}
rclcpp::rclcpp
)
add_executable(cartographer_offline_node src/offline_node_main.cpp)
target_include_directories(cartographer_offline_node PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
)
target_link_libraries(cartographer_offline_node PRIVATE
${PROJECT_NAME}
cartographer
gflags
rclcpp::rclcpp
)
add_executable(cartographer_assets_writer src/assets_writer_main.cpp)
target_include_directories(cartographer_assets_writer PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
)
target_link_libraries(cartographer_assets_writer PRIVATE
${PROJECT_NAME}
gflags
glog::glog
rclcpp::rclcpp
)
add_executable(cartographer_pbstream_map_publisher src/pbstream_map_publisher_main.cpp)
target_include_directories(cartographer_pbstream_map_publisher PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
)
target_link_libraries(cartographer_pbstream_map_publisher PRIVATE
${PROJECT_NAME}
cartographer
gflags
glog::glog
${nav_msgs_TARGETS}
rclcpp::rclcpp
)
add_executable(cartographer_pbstream_to_ros_map src/pbstream_to_ros_map_main.cpp)
target_include_directories(cartographer_pbstream_to_ros_map PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
)
target_link_libraries(cartographer_pbstream_to_ros_map PRIVATE
${PROJECT_NAME}
cartographer
gflags
glog::glog
rclcpp::rclcpp
)
add_executable(cartographer_rosbag_validate src/rosbag_validate_main.cpp)
target_include_directories(cartographer_rosbag_validate PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
)
if ("$ENV{ROS_DISTRO}" STRLESS "kilted")
target_compile_definitions(cartographer_rosbag_validate PRIVATE "-DUSE_URDF_H_FILES")
endif()
target_link_libraries(cartographer_rosbag_validate
${PROJECT_NAME}
absl::memory
cartographer
gflags
glog::glog
${nav_msgs_TARGETS}
rclcpp::rclcpp
rosbag2_cpp::rosbag2_cpp
${sensor_msgs_TARGETS}
tf2_eigen::tf2_eigen
${tf2_msgs_TARGETS}
tf2_ros::tf2_ros
urdf::urdf
tf2::tf2
)
if($ENV{ROS_DISTRO} MATCHES "humble" OR $ENV{ROS_DISTRO} MATCHES "iron")
target_compile_definitions(${PROJECT_NAME} PRIVATE PRE_JAZZY_SERIALIZED_BAG_MSG_FIELD_NAME)
target_compile_definitions(cartographer_rosbag_validate PRIVATE PRE_JAZZY_SERIALIZED_BAG_MSG_FIELD_NAME)
endif()
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
install(TARGETS
cartographer_node
cartographer_occupancy_grid_node
cartographer_offline_node
cartographer_assets_writer
cartographer_pbstream_map_publisher
cartographer_pbstream_to_ros_map
cartographer_rosbag_validate
RUNTIME DESTINATION lib/${PROJECT_NAME}
)
install(DIRECTORY include/
DESTINATION include/${PROJECT_NAME}
)
install(DIRECTORY configuration_files urdf launch
DESTINATION share/${PROJECT_NAME}/
)
ament_export_targets(${PROJECT_NAME})
ament_export_include_directories(include/${PROJECT_NAME})
ament_export_libraries(${PROJECT_NAME})
ament_export_dependencies(
absl
builtin_interfaces
cartographer
cartographer_ros_msgs
geometry_msgs
nav_msgs
rclcpp
rosbag2_cpp
rosbag2_storage
sensor_msgs
tf2_ros
visualization_msgs
)
ament_package()
# Non converted bin:
#google_binary(cartographer_dev_pbstream_trajectories_to_rosbag
# SRCS
# dev/pbstream_trajectories_to_rosbag_main.cc
#)
#google_binary(cartographer_dev_rosbag_publisher
# SRCS
# dev/rosbag_publisher_main.cc
#)
#google_binary(cartographer_dev_trajectory_comparison
# SRCS
# dev/trajectory_comparison_main.cc
#)
## TODO(cschuet): Add support for shared library case.
#if (${BUILD_GRPC})
# google_binary(cartographer_grpc_node
# SRCS
# cartographer_grpc/node_grpc_main.cc
# )
# google_binary(cartographer_grpc_offline_node
# SRCS
# cartographer_grpc/offline_node_grpc_main.cc
# )
# install(PROGRAMS
# ../scripts/cartographer_grpc_server.sh
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
#endif()
@@ -0,0 +1,50 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
map_frame = "map",
tracking_frame = "base_footprint",
published_frame = "base_footprint",
odom_frame = "odom",
provide_odom_frame = true,
publish_frame_projected_to_2d = true,
use_pose_extrapolator = true,
use_odometry = true,
use_nav_sat = false,
use_landmarks = false,
num_laser_scans = 1,
num_multi_echo_laser_scans = 0,
num_subdivisions_per_laser_scan = 1,
num_point_clouds = 0,
lookup_transform_timeout_sec = 0.2,
submap_publish_period_sec = 0.3,
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
}
MAP_BUILDER.use_trajectory_builder_2d = true
TRAJECTORY_BUILDER_2D.num_accumulated_range_data = 10
TRAJECTORY_BUILDER_2D.use_imu_data = false
return options
@@ -0,0 +1,131 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
-- WARNING: we create a lot of X-Rays of a potentially large space in this
-- pipeline. For example, running over the
-- cartographer_paper_deutsches_museum.bag requires ~25GiB of memory. You can
-- reduce this by writing fewer X-Rays or upping VOXEL_SIZE - which is the size
-- of a pixel in a X-Ray.
VOXEL_SIZE = 5e-2
include "transform.lua"
options = {
tracking_frame = "base_link",
pipeline = {
{
action = "min_max_range_filter",
min_range = 1.,
max_range = 60.,
},
{
action = "dump_num_points",
},
-- Gray X-Rays. These only use geometry to color pixels.
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_yz_all",
transform = YZ_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xy_all",
transform = XY_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xz_all",
transform = XZ_TRANSFORM,
},
-- We now use the intensities to color our points. We apply a linear
-- transform to clamp our intensity values into [0, 255] and then use this
-- value for RGB of our points. Every stage in the pipeline after this now
-- receives colored points.
--
-- We write xrays again. These now use geometry and the intensities to
-- color pixels - they look quite similar, just a little lighter.
{
action = "intensity_to_color",
min_intensity = 0.,
max_intensity = 4095.,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_yz_all_intensity",
transform = YZ_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xy_all_intensity",
transform = XY_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xz_all_intensity",
transform = XZ_TRANSFORM,
},
-- We also write a PLY file at this stage, because gray points look good.
-- The points in the PLY can be visualized using
-- https://github.com/cartographer-project/point_cloud_viewer.
{
action = "write_ply",
filename = "points.ply",
},
-- Now we recolor our points by frame and write another batch of X-Rays. It
-- is visible in them what was seen by the horizontal and the vertical
-- laser.
{
action = "color_points",
frame_id = "horizontal_laser_link",
color = { 255., 0., 0. },
},
{
action = "color_points",
frame_id = "vertical_laser_link",
color = { 0., 255., 0. },
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_yz_all_color",
transform = YZ_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xy_all_color",
transform = XY_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xz_all_color",
transform = XZ_TRANSFORM,
},
}
}
return options
@@ -0,0 +1,56 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
-- WARNING: we create a lot of X-Rays of a potentially large space in this
-- pipeline. For example, running over the
-- cartographer_paper_deutsches_museum.bag requires ~25GiB of memory. You can
-- reduce this by writing fewer X-Rays or upping VOXEL_SIZE - which is the size
-- of a pixel in a X-Ray.
VOXEL_SIZE = 5e-2
include "transform.lua"
options = {
tracking_frame = "base_link",
pipeline = {
{
action = "min_max_range_filter",
min_range = 1.,
max_range = 60.,
},
{
action = "dump_num_points",
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_yz_all",
transform = YZ_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xy_all",
transform = XY_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xz_all",
transform = XZ_TRANSFORM,
},
}
}
return options
@@ -0,0 +1,86 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
VOXEL_SIZE = 5e-2
include "transform.lua"
options = {
tracking_frame = "base_link",
pipeline = {
{
action = "min_max_range_filter",
min_range = 1.,
max_range = 60.,
},
{
action = "dump_num_points",
},
-- Gray X-Rays. These only use geometry to color pixels.
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_yz_all",
transform = YZ_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xy_all",
transform = XY_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xz_all",
transform = XZ_TRANSFORM,
},
-- Now we recolor our points by frame and write another batch of X-Rays. It
-- is visible in them what was seen by the horizontal and the vertical
-- laser.
{
action = "color_points",
frame_id = "horizontal_vlp16_link",
color = { 255., 0., 0. },
},
{
action = "color_points",
frame_id = "vertical_vlp16_link",
color = { 0., 255., 0. },
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_yz_all_color",
transform = YZ_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xy_all_color",
transform = XY_TRANSFORM,
},
{
action = "write_xray_image",
voxel_size = VOXEL_SIZE,
filename = "xray_xz_all_color",
transform = XZ_TRANSFORM,
},
}
}
return options
@@ -0,0 +1,36 @@
-- Copyright 2018 The Cartographer Authors
--
-- 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.
options = {
tracking_frame = "base_link",
pipeline = {
{
action = "min_max_range_filter",
min_range = 1.,
max_range = 60.,
},
{
action = "write_ros_map",
range_data_inserter = {
insert_free_space = true,
hit_probability = 0.55,
miss_probability = 0.49,
},
filestem = "map",
resolution = 0.05,
}
}
}
return options
@@ -0,0 +1,49 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
map_frame = "map",
tracking_frame = "base_link",
published_frame = "base_link",
odom_frame = "odom",
provide_odom_frame = true,
publish_frame_projected_to_2d = false,
use_pose_extrapolator = true,
use_odometry = false,
use_nav_sat = false,
use_landmarks = false,
num_laser_scans = 0,
num_multi_echo_laser_scans = 1,
num_subdivisions_per_laser_scan = 10,
num_point_clouds = 0,
lookup_transform_timeout_sec = 0.2,
submap_publish_period_sec = 0.3,
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
}
MAP_BUILDER.use_trajectory_builder_2d = true
TRAJECTORY_BUILDER_2D.num_accumulated_range_data = 10
return options
@@ -0,0 +1,22 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "backpack_2d.lua"
TRAJECTORY_BUILDER.pure_localization_trimmer = {
max_submaps_to_keep = 3,
}
POSE_GRAPH.optimize_every_n_nodes = 20
return options
@@ -0,0 +1,27 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "backpack_2d_localization.lua"
-- output map to base_link for evaluation
options.provide_odom_frame = false
POSE_GRAPH.optimization_problem.log_solver_summary = true
-- fast localization
MAP_BUILDER.num_background_threads = 12
POSE_GRAPH.constraint_builder.sampling_ratio = 0.5 * POSE_GRAPH.constraint_builder.sampling_ratio
POSE_GRAPH.global_sampling_ratio = 0.1 * POSE_GRAPH.global_sampling_ratio
POSE_GRAPH.max_num_final_iterations = 1
return options
@@ -0,0 +1,19 @@
-- Copyright 2018 The Cartographer Authors
--
-- 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.
include "map_builder_server.lua"
MAP_BUILDER_SERVER.map_builder.use_trajectory_builder_2d = true
return MAP_BUILDER_SERVER
@@ -0,0 +1,57 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
map_frame = "map",
tracking_frame = "base_link",
published_frame = "base_link",
odom_frame = "odom",
provide_odom_frame = true,
publish_frame_projected_to_2d = false,
use_pose_extrapolator = true,
use_odometry = false,
use_nav_sat = false,
use_landmarks = false,
num_laser_scans = 0,
num_multi_echo_laser_scans = 0,
num_subdivisions_per_laser_scan = 1,
num_point_clouds = 2,
lookup_transform_timeout_sec = 0.2,
submap_publish_period_sec = 0.3,
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
}
TRAJECTORY_BUILDER_3D.num_accumulated_range_data = 160
MAP_BUILDER.use_trajectory_builder_3d = true
MAP_BUILDER.num_background_threads = 7
POSE_GRAPH.optimization_problem.huber_scale = 5e2
POSE_GRAPH.optimize_every_n_nodes = 320
POSE_GRAPH.constraint_builder.sampling_ratio = 0.03
POSE_GRAPH.optimization_problem.ceres_solver_options.max_num_iterations = 10
POSE_GRAPH.constraint_builder.min_score = 0.62
POSE_GRAPH.constraint_builder.global_localization_min_score = 0.66
return options
@@ -0,0 +1,22 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "backpack_3d.lua"
TRAJECTORY_BUILDER.pure_localization_trimmer = {
max_submaps_to_keep = 3,
}
POSE_GRAPH.optimize_every_n_nodes = 100
return options
@@ -0,0 +1,459 @@
Panels:
- Class: rviz_common/Displays
Help Height: 78
Name: Displays
Property Tree Widget:
Expanded:
- /Global Options1
- /RobotModel1/Description Topic1
- /TF1/Tree1
- /map1/Topic1
- /SubmapsDisplay1/Submaps1
- /Trajectories1/Namespaces1
- /Constraints1/Namespaces1
Splitter Ratio: 0.42203986644744873
Tree Height: 1174
- Class: rviz_common/Selection
Name: Selection
- Class: rviz_common/Tool Properties
Expanded:
- /2D Goal Pose1
- /Publish Point1
Name: Tool Properties
Splitter Ratio: 0.5886790156364441
- Class: rviz_common/Views
Expanded:
- /Current View1
Name: Views
Splitter Ratio: 0.5
- Class: teleop_panel/Teleop
Name: Teleop
Topic: /rt_cmd_vel
- Class: wyca_rviz_plugin/Wyca
Name: Wyca
- Class: rviz_common/Time
Experimental: false
Name: Time
SyncMode: 0
SyncSource: ""
Visualization Manager:
Class: ""
Displays:
- Alpha: 1
Class: rviz_default_plugins/RobotModel
Collision Enabled: false
Description File: ""
Description Source: Topic
Description Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /robot_description
Enabled: true
Links:
All Links Enabled: true
Expand Joint Details: false
Expand Link Details: false
Expand Tree: false
Link Tree Style: Links in Alphabetic Order
Name: RobotModel
TF Prefix: ""
Update Interval: 0
Value: true
Visual Enabled: true
- Class: rviz_default_plugins/TF
Enabled: true
Frame Timeout: 15
Frames:
All Enabled: false
Marker Scale: 0.30000001192092896
Name: TF
Show Arrows: true
Show Axes: true
Show Names: true
Tree:
{}
Update Interval: 0
Value: true
- Alpha: 0.699999988079071
Class: rviz_default_plugins/Map
Color Scheme: map
Draw Behind: false
Enabled: true
Name: map
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Best Effort
Value: /map
Update Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /map_updates
Use Timestamp: false
Value: true
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 10
Min Value: -10
Value: true
Axis: Z
Channel Name: intensity
Class: rviz_default_plugins/PointCloud2
Color: 239; 41; 41
Color Transformer: FlatColor
Decay Time: 0
Enabled: true
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 4096
Min Color: 0; 0; 0
Min Intensity: 0
Name: PointCloud2
Position Transformer: XYZ
Selectable: true
Size (Pixels): 3
Size (m): 0.10000000149011612
Style: Flat Squares
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /scan_matched_points2
Use Fixed Frame: true
Use rainbow: false
Value: true
- Class: cartographer_rviz/SubmapsDisplay
Enabled: true
Fade-out distance: 1
High Resolution: true
Low Resolution: false
Name: SubmapsDisplay
Submap query service: /submap_query
Submaps:
All: true
All Submap Pose Markers: true
Trajectory 0:
0.60: true
1.60: true
10.60: true
100.60: true
101.60: true
102.60: true
103.60: true
104.60: true
105.60: true
106.60: true
107.60: true
108.60: true
109.60: true
11.60: true
110.60: true
111.60: true
112.60: true
113.60: true
114.60: true
115.60: true
116.60: true
117.60: true
118.60: true
119.60: true
12.60: true
120.60: true
121.60: true
122.60: true
123.60: true
124.60: true
125.60: true
126.60: true
127.60: true
128.60: true
129.60: true
13.60: true
130.60: true
131.60: true
132.60: true
133.60: true
134.60: true
135.60: true
136.60: true
137.60: true
138.60: true
139.60: true
14.60: true
140.60: true
141.60: true
142.60: true
143.60: true
144.60: true
145.60: true
146.60: true
147.60: true
148.60: true
149.60: true
15.60: true
150.60: true
151.60: true
152.60: true
153.60: true
154.60: true
155.60: true
156.60: true
157.60: true
158.60: true
159.60: true
16.60: true
160.60: true
161.60: true
162.60: true
163.60: true
164.60: true
165.60: true
166.60: true
167.60: true
168.60: true
169.60: true
17.60: true
170.60: true
171.60: true
172.43: true
173.13: true
18.60: true
19.60: true
2.60: true
20.60: true
21.60: true
22.60: true
23.60: true
24.60: true
25.60: true
26.60: true
27.60: true
28.60: true
29.60: true
3.60: true
30.60: true
31.60: true
32.60: true
33.60: true
34.60: true
35.60: true
36.60: true
37.60: true
38.60: true
39.60: true
4.60: true
40.60: true
41.60: true
42.60: true
43.60: true
44.60: true
45.60: true
46.60: true
47.60: true
48.60: true
49.60: true
5.60: true
50.60: true
51.60: true
52.60: true
53.60: true
54.60: true
55.60: true
56.60: true
57.60: true
58.60: true
59.60: true
6.60: true
60.60: true
61.60: true
62.60: true
63.60: true
64.60: true
65.60: true
66.60: true
67.60: true
68.60: true
69.60: true
7.60: true
70.60: true
71.60: true
72.60: true
73.60: true
74.60: true
75.60: true
76.60: true
77.60: true
78.60: true
79.60: true
8.60: true
80.60: true
81.60: true
82.60: true
83.60: true
84.60: true
85.60: true
86.60: true
87.60: true
88.60: true
89.60: true
9.60: true
90.60: true
91.60: true
92.60: true
93.60: true
94.60: true
95.60: true
96.60: true
97.60: true
98.60: true
99.60: true
Submap Pose Markers: true
Value: true
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /submap_list
Tracking frame: map
Value: true
- Class: rviz_default_plugins/MarkerArray
Enabled: false
Name: Trajectories
Namespaces:
{}
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /trajectory_node_list
Value: false
- Class: rviz_default_plugins/MarkerArray
Enabled: true
Name: Constraints
Namespaces:
Inter constraints, different trajectories: true
Inter constraints, same trajectory: true
Inter residuals, different trajectories: true
Inter residuals, same trajectory: true
Intra constraints: true
Intra residuals: true
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /constraint_list
Value: true
- Class: rviz_default_plugins/MarkerArray
Enabled: true
Name: Landmarks
Namespaces:
{}
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /landmark_poses_list
Value: true
Enabled: true
Global Options:
Background Color: 48; 48; 48
Fixed Frame: map
Frame Rate: 30
Name: root
Tools:
- Class: rviz_default_plugins/Interact
Hide Inactive Objects: true
- Class: rviz_default_plugins/MoveCamera
- Class: rviz_default_plugins/Select
- Class: rviz_default_plugins/FocusCamera
- Class: rviz_default_plugins/Measure
Line color: 128; 128; 0
- Class: rviz_default_plugins/SetInitialPose
Covariance x: 0.25
Covariance y: 0.25
Covariance yaw: 0.06853891909122467
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /initialpose
- Class: rviz_default_plugins/SetGoal
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /goal_pose
- Class: rviz_default_plugins/PublishPoint
Single click: true
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /clicked_point
- Class: nav2_rviz_plugins/GoalTool
Transformation:
Current:
Class: rviz_default_plugins/TF
Value: true
Views:
Current:
Class: rviz_default_plugins/ThirdPersonFollower
Distance: 204.58663940429688
Enable Stereo Rendering:
Stereo Eye Separation: 0.05999999865889549
Stereo Focal Distance: 1
Swap Stereo Eyes: false
Value: false
Focal Point:
X: -11.516843795776367
Y: 13.40983772277832
Z: 7.403941708616912e-05
Focal Shape Fixed Size: false
Focal Shape Size: 0.05000000074505806
Invert Z Axis: false
Name: Current View
Near Clip Distance: 0.009999999776482582
Pitch: 1.5697963237762451
Target Frame: map
Value: ThirdPersonFollower (rviz_default_plugins)
Yaw: 1.6953976154327393
Saved: ~
Window Geometry:
Displays:
collapsed: false
Height: 1403
Hide Left Dock: false
Hide Right Dock: false
QMainWindow State: 000000ff00000000fd00000004000000000000028100000521fc020000000cfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d00000521000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb00000018004e0061007600690067006100740069006f006e002000320000000324000000b70000000000000000fb0000000c00540065006c0065006f007000000002af00000164000000bb00fffffffb00000008005700790063006100000003a5000001000000006000fffffffb0000000800540069006d00650000000484000000bf0000003900ffffff000000010000010f00000521fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d00000521000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000001fb0000000800540069006d00650100000000000004500000000000000000000006640000052100000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Selection:
collapsed: false
Teleop:
collapsed: false
Time:
collapsed: false
Tool Properties:
collapsed: false
Views:
collapsed: false
Width: 2560
Wyca:
collapsed: false
X: 3840
Y: 0
@@ -0,0 +1,394 @@
Panels:
- Class: rviz_common/Displays
Help Height: 78
Name: Displays
Property Tree Widget:
Expanded:
- /Global Options1
- /RobotModel1/Description Topic1
- /map1/Status1
- /map1/Topic1
- /SubmapsDisplay1/Submaps1
- /Trajectories1/Namespaces1
Splitter Ratio: 0.47058823704719543
Tree Height: 1174
- Class: rviz_common/Selection
Name: Selection
- Class: rviz_common/Tool Properties
Expanded:
- /2D Goal Pose1
- /Publish Point1
Name: Tool Properties
Splitter Ratio: 0.5886790156364441
- Class: rviz_common/Views
Expanded:
- /Current View1
Name: Views
Splitter Ratio: 0.5
- Class: teleop_panel/Teleop
Name: Teleop
Topic: /rt_cmd_vel
- Class: wyca_rviz_plugin/Wyca
Name: Wyca
- Class: rviz_common/Time
Experimental: false
Name: Time
SyncMode: 0
SyncSource: matched_points
Visualization Manager:
Class: ""
Displays:
- Alpha: 1
Class: rviz_default_plugins/RobotModel
Collision Enabled: false
Description File: ""
Description Source: Topic
Description Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /robot_description
Enabled: true
Links:
All Links Enabled: true
Expand Joint Details: false
Expand Link Details: false
Expand Tree: false
Link Tree Style: Links in Alphabetic Order
base_link:
Alpha: 1
Show Axes: false
Show Trail: false
horizontal_vlp16_link:
Alpha: 1
Show Axes: false
Show Trail: false
Value: true
imu_link:
Alpha: 1
Show Axes: false
Show Trail: false
Value: true
vertical_vlp16_link:
Alpha: 1
Show Axes: false
Show Trail: false
Value: true
Name: RobotModel
TF Prefix: ""
Update Interval: 0
Value: true
Visual Enabled: true
- Class: rviz_default_plugins/TF
Enabled: true
Frame Timeout: 15
Frames:
All Enabled: false
base_link:
Value: false
horizontal_vlp16_link:
Value: true
imu_link:
Value: true
map:
Value: true
odom:
Value: true
vertical_vlp16_link:
Value: true
Marker Scale: 0.30000001192092896
Name: TF
Show Arrows: true
Show Axes: true
Show Names: true
Tree:
map:
odom:
base_link:
horizontal_vlp16_link:
{}
imu_link:
{}
vertical_vlp16_link:
{}
Update Interval: 0
Value: true
- Alpha: 0.699999988079071
Class: rviz_default_plugins/Map
Color Scheme: map
Draw Behind: false
Enabled: true
Name: map
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Best Effort
Value: /map
Update Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /map_updates
Use Timestamp: false
Value: true
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 10
Min Value: -10
Value: true
Axis: Z
Channel Name: intensity
Class: rviz_default_plugins/PointCloud2
Color: 239; 41; 41
Color Transformer: FlatColor
Decay Time: 0
Enabled: true
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 4096
Min Color: 0; 0; 0
Min Intensity: 0
Name: matched_points
Position Transformer: XYZ
Selectable: true
Size (Pixels): 3
Size (m): 0.10000000149011612
Style: Flat Squares
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /scan_matched_points2
Use Fixed Frame: true
Use rainbow: false
Value: true
- Class: cartographer_rviz/SubmapsDisplay
Enabled: true
Fade-out distance: 1
High Resolution: true
Low Resolution: false
Name: SubmapsDisplay
Submap query service: /submap_query
Submaps:
All: true
All Submap Pose Markers: true
Trajectory 0:
0.320: true
1.204: true
2.44: true
Submap Pose Markers: true
Value: true
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /submap_list
Tracking frame: odom
Value: true
- Class: rviz_default_plugins/MarkerArray
Enabled: false
Name: Trajectories
Namespaces:
{}
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /trajectory_node_list
Value: false
- Class: rviz_default_plugins/MarkerArray
Enabled: true
Name: Constraints
Namespaces:
Inter constraints, different trajectories: true
Inter constraints, same trajectory: true
Inter residuals, different trajectories: true
Inter residuals, same trajectory: true
Intra constraints: true
Intra residuals: true
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /constraint_list
Value: true
- Class: rviz_default_plugins/MarkerArray
Enabled: true
Name: Landmarks
Namespaces:
{}
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /landmark_poses_list
Value: true
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 10
Min Value: -10
Value: true
Axis: Z
Channel Name: intensity
Class: rviz_default_plugins/PointCloud2
Color: 255; 255; 255
Color Transformer: Intensity
Decay Time: 0
Enabled: false
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 57
Min Color: 0; 0; 0
Min Intensity: 1
Name: horizontal_laser
Position Transformer: XYZ
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /horizontal_laser_3d
Use Fixed Frame: true
Use rainbow: true
Value: false
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 10
Min Value: -10
Value: true
Axis: Z
Channel Name: intensity
Class: rviz_default_plugins/PointCloud2
Color: 255; 255; 255
Color Transformer: Intensity
Decay Time: 0
Enabled: false
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 90
Min Color: 0; 0; 0
Min Intensity: 1
Name: vertical_laser
Position Transformer: XYZ
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /vertical_laser_3d
Use Fixed Frame: true
Use rainbow: true
Value: false
Enabled: true
Global Options:
Background Color: 48; 48; 48
Fixed Frame: map
Frame Rate: 30
Name: root
Tools:
- Class: rviz_default_plugins/Interact
Hide Inactive Objects: true
- Class: rviz_default_plugins/MoveCamera
- Class: rviz_default_plugins/Select
- Class: rviz_default_plugins/FocusCamera
- Class: rviz_default_plugins/Measure
Line color: 128; 128; 0
- Class: rviz_default_plugins/SetInitialPose
Covariance x: 0.25
Covariance y: 0.25
Covariance yaw: 0.06853891909122467
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /initialpose
- Class: rviz_default_plugins/SetGoal
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /goal_pose
- Class: rviz_default_plugins/PublishPoint
Single click: true
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /clicked_point
- Class: nav2_rviz_plugins/GoalTool
Transformation:
Current:
Class: rviz_default_plugins/TF
Value: true
Views:
Current:
Class: rviz_default_plugins/ThirdPersonFollower
Distance: 59.301063537597656
Enable Stereo Rendering:
Stereo Eye Separation: 0.05999999865889549
Stereo Focal Distance: 1
Swap Stereo Eyes: false
Value: false
Focal Point:
X: -0.8213143348693848
Y: -0.22988438606262207
Z: -0.00012816624075639993
Focal Shape Fixed Size: false
Focal Shape Size: 0.05000000074505806
Invert Z Axis: false
Name: Current View
Near Clip Distance: 0.009999999776482582
Pitch: 1.1647964715957642
Target Frame: map
Value: ThirdPersonFollower (rviz_default_plugins)
Yaw: 0.3154185116291046
Saved: ~
Window Geometry:
Displays:
collapsed: false
Height: 1403
Hide Left Dock: false
Hide Right Dock: false
QMainWindow State: 000000ff00000000fd0000000400000000000001ac00000521fc020000000cfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d00000521000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb00000018004e0061007600690067006100740069006f006e002000320000000324000000b70000000000000000fb0000000c00540065006c0065006f007000000002af00000164000000bb00fffffffb00000008005700790063006100000003a5000001000000006000fffffffb0000000800540069006d00650000000484000000bf0000003900ffffff000000010000010f00000521fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d00000521000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000001fb0000000800540069006d00650100000000000004500000000000000000000007390000052100000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Selection:
collapsed: false
Teleop:
collapsed: false
Time:
collapsed: false
Tool Properties:
collapsed: false
Views:
collapsed: false
Width: 2560
Wyca:
collapsed: false
X: 3840
Y: 0
@@ -0,0 +1,77 @@
-- Copyright 2018 The Cartographer Authors
--
-- 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.
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
map_frame = "map",
tracking_frame = "imu_frame",
published_frame = "base_link",
odom_frame = "odom",
provide_odom_frame = true,
publish_frame_projected_to_2d = false,
use_odometry = true,
use_pose_extrapolator = true,
use_nav_sat = false,
use_landmarks = true,
num_laser_scans = 2,
num_multi_echo_laser_scans = 0,
num_subdivisions_per_laser_scan = 1,
num_point_clouds = 0,
lookup_transform_timeout_sec = 0.2,
submap_publish_period_sec = 0.3,
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
}
MAP_BUILDER.use_trajectory_builder_2d = true
TRAJECTORY_BUILDER.collate_landmarks = false
TRAJECTORY_BUILDER_2D.num_accumulated_range_data = 2
TRAJECTORY_BUILDER_2D.use_imu_data = true
TRAJECTORY_BUILDER_2D.submaps.num_range_data = 45
-- more points
TRAJECTORY_BUILDER_2D.adaptive_voxel_filter.max_length = 0.2
TRAJECTORY_BUILDER_2D.adaptive_voxel_filter.min_num_points = 400
-- slightly slower insertion
TRAJECTORY_BUILDER_2D.submaps.range_data_inserter.probability_grid_range_data_inserter.hit_probability = 0.53
TRAJECTORY_BUILDER_2D.submaps.range_data_inserter.probability_grid_range_data_inserter.miss_probability = 0.493
-- slightly shorter rays
TRAJECTORY_BUILDER_2D.max_range = 15.
-- wheel odometry is fine
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight = 20
-- IMU is ok
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.rotation_weight = 20
-- less outliers
POSE_GRAPH.constraint_builder.max_constraint_distance = 5.
POSE_GRAPH.constraint_builder.min_score = 0.5
-- tune down IMU in optimization
POSE_GRAPH.optimization_problem.acceleration_weight = 0.1 * 1e3
POSE_GRAPH.optimization_problem.rotation_weight = 0.1 * 3e5
-- ignore wheels in optimization
POSE_GRAPH.optimization_problem.odometry_translation_weight = 0.
POSE_GRAPH.optimization_problem.odometry_rotation_weight = 0.
POSE_GRAPH.optimization_problem.log_solver_summary = true
return options
@@ -0,0 +1,55 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
map_frame = "map",
tracking_frame = "base_footprint",
published_frame = "base_footprint",
odom_frame = "odom",
provide_odom_frame = true,
publish_frame_projected_to_2d = false,
use_pose_extrapolator = true,
use_odometry = false,
use_nav_sat = false,
use_landmarks = false,
num_laser_scans = 1,
num_multi_echo_laser_scans = 0,
num_subdivisions_per_laser_scan = 1,
num_point_clouds = 0,
lookup_transform_timeout_sec = 0.2,
submap_publish_period_sec = 0.3,
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
}
MAP_BUILDER.use_trajectory_builder_2d = true
TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true
TRAJECTORY_BUILDER_2D.use_imu_data = false
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.linear_search_window = 0.15
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.angular_search_window = math.rad(35.)
POSE_GRAPH.optimization_problem.huber_scale = 1e2
return options
@@ -0,0 +1,62 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
map_frame = "map",
tracking_frame = "horizontal_laser_link",
published_frame = "horizontal_laser_link",
odom_frame = "odom",
provide_odom_frame = true,
publish_frame_projected_to_2d = false,
use_pose_extrapolator = true,
use_odometry = false,
use_nav_sat = false,
use_landmarks = false,
num_laser_scans = 1,
num_multi_echo_laser_scans = 0,
num_subdivisions_per_laser_scan = 1,
num_point_clouds = 0,
lookup_transform_timeout_sec = 0.2,
submap_publish_period_sec = 0.3,
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
}
MAP_BUILDER.use_trajectory_builder_2d = true
TRAJECTORY_BUILDER_2D.submaps.num_range_data = 35
TRAJECTORY_BUILDER_2D.min_range = 0.3
TRAJECTORY_BUILDER_2D.max_range = 8.
TRAJECTORY_BUILDER_2D.missing_data_ray_length = 1.
TRAJECTORY_BUILDER_2D.use_imu_data = false
TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.linear_search_window = 0.1
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.translation_delta_cost_weight = 10.
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.rotation_delta_cost_weight = 1e-1
POSE_GRAPH.optimization_problem.huber_scale = 1e2
POSE_GRAPH.optimize_every_n_nodes = 35
POSE_GRAPH.constraint_builder.min_score = 0.65
return options
@@ -0,0 +1,60 @@
-- Copyright 2016 The Cartographer Authors
--
-- 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.
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
map_frame = "map",
tracking_frame = "base_link",
published_frame = "odom",
odom_frame = "odom",
provide_odom_frame = false,
publish_frame_projected_to_2d = false,
use_pose_extrapolator = true,
use_odometry = true,
use_nav_sat = false,
use_landmarks = false,
num_laser_scans = 1,
num_multi_echo_laser_scans = 0,
num_subdivisions_per_laser_scan = 1,
num_point_clouds = 0,
lookup_transform_timeout_sec = 0.2,
submap_publish_period_sec = 0.3,
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
}
TRAJECTORY_BUILDER_3D.num_accumulated_range_data = 180
TRAJECTORY_BUILDER_3D.min_range = 0.5
TRAJECTORY_BUILDER_3D.max_range = 20.
TRAJECTORY_BUILDER_3D.submaps.num_range_data = 40.
MAP_BUILDER.use_trajectory_builder_3d = true
MAP_BUILDER.num_background_threads = 7
POSE_GRAPH.optimization_problem.huber_scale = 5e2
POSE_GRAPH.optimize_every_n_nodes = 40
POSE_GRAPH.constraint_builder.sampling_ratio = 0.03
POSE_GRAPH.optimization_problem.ceres_solver_options.max_num_iterations = 10
POSE_GRAPH.constraint_builder.min_score = 0.62
POSE_GRAPH.constraint_builder.log_matches = true
return options
@@ -0,0 +1,28 @@
-- Copyright 2017 The Cartographer Authors
--
-- 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.
XY_TRANSFORM = {
translation = { 0., 0., 0. },
rotation = { 0., -math.pi / 2., 0., },
}
XZ_TRANSFORM = {
translation = { 0., 0., 0. },
rotation = { 0. , 0., -math.pi / 2, },
}
YZ_TRANSFORM = {
translation = { 0., 0., 0. },
rotation = { 0. , 0., math.pi, },
}
@@ -0,0 +1,21 @@
-- Copyright 2018 The Cartographer Authors
--
-- 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.
include "backpack_2d.lua"
POSE_GRAPH.constraint_builder.sampling_ratio = 0
POSE_GRAPH.global_sampling_ratio = 0
POSE_GRAPH.optimize_every_n_nodes = 0
return options
@@ -0,0 +1,64 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#include <string>
#include <vector>
#include "cartographer/common/configuration_file_resolver.h"
#include "cartographer/io/points_processor_pipeline_builder.h"
#include "cartographer/mapping/proto/pose_graph.pb.h"
#include "cartographer/mapping/proto/trajectory_builder_options.pb.h"
#include <rclcpp/rclcpp.hpp>
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ASSETS_WRITER_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ASSETS_WRITER_H
namespace cartographer_ros {
class AssetsWriter {
public:
AssetsWriter(const std::string& pose_graph_filename,
const std::vector<std::string>& bag_filenames,
const std::string& output_file_prefix);
// Registers a new PointsProcessor type uniquly identified by 'name' which
// will be created using 'factory'.
void RegisterPointsProcessor(
const std::string& name,
cartographer::io::PointsProcessorPipelineBuilder::FactoryFunction
factory);
// Configures a points processing pipeline and pushes the points from the
// bag through the pipeline.
void Run(const std::string& configuration_directory,
const std::string& configuration_basename,
const std::string& urdf_filename, bool use_bag_transforms);
// Creates a FileWriterFactory which creates a FileWriter for storing assets.
static ::cartographer::io::FileWriterFactory CreateFileWriterFactory(
const std::string& file_path);
private:
std::vector<std::string> bag_filenames_;
std::vector<::cartographer::mapping::proto::Trajectory> all_trajectories_;
::cartographer::mapping::proto::PoseGraph pose_graph_;
std::unique_ptr<::cartographer::io::PointsProcessorPipelineBuilder>
point_pipeline_builder_;
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ASSETS_WRITER_H
@@ -0,0 +1,130 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MAP_BUILDER_BRIDGE_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MAP_BUILDER_BRIDGE_H
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include "absl/synchronization/mutex.h"
#include "cartographer/mapping/map_builder_interface.h"
#include "cartographer/mapping/pose_graph_interface.h"
#include "cartographer/mapping/proto/trajectory_builder_options.pb.h"
#include "cartographer/mapping/trajectory_builder_interface.h"
#include "cartographer_ros/node_options.h"
#include "cartographer_ros/sensor_bridge.h"
#include "cartographer_ros/tf_bridge.h"
#include "cartographer_ros/trajectory_options.h"
#include "cartographer_ros_msgs/msg/submap_entry.hpp"
#include "cartographer_ros_msgs/msg/submap_list.hpp"
#include "cartographer_ros_msgs/srv/submap_query.hpp"
#include "cartographer_ros_msgs/srv/trajectory_query.hpp"
#include "geometry_msgs/msg/transform_stamped.hpp"
#include "nav_msgs/msg/occupancy_grid.hpp"
// Abseil unfortunately pulls in winnt.h, which #defines DELETE.
// Clean up to unbreak visualization_msgs::msg::Marker::DELETE.
#ifdef DELETE
#undef DELETE
#endif
#include "visualization_msgs/msg/marker_array.hpp"
namespace cartographer_ros {
class MapBuilderBridge {
public:
struct LocalTrajectoryData {
// Contains the trajectory data received from local SLAM, after
// it had processed accumulated 'range_data_in_local' and estimated
// current 'local_pose' at 'time'.
struct LocalSlamData {
::cartographer::common::Time time;
::cartographer::transform::Rigid3d local_pose;
::cartographer::sensor::RangeData range_data_in_local;
};
std::shared_ptr<const LocalSlamData> local_slam_data;
cartographer::transform::Rigid3d local_to_map;
std::unique_ptr<cartographer::transform::Rigid3d> published_to_tracking;
TrajectoryOptions trajectory_options;
};
MapBuilderBridge(
const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
tf2_ros::Buffer* tf_buffer);
MapBuilderBridge(const MapBuilderBridge&) = delete;
MapBuilderBridge& operator=(const MapBuilderBridge&) = delete;
void LoadState(const std::string& state_filename, bool load_frozen_state);
int AddTrajectory(
const std::set<
::cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& trajectory_options);
void FinishTrajectory(int trajectory_id);
void RunFinalOptimization();
bool SerializeState(const std::string& filename,
const bool include_unfinished_submaps);
void HandleSubmapQuery(
const cartographer_ros_msgs::srv::SubmapQuery::Request::SharedPtr request,
cartographer_ros_msgs::srv::SubmapQuery::Response::SharedPtr response);
void HandleTrajectoryQuery(
const cartographer_ros_msgs::srv::TrajectoryQuery::Request::SharedPtr request,
cartographer_ros_msgs::srv::TrajectoryQuery::Response::SharedPtr response);
std::map<int /* trajectory_id */,
::cartographer::mapping::PoseGraphInterface::TrajectoryState>
GetTrajectoryStates();
cartographer_ros_msgs::msg::SubmapList GetSubmapList(rclcpp::Time node_time);
std::unordered_map<int, LocalTrajectoryData> GetLocalTrajectoryData()
LOCKS_EXCLUDED(mutex_);
visualization_msgs::msg::MarkerArray GetTrajectoryNodeList(rclcpp::Time node_time);
visualization_msgs::msg::MarkerArray GetLandmarkPosesList(rclcpp::Time node_time);
visualization_msgs::msg::MarkerArray GetConstraintList(rclcpp::Time node_time);
SensorBridge* sensor_bridge(int trajectory_id);
private:
void OnLocalSlamResult(const int trajectory_id,
const ::cartographer::common::Time time,
const ::cartographer::transform::Rigid3d local_pose,
::cartographer::sensor::RangeData range_data_in_local)
LOCKS_EXCLUDED(mutex_);
absl::Mutex mutex_;
const NodeOptions node_options_;
std::unordered_map<int,
std::shared_ptr<const LocalTrajectoryData::LocalSlamData>>
local_slam_data_ GUARDED_BY(mutex_);
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder_;
tf2_ros::Buffer* const tf_buffer_;
std::unordered_map<std::string /* landmark ID */, int> landmark_to_index_;
// These are keyed with 'trajectory_id'.
std::unordered_map<int, TrajectoryOptions> trajectory_options_;
std::unordered_map<int, std::unique_ptr<SensorBridge>> sensor_bridges_;
std::unordered_map<int, size_t> trajectory_to_highest_marker_id_;
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MAP_BUILDER_BRIDGE_H
@@ -0,0 +1,61 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_METRICS_FAMILY_FACTORY_H
#define CARTOGRAPHER_ROS_METRICS_FAMILY_FACTORY_H
#include <memory>
#include <string>
#include "cartographer/metrics/family_factory.h"
#include "cartographer_ros/metrics/internal/counter.h"
#include "cartographer_ros/metrics/internal/family.h"
#include "cartographer_ros/metrics/internal/gauge.h"
#include "cartographer_ros/metrics/internal/histogram.h"
#include "cartographer_ros_msgs/srv/read_metrics.hpp"
namespace cartographer_ros {
namespace metrics {
// Realizes the factory / registry interface for the metrics in libcartographer
// and provides a wrapper to collect ROS messages from the metrics it owns.
class FamilyFactory : public ::cartographer::metrics::FamilyFactory {
public:
::cartographer::metrics::Family<::cartographer::metrics::Counter>*
NewCounterFamily(const std::string& name,
const std::string& description) override;
::cartographer::metrics::Family<::cartographer::metrics::Gauge>*
NewGaugeFamily(const std::string& name,
const std::string& description) override;
::cartographer::metrics::Family<::cartographer::metrics::Histogram>*
NewHistogramFamily(const std::string& name, const std::string& description,
const ::cartographer::metrics::Histogram::BucketBoundaries&
boundaries) override;
void ReadMetrics(
cartographer_ros_msgs::srv::ReadMetrics::Response::SharedPtr response) const;
private:
std::vector<std::unique_ptr<CounterFamily>> counter_families_;
std::vector<std::unique_ptr<GaugeFamily>> gauge_families_;
std::vector<std::unique_ptr<HistogramFamily>> histogram_families_;
};
} // namespace metrics
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_METRICS_FAMILY_FACTORY_H
@@ -0,0 +1,51 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_METRICS_INTERNAL_COUNTER_H
#define CARTOGRAPHER_ROS_METRICS_INTERNAL_COUNTER_H
#include "cartographer/metrics/counter.h"
#include "cartographer_ros/metrics/internal/gauge.h"
#include "cartographer_ros_msgs/msg/metric.hpp"
namespace cartographer_ros {
namespace metrics {
class Counter : public ::cartographer::metrics::Counter {
public:
explicit Counter(const std::map<std::string, std::string>& labels)
: gauge_(labels) {}
void Increment(const double value) override { gauge_.Increment(value); }
void Increment() override { gauge_.Increment(); }
double Value() { return gauge_.Value(); }
cartographer_ros_msgs::msg::Metric ToRosMessage() {
cartographer_ros_msgs::msg::Metric msg = gauge_.ToRosMessage();
msg.type = cartographer_ros_msgs::msg::Metric::TYPE_COUNTER;
return msg;
}
private:
Gauge gauge_;
};
} // namespace metrics
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_METRICS_INTERNAL_COUNTER_H
@@ -0,0 +1,81 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_METRICS_INTERNAL_FAMILY_H
#define CARTOGRAPHER_ROS_METRICS_INTERNAL_FAMILY_H
#include <memory>
#include <string>
#include "cartographer/metrics/family_factory.h"
#include "cartographer_ros/metrics/internal/counter.h"
#include "cartographer_ros/metrics/internal/gauge.h"
#include "cartographer_ros/metrics/internal/histogram.h"
#include "cartographer_ros_msgs/msg/metric_family.hpp"
namespace cartographer_ros {
namespace metrics {
class CounterFamily
: public ::cartographer::metrics::Family<::cartographer::metrics::Counter> {
public:
CounterFamily(const std::string& name, const std::string& description)
: name_(name), description_(description) {}
Counter* Add(const std::map<std::string, std::string>& labels) override;
cartographer_ros_msgs::msg::MetricFamily ToRosMessage();
private:
std::string name_;
std::string description_;
std::vector<std::unique_ptr<Counter>> wrappers_;
};
class GaugeFamily
: public ::cartographer::metrics::Family<::cartographer::metrics::Gauge> {
public:
GaugeFamily(const std::string& name, const std::string& description)
: name_(name), description_(description) {}
Gauge* Add(const std::map<std::string, std::string>& labels) override;
cartographer_ros_msgs::msg::MetricFamily ToRosMessage();
private:
std::string name_;
std::string description_;
std::vector<std::unique_ptr<Gauge>> wrappers_;
};
class HistogramFamily : public ::cartographer::metrics::Family<
::cartographer::metrics::Histogram> {
public:
HistogramFamily(const std::string& name, const std::string& description,
const BucketBoundaries& boundaries)
: name_(name), description_(description), boundaries_(boundaries) {}
Histogram* Add(const std::map<std::string, std::string>& labels) override;
cartographer_ros_msgs::msg::MetricFamily ToRosMessage();
private:
std::string name_;
std::string description_;
std::vector<std::unique_ptr<Histogram>> wrappers_;
const BucketBoundaries boundaries_;
};
} // namespace metrics
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_METRICS_INTERNAL_FAMILY_H
@@ -0,0 +1,80 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_METRICS_INTERNAL_GAUGE_H
#define CARTOGRAPHER_ROS_METRICS_INTERNAL_GAUGE_H
#include <map>
#include <string>
#include "absl/synchronization/mutex.h"
#include "cartographer/metrics/gauge.h"
#include "cartographer_ros_msgs/msg/metric.hpp"
namespace cartographer_ros {
namespace metrics {
class Gauge : public ::cartographer::metrics::Gauge {
public:
explicit Gauge(const std::map<std::string, std::string>& labels)
: labels_(labels), value_(0.) {}
void Decrement(const double value) override { Add(-1. * value); }
void Decrement() override { Decrement(1.); }
void Increment(const double value) override { Add(value); }
void Increment() override { Increment(1.); }
void Set(double value) override {
absl::MutexLock lock(&mutex_);
value_ = value;
}
double Value() {
absl::MutexLock lock(&mutex_);
return value_;
}
cartographer_ros_msgs::msg::Metric ToRosMessage() {
cartographer_ros_msgs::msg::Metric msg;
msg.type = cartographer_ros_msgs::msg::Metric::TYPE_GAUGE;
for (const auto& label : labels_) {
cartographer_ros_msgs::msg::MetricLabel label_msg;
label_msg.key = label.first;
label_msg.value = label.second;
msg.labels.push_back(label_msg);
}
msg.value = Value();
return msg;
}
private:
void Add(const double value) {
absl::MutexLock lock(&mutex_);
value_ += value;
}
absl::Mutex mutex_;
const std::map<std::string, std::string> labels_;
double value_ GUARDED_BY(mutex_);
};
} // namespace metrics
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_METRICS_INTERNAL_GAUGE_H
@@ -0,0 +1,60 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_METRICS_INTERNAL_HISTOGRAM_H
#define CARTOGRAPHER_ROS_METRICS_INTERNAL_HISTOGRAM_H
#include <map>
#include <vector>
#include "absl/synchronization/mutex.h"
#include "cartographer/metrics/histogram.h"
#include "cartographer_ros_msgs/msg/metric.hpp"
namespace cartographer_ros {
namespace metrics {
constexpr double kInfiniteBoundary = std::numeric_limits<double>::infinity();
using BucketBoundaries = ::cartographer::metrics::Histogram::BucketBoundaries;
class Histogram : public ::cartographer::metrics::Histogram {
public:
explicit Histogram(const std::map<std::string, std::string>& labels,
const BucketBoundaries& bucket_boundaries);
void Observe(double value) override;
std::map<double, double> CountsByBucket();
double Sum();
double CumulativeCount();
cartographer_ros_msgs::msg::Metric ToRosMessage();
private:
absl::Mutex mutex_;
const std::map<std::string, std::string> labels_;
const BucketBoundaries bucket_boundaries_;
std::vector<double> bucket_counts_ GUARDED_BY(mutex_);
double sum_ GUARDED_BY(mutex_);
};
} // namespace metrics
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_METRICS_INTERNAL_HISTOGRAM_H
@@ -0,0 +1,95 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MSG_CONVERSION_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MSG_CONVERSION_H
#include "cartographer/common/time.h"
#include "cartographer/io/submap_painter.h"
#include "cartographer/sensor/landmark_data.h"
#include "cartographer/sensor/point_cloud.h"
#include "cartographer/transform/rigid_transform.h"
#include "cartographer_ros_msgs/msg/landmark_list.hpp"
#include "geometry_msgs/msg/pose.hpp"
#include "geometry_msgs/msg/point.hpp"
#include "geometry_msgs/msg/transform.hpp"
#include "geometry_msgs/msg/transform_stamped.hpp"
#include "nav_msgs/msg/occupancy_grid.hpp"
#include "sensor_msgs/msg/laser_scan.hpp"
#include "sensor_msgs/msg/multi_echo_laser_scan.hpp"
#include "sensor_msgs/msg/point_cloud2.hpp"
#include <rclcpp/rclcpp.hpp>
namespace cartographer_ros {
sensor_msgs::msg::PointCloud2 ToPointCloud2Message(
int64_t timestamp, const std::string& frame_id,
const ::cartographer::sensor::TimedPointCloud& point_cloud);
geometry_msgs::msg::Transform ToGeometryMsgTransform(
const ::cartographer::transform::Rigid3d& rigid3d);
geometry_msgs::msg::Pose ToGeometryMsgPose(
const ::cartographer::transform::Rigid3d& rigid3d);
geometry_msgs::msg::Point ToGeometryMsgPoint(const Eigen::Vector3d& vector3d);
// Converts ROS message to point cloud. Returns the time when the last point
// was acquired (different from the ROS timestamp). Timing of points is given in
// the fourth component of each point relative to `Time`.
std::tuple<::cartographer::sensor::PointCloudWithIntensities,
::cartographer::common::Time>
ToPointCloudWithIntensities(const sensor_msgs::msg::LaserScan& msg);
std::tuple<::cartographer::sensor::PointCloudWithIntensities,
::cartographer::common::Time>
ToPointCloudWithIntensities(const sensor_msgs::msg::MultiEchoLaserScan& msg);
std::tuple<::cartographer::sensor::PointCloudWithIntensities,
::cartographer::common::Time>
ToPointCloudWithIntensities(const sensor_msgs::msg::PointCloud2& msg);
::cartographer::sensor::LandmarkData ToLandmarkData(
const cartographer_ros_msgs::msg::LandmarkList& landmark_list);
::cartographer::transform::Rigid3d ToRigid3d(
const geometry_msgs::msg::TransformStamped& transform);
::cartographer::transform::Rigid3d ToRigid3d(const geometry_msgs::msg::Pose& pose);
Eigen::Vector3d ToEigen(const geometry_msgs::msg::Vector3& vector3);
Eigen::Quaterniond ToEigen(const geometry_msgs::msg::Quaternion& quaternion);
// Converts from WGS84 (latitude, longitude, altitude) to ECEF.
Eigen::Vector3d LatLongAltToEcef(double latitude, double longitude,
double altitude);
// Returns a transform that takes ECEF coordinates from nearby points to a local
// frame that has z pointing upwards.
cartographer::transform::Rigid3d ComputeLocalFrameFromLatLong(double latitude,
double longitude);
// Points to an occupancy grid message at a specific resolution from painted
// submap slices obtained via ::cartographer::io::PaintSubmapSlices(...).
std::unique_ptr<nav_msgs::msg::OccupancyGrid> CreateOccupancyGridMsg(
const cartographer::io::PaintSubmapSlicesResult& painted_slices,
const double resolution, const std::string& frame_id,
const rclcpp::Time& time);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MSG_CONVERSION_H
@@ -0,0 +1,246 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_H
#include <map>
#include <memory>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "absl/synchronization/mutex.h"
#include "cartographer/common/fixed_ratio_sampler.h"
#include "cartographer/mapping/map_builder_interface.h"
#include "cartographer/mapping/pose_extrapolator.h"
#include "cartographer_ros/map_builder_bridge.h"
#include "cartographer_ros/metrics/family_factory.h"
#include "cartographer_ros/node_constants.h"
#include "cartographer_ros/node_options.h"
#include "cartographer_ros/trajectory_options.h"
#include "cartographer_ros_msgs/srv/finish_trajectory.hpp"
#include "cartographer_ros_msgs/srv/get_trajectory_states.hpp"
#include "cartographer_ros_msgs/srv/read_metrics.hpp"
#include "cartographer_ros_msgs/srv/start_trajectory.hpp"
#include "cartographer_ros_msgs/msg/status_response.hpp"
#include "cartographer_ros_msgs/msg/submap_entry.hpp"
#include "cartographer_ros_msgs/msg/submap_list.hpp"
#include "cartographer_ros_msgs/srv/submap_query.hpp"
#include "cartographer_ros_msgs/srv/write_state.hpp"
#include "nav_msgs/msg/odometry.hpp"
#include <rclcpp/rclcpp.hpp>
#include <sensor_msgs/msg/imu.hpp>
#include <sensor_msgs/msg/laser_scan.hpp>
#include <sensor_msgs/msg/multi_echo_laser_scan.hpp>
#include <sensor_msgs/msg/nav_sat_fix.hpp>
#include <sensor_msgs/msg/point_cloud2.hpp>
#include <tf2_ros/transform_broadcaster.h>
#include <tf2_ros/buffer.h>
#include <tf2_ros/transform_listener.h>
namespace cartographer_ros {
// Wires up ROS topics to SLAM.
class Node {
public:
Node(const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
std::shared_ptr<tf2_ros::Buffer> tf_buffer,
rclcpp::Node::SharedPtr node,
bool collect_metrics);
~Node();
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
// Finishes all yet active trajectories.
void FinishAllTrajectories();
// Finishes a single given trajectory. Returns false if the trajectory did not
// exist or was already finished.
bool FinishTrajectory(int trajectory_id);
// Runs final optimization. All trajectories have to be finished when calling.
void RunFinalOptimization();
// Starts the first trajectory with the default topics.
void StartTrajectoryWithDefaultTopics(const TrajectoryOptions& options);
// Returns unique SensorIds for multiple input bag files based on
// their TrajectoryOptions.
// 'SensorId::id' is the expected ROS topic name.
std::vector<
std::set<::cartographer::mapping::TrajectoryBuilderInterface::SensorId>>
ComputeDefaultSensorIdsForMultipleBags(
const std::vector<TrajectoryOptions>& bags_options) const;
// Adds a trajectory for offline processing, i.e. not listening to topics.
int AddOfflineTrajectory(
const std::set<
cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& options);
// The following functions handle adding sensor data to a trajectory.
void HandleOdometryMessage(int trajectory_id, const std::string& sensor_id,
const nav_msgs::msg::Odometry::ConstSharedPtr& msg);
void HandleNavSatFixMessage(int trajectory_id, const std::string& sensor_id,
const sensor_msgs::msg::NavSatFix::ConstSharedPtr& msg);
void HandleLandmarkMessage(
int trajectory_id, const std::string& sensor_id,
const cartographer_ros_msgs::msg::LandmarkList::ConstSharedPtr& msg);
void HandleImuMessage(int trajectory_id, const std::string& sensor_id,
const sensor_msgs::msg::Imu::ConstSharedPtr &msg);
void HandleLaserScanMessage(int trajectory_id, const std::string& sensor_id,
const sensor_msgs::msg::LaserScan::ConstSharedPtr& msg);
void HandleMultiEchoLaserScanMessage(
int trajectory_id, const std::string& sensor_id,
const sensor_msgs::msg::MultiEchoLaserScan::ConstSharedPtr& msg);
void HandlePointCloud2Message(int trajectory_id, const std::string& sensor_id,
const sensor_msgs::msg::PointCloud2::ConstSharedPtr& msg);
// Serializes the complete Node state.
void SerializeState(const std::string& filename,
const bool include_unfinished_submaps);
// Loads a serialized SLAM state from a .pbstream file.
void LoadState(const std::string& state_filename, bool load_frozen_state);
private:
struct Subscriber {
rclcpp::SubscriptionBase::SharedPtr subscriber;
// ::ros::Subscriber::getTopic() does not necessarily return the same
// std::string
// it was given in its constructor. Since we rely on the topic name as the
// unique identifier of a subscriber, we remember it ourselves.
std::string topic;
};
bool handleSubmapQuery(
const cartographer_ros_msgs::srv::SubmapQuery::Request::SharedPtr request,
cartographer_ros_msgs::srv::SubmapQuery::Response::SharedPtr response);
bool handleTrajectoryQuery(
const cartographer_ros_msgs::srv::TrajectoryQuery::Request::SharedPtr request,
cartographer_ros_msgs::srv::TrajectoryQuery::Response::SharedPtr response);
bool handleStartTrajectory(
const cartographer_ros_msgs::srv::StartTrajectory::Request::SharedPtr request,
cartographer_ros_msgs::srv::StartTrajectory::Response::SharedPtr response);
bool handleFinishTrajectory(
const cartographer_ros_msgs::srv::FinishTrajectory::Request::SharedPtr request,
cartographer_ros_msgs::srv::FinishTrajectory::Response::SharedPtr response);
bool handleWriteState(
const cartographer_ros_msgs::srv::WriteState::Request::SharedPtr request,
cartographer_ros_msgs::srv::WriteState::Response::SharedPtr response);
bool handleGetTrajectoryStates(
const cartographer_ros_msgs::srv::GetTrajectoryStates::Request::SharedPtr,
cartographer_ros_msgs::srv::GetTrajectoryStates::Response::SharedPtr response);
bool handleReadMetrics(const cartographer_ros_msgs::srv::ReadMetrics::Request::SharedPtr,
cartographer_ros_msgs::srv::ReadMetrics::Response::SharedPtr response);
// Returns the set of SensorIds expected for a trajectory.
// 'SensorId::id' is the expected ROS topic name.
std::set<::cartographer::mapping::TrajectoryBuilderInterface::SensorId>
ComputeExpectedSensorIds(const TrajectoryOptions& options) const;
int AddTrajectory(const TrajectoryOptions& options);
void LaunchSubscribers(const TrajectoryOptions& options, int trajectory_id);
void PublishSubmapList();
void AddExtrapolator(int trajectory_id, const TrajectoryOptions& options);
void AddSensorSamplers(int trajectory_id, const TrajectoryOptions& options);
void PublishLocalTrajectoryData();
void PublishTrajectoryNodeList();
void PublishLandmarkPosesList();
void PublishConstraintList();
bool ValidateTrajectoryOptions(const TrajectoryOptions& options);
bool ValidateTopicNames(const TrajectoryOptions& options);
cartographer_ros_msgs::msg::StatusResponse FinishTrajectoryUnderLock(
int trajectory_id) EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void MaybeWarnAboutTopicMismatch();
// Helper function for service handlers that need to check trajectory states.
cartographer_ros_msgs::msg::StatusResponse TrajectoryStateToStatus(
int trajectory_id,
const std::set<
cartographer::mapping::PoseGraphInterface::TrajectoryState>&
valid_states);
const NodeOptions node_options_;
std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster_;
absl::Mutex mutex_;
std::unique_ptr<cartographer_ros::metrics::FamilyFactory> metrics_registry_;
std::shared_ptr<MapBuilderBridge> map_builder_bridge_ GUARDED_BY(mutex_);
rclcpp::Node::SharedPtr node_;
::rclcpp::Publisher<::cartographer_ros_msgs::msg::SubmapList>::SharedPtr submap_list_publisher_;
::rclcpp::Publisher<::visualization_msgs::msg::MarkerArray>::SharedPtr trajectory_node_list_publisher_;
::rclcpp::Publisher<::visualization_msgs::msg::MarkerArray>::SharedPtr landmark_poses_list_publisher_;
::rclcpp::Publisher<::visualization_msgs::msg::MarkerArray>::SharedPtr constraint_list_publisher_;
::rclcpp::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr tracked_pose_publisher_;
::rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr scan_matched_point_cloud_publisher_;
// These ros service servers need to live for the lifetime of the node.
::rclcpp::Service<cartographer_ros_msgs::srv::SubmapQuery>::SharedPtr submap_query_server_;
::rclcpp::Service<cartographer_ros_msgs::srv::TrajectoryQuery>::SharedPtr trajectory_query_server;
::rclcpp::Service<cartographer_ros_msgs::srv::StartTrajectory>::SharedPtr start_trajectory_server_;
::rclcpp::Service<cartographer_ros_msgs::srv::FinishTrajectory>::SharedPtr finish_trajectory_server_;
::rclcpp::Service<cartographer_ros_msgs::srv::WriteState>::SharedPtr write_state_server_;
::rclcpp::Service<cartographer_ros_msgs::srv::GetTrajectoryStates>::SharedPtr get_trajectory_states_server_;
::rclcpp::Service<cartographer_ros_msgs::srv::ReadMetrics>::SharedPtr read_metrics_server_;
struct TrajectorySensorSamplers {
TrajectorySensorSamplers(const double rangefinder_sampling_ratio,
const double odometry_sampling_ratio,
const double fixed_frame_pose_sampling_ratio,
const double imu_sampling_ratio,
const double landmark_sampling_ratio)
: rangefinder_sampler(rangefinder_sampling_ratio),
odometry_sampler(odometry_sampling_ratio),
fixed_frame_pose_sampler(fixed_frame_pose_sampling_ratio),
imu_sampler(imu_sampling_ratio),
landmark_sampler(landmark_sampling_ratio) {}
::cartographer::common::FixedRatioSampler rangefinder_sampler;
::cartographer::common::FixedRatioSampler odometry_sampler;
::cartographer::common::FixedRatioSampler fixed_frame_pose_sampler;
::cartographer::common::FixedRatioSampler imu_sampler;
::cartographer::common::FixedRatioSampler landmark_sampler;
};
// These are keyed with 'trajectory_id'.
std::map<int, ::cartographer::mapping::PoseExtrapolator> extrapolators_;
std::map<int, builtin_interfaces::msg::Time> last_published_tf_stamps_;
std::unordered_map<int, TrajectorySensorSamplers> sensor_samplers_;
std::unordered_map<int, std::vector<Subscriber>> subscribers_;
std::unordered_set<std::string> subscribed_topics_;
std::unordered_set<int> trajectories_scheduled_for_finish_;
// The timer for publishing local trajectory data (i.e. pose transforms and
// range data point clouds) is a regular timer which is not triggered when
// simulation time is standing still. This prevents overflowing the transform
// listener buffer by publishing the same transforms over and over again.
::rclcpp::TimerBase::SharedPtr submap_list_timer_;
::rclcpp::TimerBase::SharedPtr local_trajectory_data_timer_;
::rclcpp::TimerBase::SharedPtr trajectory_node_list_timer_;
::rclcpp::TimerBase::SharedPtr landmark_pose_list_timer_;
::rclcpp::TimerBase::SharedPtr constrain_list_timer_;
::rclcpp::TimerBase::SharedPtr maybe_warn_about_topic_mismatch_timer_;
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_H
@@ -0,0 +1,59 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_CONSTANTS_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_CONSTANTS_H
#include <string>
#include <vector>
namespace cartographer_ros {
// Default topic names; expected to be remapped as needed.
constexpr char kLaserScanTopic[] = "scan";
constexpr char kMultiEchoLaserScanTopic[] = "echoes";
constexpr char kPointCloud2Topic[] = "points2";
constexpr char kImuTopic[] = "imu";
constexpr char kOdometryTopic[] = "odom";
constexpr char kNavSatFixTopic[] = "fix";
constexpr char kLandmarkTopic[] = "landmark";
constexpr char kFinishTrajectoryServiceName[] = "finish_trajectory";
constexpr char kOccupancyGridTopic[] = "map";
constexpr char kScanMatchedPointCloudTopic[] = "scan_matched_points2";
constexpr char kSubmapListTopic[] = "submap_list";
constexpr char kTrackedPoseTopic[] = "tracked_pose";
constexpr char kSubmapQueryServiceName[] = "submap_query";
constexpr char kTrajectoryQueryServiceName[] = "trajectory_query";
constexpr char kStartTrajectoryServiceName[] = "start_trajectory";
constexpr char kWriteStateServiceName[] = "write_state";
constexpr char kGetTrajectoryStatesServiceName[] = "get_trajectory_states";
constexpr char kReadMetricsServiceName[] = "read_metrics";
constexpr char kTrajectoryNodeListTopic[] = "trajectory_node_list";
constexpr char kLandmarkPosesListTopic[] = "landmark_poses_list";
constexpr char kConstraintListTopic[] = "constraint_list";
constexpr double kConstraintPublishPeriodSec = 0.5;
constexpr double kTopicMismatchCheckDelaySec = 3.0;
constexpr int kInfiniteSubscriberQueueSize = 0;
constexpr int kLatestOnlyPublisherQueueSize = 1;
// For multiple topics adds numbers to the topic name and returns the list.
std::vector<std::string> ComputeRepeatedTopicNames(const std::string& topic,
int num_topics);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_CONSTANTS_H
@@ -0,0 +1,51 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_OPTIONS_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_OPTIONS_H
#include <string>
#include <tuple>
#include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/common/port.h"
#include "cartographer/mapping/proto/map_builder_options.pb.h"
#include "cartographer_ros/trajectory_options.h"
namespace cartographer_ros {
// Top-level options of Cartographer's ROS integration.
struct NodeOptions {
::cartographer::mapping::proto::MapBuilderOptions map_builder_options;
std::string map_frame;
double lookup_transform_timeout_sec;
double submap_publish_period_sec;
double pose_publish_period_sec;
double trajectory_publish_period_sec;
bool publish_to_tf = true;
bool publish_tracked_pose = false;
bool use_pose_extrapolator = true;
};
NodeOptions CreateNodeOptions(
::cartographer::common::LuaParameterDictionary* lua_parameter_dictionary);
std::tuple<NodeOptions, TrajectoryOptions> LoadOptions(
const std::string& configuration_directory,
const std::string& configuration_basename);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_NODE_OPTIONS_H
@@ -0,0 +1,40 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_OFFLINE_NODE_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_OFFLINE_NODE_H
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <rclcpp/rclcpp.hpp>
#include "cartographer/mapping/map_builder_interface.h"
#include "cartographer_ros/node_options.h"
namespace cartographer_ros {
using MapBuilderFactory =
std::function<std::unique_ptr<::cartographer::mapping::MapBuilderInterface>(
const ::cartographer::mapping::proto::MapBuilderOptions&)>;
void RunOfflineNode(const MapBuilderFactory& map_builder_factory,
rclcpp::Node::SharedPtr cartographer_offline_node);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_OFFLINE_NODE_H
@@ -0,0 +1,116 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_PLAYABLE_BAG_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_PLAYABLE_BAG_H
#include <functional>
#include <queue>
#include "cartographer_ros_msgs/msg/bagfile_progress.hpp"
#include <rclcpp/rclcpp.hpp>
#include <rosbag2_cpp/reader.hpp>
#include <rosbag2_cpp/readers/sequential_reader.hpp>
#include <rosbag2_cpp/writer.hpp>
#include <rosbag2_cpp/writers/sequential_writer.hpp>
#include "tf2_ros/buffer.h"
namespace cartographer_ros {
class PlayableBag {
public:
// Handles messages early, i.e. when they are about to enter the buffer.
// Returns a boolean indicating whether the message should enter the buffer.
using FilteringEarlyMessageHandler =
std::function<bool /* forward_message_to_buffer */ (
std::shared_ptr<rosbag2_storage::SerializedBagMessage>)>;
PlayableBag(const std::string& bag_filename, int bag_id,
rclcpp::Duration buffer_delay,
FilteringEarlyMessageHandler filtering_early_message_handler);
rclcpp::Time PeekMessageTime() const;
rosbag2_storage::SerializedBagMessage GetNextMessage(
cartographer_ros_msgs::msg::BagfileProgress* progress);
bool IsMessageAvailable() const;
std::tuple<rclcpp::Time, rclcpp::Time> GetBeginEndTime() const;
int bag_id() const;
std::set<std::string> topics() const { return topics_; }
double duration_in_seconds() const { return duration_in_seconds_; }
bool finished() const { return finished_; }
rosbag2_storage::BagMetadata bag_metadata;
private:
void AdvanceOneMessage();
void AdvanceUntilMessageAvailable();
std::unique_ptr<rosbag2_cpp::Reader> bag_reader_;
bool finished_;
const int bag_id_;
const std::string bag_filename_;
double duration_in_seconds_;
int message_counter_;
std::deque<rosbag2_storage::SerializedBagMessage> buffered_messages_;
const rclcpp::Duration buffer_delay_;
FilteringEarlyMessageHandler filtering_early_message_handler_;
std::set<std::string> topics_;
};
class PlayableBagMultiplexer {
public:
PlayableBagMultiplexer(rclcpp::Node::SharedPtr node);
void AddPlayableBag(PlayableBag playable_bag);
// Returns the next message from the multiplexed (merge-sorted) message
// stream, along with the bag id corresponding to the message, and whether
// this was the last message in that bag.
std::tuple<rosbag2_storage::SerializedBagMessage, int, std::string, bool> GetNextMessage();
bool IsMessageAvailable() const;
rclcpp::Time PeekMessageTime() const;
std::set<std::string> topics() const { return topics_; }
private:
struct BagMessageItem {
rclcpp::Time message_timestamp;
int bag_index;
struct TimestampIsGreater {
bool operator()(const BagMessageItem& l, const BagMessageItem& r) {
return l.message_timestamp > r.message_timestamp;
}
};
};
rclcpp::Node::SharedPtr node_;
// Publishes information about the bag-file(s) processing and its progress
rclcpp::Publisher<cartographer_ros_msgs::msg::BagfileProgress>::SharedPtr bag_progress_pub_;
// Map between bagfile id and the last time when its progress was published
std::map<int, rclcpp::Time> bag_progress_time_map_;
// The time interval of publishing bag-file(s) processing in seconds
double progress_pub_interval_;
std::vector<PlayableBag> playable_bags_;
std::priority_queue<BagMessageItem, std::vector<BagMessageItem>,
BagMessageItem::TimestampIsGreater>
next_message_queue_;
std::set<std::string> topics_;
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_PLAYABLE_BAG_H
@@ -0,0 +1,47 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_LOG_SINK_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_LOG_SINK_H
#include <ctime>
#include "glog/logging.h"
#include <rclcpp/rclcpp.hpp>
namespace cartographer_ros {
// Makes Google logging use ROS logging for output while an instance of this
// class exists.
class ScopedRosLogSink : public ::google::LogSink {
public:
ScopedRosLogSink();
~ScopedRosLogSink() override;
void send(::google::LogSeverity severity, const char* filename,
const char* base_filename, int line, const struct std::tm* tm_time,
const char* message, size_t message_len) override;
void WaitTillSent() override;
private:
bool will_die_;
rclcpp::Logger logger_{rclcpp::get_logger("cartographer logger")};
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_LOG_SINK_H
@@ -0,0 +1,41 @@
/*
* Copyright 2017 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_MAP_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_MAP_H
#include <string>
#include "Eigen/Core"
#include "cartographer/io/file_writer.h"
#include "cartographer/io/image.h"
#include "cartographer/mapping/2d/map_limits.h"
namespace cartographer_ros {
// Write 'image' as a pgm into 'file_writer'. The resolution is used in the
// comment only'
void WritePgm(const ::cartographer::io::Image& image, const double resolution,
::cartographer::io::FileWriter* file_writer);
// Write the corresponding yaml into 'file_writer'.
void WriteYaml(const double resolution, const Eigen::Vector2d& origin,
const std::string& pgm_filename,
::cartographer::io::FileWriter* file_writer);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_MAP_H
@@ -0,0 +1,69 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_MAP_WRITING_POINTS_PROCESSOR_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_MAP_WRITING_POINTS_PROCESSOR_H
#include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/io/file_writer.h"
#include "cartographer/io/points_processor.h"
#include "cartographer/mapping/2d/probability_grid.h"
#include "cartographer/mapping/2d/probability_grid_range_data_inserter_2d.h"
#include "cartographer/mapping/proto/probability_grid_range_data_inserter_options_2d.pb.h"
#include "cartographer/mapping/value_conversion_tables.h"
namespace cartographer_ros {
// Very similar to Cartographer's ProbabilityGridPointsProcessor, but writes
// out a PGM and YAML suitable for ROS map server to consume.
class RosMapWritingPointsProcessor
: public ::cartographer::io::PointsProcessor {
public:
constexpr static const char* kConfigurationFileActionName = "write_ros_map";
RosMapWritingPointsProcessor(
double resolution,
const ::cartographer::mapping::proto::
ProbabilityGridRangeDataInserterOptions2D&
range_data_inserter_options,
::cartographer::io::FileWriterFactory file_writer_factory,
const std::string& filestem, PointsProcessor* next);
RosMapWritingPointsProcessor(const RosMapWritingPointsProcessor&) = delete;
RosMapWritingPointsProcessor& operator=(const RosMapWritingPointsProcessor&) =
delete;
static std::unique_ptr<RosMapWritingPointsProcessor> FromDictionary(
::cartographer::io::FileWriterFactory file_writer_factory,
::cartographer::common::LuaParameterDictionary* dictionary,
PointsProcessor* next);
~RosMapWritingPointsProcessor() override {}
void Process(std::unique_ptr<::cartographer::io::PointsBatch> batch) override;
FlushResult Flush() override;
private:
const std::string filestem_;
PointsProcessor* const next_;
::cartographer::io::FileWriterFactory file_writer_factory_;
::cartographer::mapping::ProbabilityGridRangeDataInserter2D
range_data_inserter_;
::cartographer::mapping::ValueConversionTables conversion_tables_;
::cartographer::mapping::ProbabilityGrid probability_grid_;
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_ROS_MAP_WRITING_POINTS_PROCESSOR_H
@@ -0,0 +1,99 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_SENSOR_BRIDGE_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_SENSOR_BRIDGE_H
#include <memory>
#include "absl/types/optional.h"
#include "cartographer/mapping/trajectory_builder_interface.h"
#include "cartographer/sensor/imu_data.h"
#include "cartographer/sensor/odometry_data.h"
#include "cartographer/transform/rigid_transform.h"
#include "cartographer/transform/transform.h"
#include "cartographer_ros/tf_bridge.h"
#include "cartographer_ros_msgs/msg/landmark_list.hpp"
#include <geometry_msgs/msg/transform.hpp>
#include <geometry_msgs/msg/transform_stamped.hpp>
#include <nav_msgs/msg/occupancy_grid.hpp>
#include <nav_msgs/msg/odometry.hpp>
#include <sensor_msgs/msg/imu.hpp>
#include <sensor_msgs/msg/laser_scan.hpp>
#include <sensor_msgs/msg/multi_echo_laser_scan.hpp>
#include <sensor_msgs/msg/nav_sat_fix.hpp>
#include <sensor_msgs/msg/point_cloud2.hpp>
namespace cartographer_ros {
// Converts ROS messages into SensorData in tracking frame for the MapBuilder.
class SensorBridge {
public:
explicit SensorBridge(
int num_subdivisions_per_laser_scan, const std::string& tracking_frame,
double lookup_transform_timeout_sec, tf2_ros::Buffer* tf_buffer,
::cartographer::mapping::TrajectoryBuilderInterface* trajectory_builder);
SensorBridge(const SensorBridge&) = delete;
SensorBridge& operator=(const SensorBridge&) = delete;
std::unique_ptr<::cartographer::sensor::OdometryData> ToOdometryData(
const nav_msgs::msg::Odometry::ConstSharedPtr& msg);
void HandleOdometryMessage(const std::string& sensor_id,
const nav_msgs::msg::Odometry::ConstSharedPtr& msg);
void HandleNavSatFixMessage(const std::string& sensor_id,
const sensor_msgs::msg::NavSatFix::ConstSharedPtr& msg);
void HandleLandmarkMessage(
const std::string& sensor_id,
const cartographer_ros_msgs::msg::LandmarkList::ConstSharedPtr& msg);
std::unique_ptr<::cartographer::sensor::ImuData> ToImuData(
const sensor_msgs::msg::Imu::ConstSharedPtr& msg);
void HandleImuMessage(const std::string& sensor_id,
const sensor_msgs::msg::Imu::ConstSharedPtr& msg);
void HandleLaserScanMessage(const std::string& sensor_id,
const sensor_msgs::msg::LaserScan::ConstSharedPtr& msg);
void HandleMultiEchoLaserScanMessage(
const std::string& sensor_id,
const sensor_msgs::msg::MultiEchoLaserScan::ConstSharedPtr& msg);
void HandlePointCloud2Message(const std::string& sensor_id,
const sensor_msgs::msg::PointCloud2::ConstSharedPtr& msg);
const TfBridge& tf_bridge() const;
private:
void HandleLaserScan(
const std::string& sensor_id, ::cartographer::common::Time start_time,
const std::string& frame_id,
const ::cartographer::sensor::PointCloudWithIntensities& points);
void HandleRangefinder(const std::string& sensor_id,
::cartographer::common::Time time,
const std::string& frame_id,
const ::cartographer::sensor::TimedPointCloud& ranges);
const int num_subdivisions_per_laser_scan_;
std::map<std::string, cartographer::common::Time>
sensor_to_previous_subdivision_time_;
const TfBridge tf_bridge_;
::cartographer::mapping::TrajectoryBuilderInterface* const
trajectory_builder_;
absl::optional<::cartographer::transform::Rigid3d> ecef_to_local_frame_;
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_SENSOR_BRIDGE_H
@@ -0,0 +1,43 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_SUBMAP_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_SUBMAP_H
#include <memory>
#include <string>
#include <vector>
#include "cartographer/io/image.h"
#include "cartographer/io/submap_painter.h"
#include "cartographer/mapping/id.h"
#include "cartographer/transform/rigid_transform.h"
#include "cartographer_ros_msgs/srv/submap_query.hpp"
#include <rclcpp/rclcpp.hpp>
namespace cartographer_ros {
// Fetch 'submap_id' using the 'client' and returning the response or 'nullptr'
// on error.
std::unique_ptr<::cartographer::io::SubmapTextures> FetchSubmapTextures(
const ::cartographer::mapping::SubmapId& submap_id,
rclcpp::Client<cartographer_ros_msgs::srv::SubmapQuery>::SharedPtr client,
rclcpp::executors::SingleThreadedExecutor::SharedPtr callback_group_executor,
const std::chrono::milliseconds timeout);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_SUBMAP_H
@@ -0,0 +1,51 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TF_BRIDGE_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TF_BRIDGE_H
#include <memory>
#include "cartographer/transform/rigid_transform.h"
#include "cartographer_ros/time_conversion.h"
#include <tf2_ros/buffer.h>
#include <rclcpp/rclcpp.hpp>
namespace cartographer_ros {
class TfBridge {
public:
TfBridge(const std::string& tracking_frame,
double lookup_transform_timeout_sec, const tf2_ros::Buffer* buffer);
~TfBridge() {}
TfBridge(const TfBridge&) = delete;
TfBridge& operator=(const TfBridge&) = delete;
// Returns the transform for 'frame_id' to 'tracking_frame_' if it exists at
// 'time'.
std::unique_ptr<::cartographer::transform::Rigid3d> LookupToTracking(
::cartographer::common::Time time, const std::string& frame_id) const;
private:
const std::string tracking_frame_;
const double lookup_transform_timeout_sec_;
const tf2_ros::Buffer* const buffer_;
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TF_BRIDGE_H
@@ -0,0 +1,32 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TIME_CONVERSION_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TIME_CONVERSION_H
#include "cartographer/common/time.h"
#include <builtin_interfaces/msg/time.hpp>
#include <rclcpp/rclcpp.hpp>
namespace cartographer_ros {
rclcpp::Time ToRos(::cartographer::common::Time time);
::cartographer::common::Time FromRos(const rclcpp::Time& time);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TIME_CONVERSION_H
@@ -0,0 +1,55 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TRAJECTORY_OPTIONS_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TRAJECTORY_OPTIONS_H
#include <string>
#include "cartographer/common/lua_parameter_dictionary.h"
#include "cartographer/common/port.h"
#include "cartographer/mapping/proto/trajectory_builder_options.pb.h"
namespace cartographer_ros {
struct TrajectoryOptions {
::cartographer::mapping::proto::TrajectoryBuilderOptions
trajectory_builder_options;
std::string tracking_frame;
std::string published_frame;
std::string odom_frame;
bool provide_odom_frame;
bool use_odometry;
bool use_nav_sat;
bool use_landmarks;
bool publish_frame_projected_to_2d;
int num_laser_scans;
int num_multi_echo_laser_scans;
int num_subdivisions_per_laser_scan;
int num_point_clouds;
double rangefinder_sampling_ratio;
double odometry_sampling_ratio;
double fixed_frame_pose_sampling_ratio;
double imu_sampling_ratio;
double landmarks_sampling_ratio;
};
TrajectoryOptions CreateTrajectoryOptions(
::cartographer::common::LuaParameterDictionary* lua_parameter_dictionary);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_TRAJECTORY_OPTIONS_H
@@ -0,0 +1,32 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_URDF_READER_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_URDF_READER_H
#include <vector>
#include "cartographer/common/port.h"
#include "tf2_ros/buffer.h"
namespace cartographer_ros {
std::vector<geometry_msgs::msg::TransformStamped> ReadStaticTransformsFromUrdf(
const std::string& urdf_filename, std::shared_ptr<tf2_ros::Buffer> tf_buffer);
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_URDF_READER_H
@@ -0,0 +1,67 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
from launch.actions import Shutdown
def generate_launch_description():
## ***** Launch arguments *****
use_sim_time_arg = DeclareLaunchArgument('use_sim_time', default_value = 'False')
## ***** File paths ******
pkg_share = FindPackageShare('agv_pro_description').find('agv_pro_description')
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_node',
parameters = [{'use_sim_time': LaunchConfiguration('use_sim_time')}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'agvpro_backpack_2d.lua'],
remappings = [
('echoes', 'horizontal_laser_2d')],
output = 'screen'
)
cartographer_occupancy_grid_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_occupancy_grid_node',
parameters = [
{'use_sim_time': False},
{'resolution': 0.05}],
)
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_2d.rviz'],
parameters = [{'use_sim_time': False}],
)
return LaunchDescription([
use_sim_time_arg,
# Nodes
rviz_node,
cartographer_node,
cartographer_occupancy_grid_node,
])
@@ -0,0 +1,58 @@
"""
Copyright 2016 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
import os
def generate_launch_description():
## ***** Launch arguments *****
configuration_directory_arg = DeclareLaunchArgument('configuration_directory', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files')
config_file_arg = DeclareLaunchArgument('config_file', default_value = 'assets_writer_backpack_2d.lua')
urdf_filename_arg = DeclareLaunchArgument('urdf_filename', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/urdf/backpack_2d.urdf')
bag_filenames_arg = DeclareLaunchArgument('bag_filenames')
pose_graph_filename_arg = DeclareLaunchArgument('pose_graph_filename')
## ***** Nodes *****
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_assets_writer',
parameters = [{'use_sim_time': False}],
arguments = [
'-configuration_directory', LaunchConfiguration('configuration_directory'),
'-configuration_basename', LaunchConfiguration('config_file'),
'-urdf_filename', LaunchConfiguration('urdf_filename'),
'-bag_filenames', LaunchConfiguration('bag_filenames'),
'-pose_graph_filename', LaunchConfiguration('pose_graph_filename')],
output = 'screen'
)
return LaunchDescription([
configuration_directory_arg,
config_file_arg,
urdf_filename_arg,
bag_filenames_arg,
pose_graph_filename_arg,
# Nodes
cartographer_node,
])
@@ -0,0 +1,58 @@
"""
Copyright 2016 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
import os
def generate_launch_description():
## ***** Launch arguments *****
configuration_directory_arg = DeclareLaunchArgument('configuration_directory', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files')
config_file_arg = DeclareLaunchArgument('config_file', default_value = 'assets_writer_backpack_3d.lua')
urdf_filename_arg = DeclareLaunchArgument('urdf_filename', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/urdf/backpack_3d.urdf')
bag_filenames_arg = DeclareLaunchArgument('bag_filenames')
pose_graph_filename_arg = DeclareLaunchArgument('pose_graph_filename')
## ***** Nodes *****
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_assets_writer',
parameters = [{'use_sim_time': False}],
arguments = [
'-configuration_directory', LaunchConfiguration('configuration_directory'),
'-configuration_basename', LaunchConfiguration('config_file'),
'-urdf_filename', LaunchConfiguration('urdf_filename'),
'-bag_filenames', LaunchConfiguration('bag_filenames'),
'-pose_graph_filename', LaunchConfiguration('pose_graph_filename')],
output = 'screen'
)
return LaunchDescription([
configuration_directory_arg,
config_file_arg,
urdf_filename_arg,
bag_filenames_arg,
pose_graph_filename_arg,
# Nodes
cartographer_node,
])
@@ -0,0 +1,54 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
import os
def generate_launch_description():
## ***** Launch arguments *****
urdf_filename_arg = DeclareLaunchArgument('urdf_filename', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/urdf/backpack_2d.urdf')
bag_filenames_arg = DeclareLaunchArgument('bag_filenames')
pose_graph_filename_arg = DeclareLaunchArgument('pose_graph_filename')
## ***** Nodes *****
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_assets_writer',
parameters = [{'use_sim_time': False}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'assets_writer_ros_map.lua',
'-urdf_filename', LaunchConfiguration('urdf_filename'),
'-bag_filenames', LaunchConfiguration('bag_filenames'),
'-pose_graph_filename', LaunchConfiguration('pose_graph_filename')],
output = 'screen'
)
return LaunchDescription([
urdf_filename_arg,
bag_filenames_arg,
pose_graph_filename_arg,
# Nodes
cartographer_node,
])
@@ -0,0 +1,75 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
import os
def generate_launch_description():
## ***** Launch arguments *****
use_sim_time_arg = DeclareLaunchArgument('use_sim_time', default_value = 'False')
## ***** File paths ******
pkg_share = FindPackageShare('cartographer_ros').find('cartographer_ros')
urdf_dir = os.path.join(pkg_share, 'urdf')
urdf_file = os.path.join(urdf_dir, 'backpack_2d.urdf')
with open(urdf_file, 'r') as infp:
robot_desc = infp.read()
## ***** Nodes *****
robot_state_publisher_node = Node(
package = 'robot_state_publisher',
executable = 'robot_state_publisher',
parameters=[
{'robot_description': robot_desc},
{'use_sim_time': LaunchConfiguration('use_sim_time')}],
output = 'screen'
)
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_node',
parameters = [{'use_sim_time': LaunchConfiguration('use_sim_time')}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'backpack_2d.lua'],
remappings = [
('echoes', 'horizontal_laser_2d')],
output = 'screen'
)
cartographer_occupancy_grid_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_occupancy_grid_node',
parameters = [
{'use_sim_time': True},
{'resolution': 0.05}],
)
return LaunchDescription([
use_sim_time_arg,
# Nodes
robot_state_publisher_node,
cartographer_node,
cartographer_occupancy_grid_node,
])
@@ -0,0 +1,76 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
import os
def generate_launch_description():
## ***** Launch arguments *****
use_sim_time_arg = DeclareLaunchArgument('use_sim_time', default_value = 'False')
## ***** File paths ******
pkg_share = FindPackageShare('cartographer_ros').find('cartographer_ros')
urdf_dir = os.path.join(pkg_share, 'urdf')
urdf_file = os.path.join(urdf_dir, 'backpack_3d.urdf')
with open(urdf_file, 'r') as infp:
robot_desc = infp.read()
## ***** Nodes *****
robot_state_publisher_node = Node(
package = 'robot_state_publisher',
executable = 'robot_state_publisher',
parameters=[
{'robot_description': robot_desc},
{'use_sim_time': LaunchConfiguration('use_sim_time')}],
output = 'screen'
)
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_node',
parameters = [{'use_sim_time': LaunchConfiguration('use_sim_time')}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'backpack_3d.lua'],
remappings = [
('points2_1', 'horizontal_laser_3d'),
('points2_2', 'vertical_laser_3d')],
output = 'screen'
)
cartographer_occupancy_grid_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_occupancy_grid_node',
parameters = [
{'use_sim_time': True},
{'resolution': 0.05}],
)
return LaunchDescription([
use_sim_time_arg,
# Nodes
robot_state_publisher_node,
cartographer_node,
cartographer_occupancy_grid_node,
])
@@ -0,0 +1,57 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, ExecuteProcess
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import Shutdown
def generate_launch_description():
## ***** Launch arguments *****
bag_filename_arg = DeclareLaunchArgument('bag_filename')
## ***** Nodes *****
backpack_2d_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(FindPackageShare('cartographer_ros').find('cartographer_ros') + '/launch/backpack_2d.launch.py'),
launch_arguments = {'use_sim_time': 'True'}.items()
)
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_2d.rviz'],
parameters = [{'use_sim_time': True}],
)
ros2_bag_play_cmd = ExecuteProcess(
cmd = ['ros2', 'bag', 'play', LaunchConfiguration('bag_filename'), '--clock'],
name = 'rosbag_play',
)
return LaunchDescription([
# Launch arguments
bag_filename_arg,
# Nodes
backpack_2d_launch,
rviz_node,
ros2_bag_play_cmd
])
@@ -0,0 +1,94 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, ExecuteProcess
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import Shutdown
import os
def generate_launch_description():
## ***** Launch arguments *****
bag_filename_arg = DeclareLaunchArgument('bag_filename')
load_state_filename_arg = DeclareLaunchArgument('load_state_filename')
## ***** File paths ******
pkg_share = FindPackageShare('cartographer_ros').find('cartographer_ros')
urdf_dir = os.path.join(pkg_share, 'urdf')
urdf_file = os.path.join(urdf_dir, 'backpack_2d.urdf')
with open(urdf_file, 'r') as infp:
robot_desc = infp.read()
## ***** Nodes *****
robot_state_publisher_node = Node(
package = 'robot_state_publisher',
executable = 'robot_state_publisher',
parameters=[
{'robot_description': robot_desc},
{'use_sim_time': True}],
output = 'screen'
)
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_node',
parameters = [{'use_sim_time': True}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'backpack_2d_localization.lua',
'-load_state_filename', LaunchConfiguration('load_state_filename')],
remappings = [
('echoes', 'horizontal_laser_2d')],
output = 'screen'
)
cartographer_occupancy_grid_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_occupancy_grid_node',
parameters = [
{'use_sim_time': True},
{'resolution': 0.05}],
)
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_2d.rviz'],
parameters = [{'use_sim_time': True}],
)
ros2_bag_play_cmd = ExecuteProcess(
cmd = ['ros2', 'bag', 'play', LaunchConfiguration('bag_filename'), '--clock'],
name = 'rosbag_play',
)
return LaunchDescription([
# Launch arguments
bag_filename_arg,
load_state_filename_arg,
# Nodes
robot_state_publisher_node,
cartographer_node,
cartographer_occupancy_grid_node,
rviz_node,
ros2_bag_play_cmd
])
@@ -0,0 +1,57 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, ExecuteProcess
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import Shutdown
def generate_launch_description():
## ***** Launch arguments *****
bag_filename_arg = DeclareLaunchArgument('bag_filename')
## ***** Nodes *****
backpack_3d_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(FindPackageShare('cartographer_ros').find('cartographer_ros') + '/launch/backpack_3d.launch.py'),
launch_arguments = {'use_sim_time': 'True'}.items()
)
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_3d.rviz'],
parameters = [{'use_sim_time': True}],
)
ros2_bag_play_cmd = ExecuteProcess(
cmd = ['ros2', 'bag', 'play', LaunchConfiguration('bag_filename'), '--clock'],
name = 'rosbag_play',
)
return LaunchDescription([
# Launch arguments
bag_filename_arg,
# Nodes
backpack_3d_launch,
rviz_node,
ros2_bag_play_cmd
])
@@ -0,0 +1,95 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, ExecuteProcess
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import Shutdown
import os
def generate_launch_description():
## ***** Launch arguments *****
bag_filename_arg = DeclareLaunchArgument('bag_filename')
load_state_filename_arg = DeclareLaunchArgument('load_state_filename')
## ***** File paths ******
pkg_share = FindPackageShare('cartographer_ros').find('cartographer_ros')
urdf_dir = os.path.join(pkg_share, 'urdf')
urdf_file = os.path.join(urdf_dir, 'backpack_3d.urdf')
with open(urdf_file, 'r') as infp:
robot_desc = infp.read()
## ***** Nodes *****
robot_state_publisher_node = Node(
package = 'robot_state_publisher',
executable = 'robot_state_publisher',
parameters=[
{'robot_description': robot_desc},
{'use_sim_time': True}],
output = 'screen'
)
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_node',
parameters = [{'use_sim_time': True}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'backpack_3d_localization.lua',
'-load_state_filename', LaunchConfiguration('load_state_filename'),],
remappings = [
('points2_1', 'horizontal_laser_3d'),
('points2_2', 'vertical_laser_3d')],
output = 'screen'
)
cartographer_occupancy_grid_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_occupancy_grid_node',
parameters = [
{'use_sim_time': True},
{'resolution': 0.05}],
)
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_3d.rviz'],
parameters = [{'use_sim_time': True}],
)
ros2_bag_play_cmd = ExecuteProcess(
cmd = ['ros2', 'bag', 'play', LaunchConfiguration('bag_filename'), '--clock'],
name = 'rosbag_play',
)
return LaunchDescription([
# Launch arguments
bag_filename_arg,
load_state_filename_arg,
# Nodes
robot_state_publisher_node,
cartographer_node,
cartographer_occupancy_grid_node,
rviz_node,
ros2_bag_play_cmd
])
@@ -0,0 +1,47 @@
<!--
Copyright 2016 The Cartographer Authors
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.
-->
<launch>
<param name="/use_sim_time" value="true" />
<node name="cartographer_node" pkg="cartographer_ros"
type="cartographer_node" args="
-configuration_directory
$(find cartographer_ros)/configuration_files
-configuration_basename pr2.lua"
output="screen">
<remap from="scan" to="/base_scan" />
</node>
<node name="cartographer_occupancy_grid_node" pkg="cartographer_ros"
type="cartographer_occupancy_grid_node" args="-resolution 0.05" />
<node name="tf_remove_frames" pkg="cartographer_ros"
type="tf_remove_frames.py">
<remap from="tf_out" to="/tf" />
<rosparam param="remove_frames">
- map
- odom_combined
</rosparam>
</node>
<node name="rviz" pkg="rviz" type="rviz" required="true"
args="-d $(find cartographer_ros)/configuration_files/demo_2d.rviz" />
<node name="playbag" pkg="rosbag" type="play"
args="--clock $(arg bag_filename)">
<remap from="tf" to="tf_in" />
</node>
</launch>
@@ -0,0 +1,91 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, ExecuteProcess
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import Shutdown
import os
def generate_launch_description():
## ***** Launch arguments *****
bag_filename_arg = DeclareLaunchArgument('bag_filename')
## ***** File paths ******
pkg_share = FindPackageShare('cartographer_ros').find('cartographer_ros')
urdf_dir = os.path.join(pkg_share, 'urdf')
urdf_file = os.path.join(urdf_dir, 'backpack_2d.urdf')
with open(urdf_file, 'r') as infp:
robot_desc = infp.read()
## ***** Nodes *****
robot_state_publisher_node = Node(
package = 'robot_state_publisher',
executable = 'robot_state_publisher',
parameters=[
{'robot_description': robot_desc},
{'use_sim_time': True}],
output = 'screen'
)
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_node',
parameters = [{'use_sim_time': True}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'revo_lds.lua'],
remappings = [
('scan', 'horizontal_laser_2d')],
output = 'screen'
)
cartographer_occupancy_grid_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_occupancy_grid_node',
parameters = [
{'use_sim_time': True},
{'resolution': 0.05}],
)
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_2d.rviz'],
parameters = [{'use_sim_time': True}],
)
ros2_bag_play_cmd = ExecuteProcess(
cmd = ['ros2', 'bag', 'play', LaunchConfiguration('bag_filename'), '--clock'],
name = 'rosbag_play',
)
return LaunchDescription([
# Launch arguments
bag_filename_arg,
# Nodes
robot_state_publisher_node,
cartographer_node,
cartographer_occupancy_grid_node,
rviz_node,
ros2_bag_play_cmd
])
@@ -0,0 +1,57 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, ExecuteProcess
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import Shutdown
def generate_launch_description():
## ***** Launch arguments *****
bag_filename_arg = DeclareLaunchArgument('bag_filename')
## ***** Nodes *****
taurob_tracker_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(FindPackageShare('cartographer_ros').find('cartographer_ros') + '/launch/taurob_tracker.launch.py'),
launch_arguments = {'use_sim_time': 'True'}.items()
)
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_3d.rviz'],
parameters = [{'use_sim_time': True}],
)
ros2_bag_play_cmd = ExecuteProcess(
cmd = ['ros2', 'bag', 'play', LaunchConfiguration('bag_filename'), '--clock'],
name = 'rosbag_play',
)
return LaunchDescription([
# Launch arguments
bag_filename_arg,
# Nodes
taurob_tracker_launch,
rviz_node,
ros2_bag_play_cmd
])
@@ -0,0 +1,45 @@
<!--
Copyright 2018 The Cartographer Authors
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.
-->
<launch>
<param name="/use_sim_time" value="true" />
<param name="robot_description"
textfile="$(find cartographer_ros)/urdf/backpack_2d.urdf" />
<node name="robot_state_publisher" pkg="robot_state_publisher"
type="robot_state_publisher" />
<node name="cartographer_grpc_server" pkg="cartographer_ros"
type="cartographer_grpc_server.sh" args="
-configuration_directory $(find cartographer_ros)/configuration_files
-configuration_basename backpack_2d_server.lua">
</node>
<node name="cartographer_grpc_node" pkg="cartographer_ros"
type="cartographer_grpc_node" args="
-client_id CLIENT_ID
-configuration_directory $(find cartographer_ros)/configuration_files
-configuration_basename backpack_2d.lua"
output="screen">
<remap from="echoes" to="horizontal_laser_2d" />
</node>
<node name="playbag" pkg="rosbag" type="play"
args="--clock $(arg bag_filename)" />
<node name="rviz" pkg="rviz" type="rviz" required="true"
args="-d $(find cartographer_ros)/configuration_files/demo_2d.rviz" />
</launch>
@@ -0,0 +1,40 @@
<!--
Copyright 2018 The Cartographer Authors
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.
-->
<launch>
<param name="/use_sim_time" value="true" />
<param name="robot_description"
textfile="$(find cartographer_ros)/urdf/backpack_2d.urdf" />
<node name="robot_state_publisher" pkg="robot_state_publisher"
type="robot_state_publisher" />
<node name="cartographer_grpc_node" pkg="cartographer_ros"
type="cartographer_grpc_node" args="
-client_id CLIENT_ID
-configuration_directory $(find cartographer_ros)/configuration_files
-configuration_basename backpack_2d.lua
-map_filename $(arg map_filename)"
output="screen">
<remap from="echoes" to="horizontal_laser_2d" />
</node>
<node name="playbag" pkg="rosbag" type="play"
args="--clock $(arg bag_filename)" />
<node name="rviz" pkg="rviz" type="rviz" required="true"
args="-d $(find cartographer_ros)/configuration_files/demo_2d.rviz" />
</launch>
@@ -0,0 +1,62 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
def generate_launch_description():
## ***** Launch arguments *****
bag_filenames_arg = DeclareLaunchArgument('bag_filenames')
no_rviz_arg = DeclareLaunchArgument('no_rviz', default_value='false')
rviz_config_arg = DeclareLaunchArgument('rviz_config', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_2d.rviz')
configuration_directory_arg = DeclareLaunchArgument('configuration_directory', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files')
configuration_basenames_arg = DeclareLaunchArgument('configuration_basenames', default_value = 'backpack_2d.lua')
urdf_filenames_arg = DeclareLaunchArgument('urdf_filenames', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/urdf/backpack_2d.urdf')
## ***** Nodes *****
offline_node_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(FindPackageShare('cartographer_ros').find('cartographer_ros') + '/launch/offline_node.launch.py'),
launch_arguments = {
'bag_filenames': LaunchConfiguration('bag_filenames'),
'no_rviz': LaunchConfiguration('no_rviz'),
'rviz_config': LaunchConfiguration('rviz_config'),
'configuration_directory': LaunchConfiguration('configuration_directory'),
'configuration_basenames': LaunchConfiguration('configuration_basenames'),
'urdf_filenames': LaunchConfiguration('urdf_filenames')}.items(),
)
set_remap = SetRemap('horizontal_laser_2d', 'echoes')
return LaunchDescription([
# Launch arguments
bag_filenames_arg,
no_rviz_arg,
rviz_config_arg,
configuration_directory_arg,
configuration_basenames_arg,
urdf_filenames_arg,
# Nodes
set_remap,
offline_node_launch,
])
@@ -0,0 +1,64 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
def generate_launch_description():
## ***** Launch arguments *****
bag_filenames_arg = DeclareLaunchArgument('bag_filenames')
no_rviz_arg = DeclareLaunchArgument('no_rviz', default_value='false')
rviz_config_arg = DeclareLaunchArgument('rviz_config', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_3d.rviz')
configuration_directory_arg = DeclareLaunchArgument('configuration_directory', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files')
configuration_basenames_arg = DeclareLaunchArgument('configuration_basenames', default_value = 'backpack_3d.lua')
urdf_filenames_arg = DeclareLaunchArgument('urdf_filenames', default_value = FindPackageShare('cartographer_ros').find('cartographer_ros') + '/urdf/backpack_3d.urdf')
## ***** Nodes *****
offline_node_launch = IncludeLaunchDescription(
PythonLaunchDescriptionSource(FindPackageShare('cartographer_ros').find('cartographer_ros') + '/launch/offline_node.launch.py'),
launch_arguments = {
'bag_filenames': LaunchConfiguration('bag_filenames'),
'no_rviz': LaunchConfiguration('no_rviz'),
'rviz_config': LaunchConfiguration('rviz_config'),
'configuration_directory': LaunchConfiguration('configuration_directory'),
'configuration_basenames': LaunchConfiguration('configuration_basenames'),
'urdf_filenames': LaunchConfiguration('urdf_filenames')}.items(),
)
set_remap1 = SetRemap('horizontal_laser_3d', 'points2_1')
set_remap2 = SetRemap('vertical_laser_3d', 'points2_2')
return LaunchDescription([
# Launch arguments
bag_filenames_arg,
no_rviz_arg,
rviz_config_arg,
configuration_directory_arg,
configuration_basenames_arg,
urdf_filenames_arg,
# Nodes
set_remap1,
set_remap2,
offline_node_launch,
])
@@ -0,0 +1,76 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 os import getenv
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
from launch.actions import Shutdown
def generate_launch_description():
## ***** Launch arguments *****
bag_filenames_arg = DeclareLaunchArgument('bag_filename')
no_rviz_arg = DeclareLaunchArgument('no_rviz', default_value = 'False')
keep_running_arg = DeclareLaunchArgument('keep_running', default_value = 'False')
## ***** Nodes *****
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_2d.rviz'],
parameters = [{'use_sim_time': True}],
condition = UnlessCondition(LaunchConfiguration('no_rviz'))
)
cartographer_offline_node_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_offline_node',
parameters = [{'use_sim_time': True}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basenames', 'mir-100-mapping.lua',
'-urdf_filenames', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/urdf/mir-100.urdf',
'-use_bag_transforms', 'false',
'-keep_running', LaunchConfiguration('keep_running'),
'-bag_filenames', LaunchConfiguration('bag_filename')],
remappings = [
('f_scan', 'scan_1'),
( 'b_scan', 'scan_2'),
( 'imu_data','imu'),
('odom','ignore_odom'),
('odom_enc','odom')],
output = 'screen'
)
return LaunchDescription([
# Launch arguments
bag_filenames_arg,
no_rviz_arg,
keep_running_arg,
# Nodes
rviz_node,
cartographer_offline_node_node,
])
@@ -0,0 +1,81 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
from launch.actions import Shutdown
def generate_launch_description():
## ***** Launch arguments *****
bag_filenames_arg = DeclareLaunchArgument('bag_filenames')
no_rviz_arg = DeclareLaunchArgument('no_rviz')
rviz_config_arg = DeclareLaunchArgument('rviz_config')
configuration_directory_arg = DeclareLaunchArgument('configuration_directory')
configuration_basenames_arg = DeclareLaunchArgument('configuration_basenames')
urdf_filenames_arg = DeclareLaunchArgument('urdf_filenames')
## ***** Nodes *****
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', LaunchConfiguration('rviz_config')],
parameters = [{'use_sim_time': True}],
condition = UnlessCondition(LaunchConfiguration('no_rviz'))
)
cartographer_occupancy_grid_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_occupancy_grid_node',
parameters = [
{'use_sim_time': True},
{'resolution': 0.05}],
)
cartographer_offline_node_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_offline_node',
parameters = [{'use_sim_time': True}],
arguments = [
'-configuration_directory', LaunchConfiguration('configuration_directory'),
'-configuration_basenames', LaunchConfiguration('configuration_basenames'),
'-urdf_filenames', LaunchConfiguration('urdf_filenames'),
'-bag_filenames', LaunchConfiguration('bag_filenames')],
output = 'screen'
)
return LaunchDescription([
# Launch arguments
bag_filenames_arg,
no_rviz_arg,
rviz_config_arg,
configuration_directory_arg,
configuration_basenames_arg,
urdf_filenames_arg,
# Nodes
rviz_node,
cartographer_occupancy_grid_node,
cartographer_offline_node_node,
])
@@ -0,0 +1,58 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
import os
def generate_launch_description():
## ***** Launch arguments *****
use_sim_time_arg = DeclareLaunchArgument('use_sim_time', default_value = 'False')
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_node',
parameters = [{'use_sim_time': LaunchConfiguration('use_sim_time')}],
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'taurob_tracker.lua'],
remappings = [
('scan', '/spin_laser/scan'),
('imu', '/imu/data')],
output = 'screen'
)
cartographer_occupancy_grid_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_occupancy_grid_node',
parameters = [
{'use_sim_time': LaunchConfiguration('use_sim_time')},
{'resolution': 0.05}],
)
return LaunchDescription([
use_sim_time_arg,
# Nodes
cartographer_node,
cartographer_occupancy_grid_node,
])
@@ -0,0 +1,57 @@
"""
Copyright 2018 The Cartographer Authors
Copyright 2022 Wyca Robotics (for the ros2 conversion)
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 launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, ExecuteProcess
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node, SetRemap
from launch_ros.substitutions import FindPackageShare
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.actions import Shutdown
def generate_launch_description():
## ***** Launch arguments *****
pbstream_filename_arg = DeclareLaunchArgument('pbstream_filename')
## ***** Nodes *****
rviz_node = Node(
package = 'rviz2',
executable = 'rviz2',
on_exit = Shutdown(),
arguments = ['-d', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files/demo_2d.rviz'],
)
cartographer_node = Node(
package = 'cartographer_ros',
executable = 'cartographer_node',
arguments = [
'-configuration_directory', FindPackageShare('cartographer_ros').find('cartographer_ros') + '/configuration_files',
'-configuration_basename', 'visualize_pbstream.lua',
'-load_state_filename', LaunchConfiguration('pbstream_filename'),
'-load_frozen_state=false',
'-start_trajectory_with_default_topics=false'],
output = 'screen'
)
return LaunchDescription([
# Launch arguments
pbstream_filename_arg,
# Nodes
rviz_node,
cartographer_node
])
@@ -0,0 +1,108 @@
<?xml version="1.0"?>
<!--
Copyright 2016 The Cartographer Authors
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.
-->
<package format="3">
<name>cartographer_ros</name>
<!--
As of 2022-03-31, the versioning for cartographer_ros is in a complicated situation.
Upstream https://github.com/cartographer-project/cartographer_ros seems to be moribund,
with no commits for close to a year. The master branch there is only for ROS 1, and
that branch has not had a released tag since 1.0.0 in 2018.
In the meantime, we've done a port to ROS 2 in https://github.com/ros2/cartographer_ros
that targets upstream cartographer 2.0.0.
Since we have no response from upstream in a long time, we are going to go ahead and
assume that the 1.x series of tags from upstream cartographer_ros will always be used
to target ROS 1. Further we are going to assume that the 2.x series of tags
from upstream cartographer_ros (none of which exist yet) will be used to target ROS 2.
If upstream comes alive and chooses a different versioning scheme, we can adjust later
as necessary. The outcome of all of this is that we are assuming a starting "upstream"
release of 2.0.0, which then plays into the rest of the explanation below.
We add 900 to the patch part of the version and then multiply it by 10,
i.e. our version = `(upstream_patch_version + 900) * 10`,
so we can have intermediate releases as well as release any future official 2.0.x versions.
This is basically packing the patch part of the version and a fourth version part together
into the third part of the version.
The use of `900` instead of something else like `100` is arbitrary, but it might
help people recognize that this is a "special" version number.
It is needed however, because we cannot have a leading `0` in our patch version.
Consider these possible future versions as an example:
2.0.9000 -> current state of this repository, 2.0.0 + some commits from us
2.0.9010 -> upstream 2.0.1
2.0.9011 -> upstream 2.0.1 + additional commits from upstream or us
2.0.9012 -> upstream 2.0.1 + additional commits from 2.0.1011 + more new commits
2.0.9020 -> upstream 2.0.2
and so on...
-->
<version>2.0.9003</version>
<description>
Cartographer is a system that provides real-time simultaneous localization
and mapping (SLAM) in 2D and 3D across multiple platforms and sensor
configurations. This package provides Cartographer's ROS integration.
</description>
<maintainer email="clalancette@openrobotics.org">Chris Lalancette</maintainer>
<license>Apache 2.0</license>
<url>https://github.com/cartographer-project/cartographer_ros</url>
<author email="google-cartographer@googlegroups.com">
The Cartographer Authors
</author>
<buildtool_depend>ament_cmake</buildtool_depend>
<build_depend>google-mock</build_depend>
<build_depend>python3-sphinx</build_depend>
<build_depend>ros_environment</build_depend>
<depend>builtin_interfaces</depend>
<depend>cartographer</depend>
<depend>cartographer_ros_msgs</depend>
<depend>eigen</depend>
<depend>geometry_msgs</depend>
<depend>libabsl-dev</depend>
<depend>libcairo2-dev</depend>
<depend>libgflags-dev</depend>
<depend>libgoogle-glog-dev</depend>
<depend>libpcl-all-dev</depend>
<depend>nav_msgs</depend>
<depend>pcl_conversions</depend>
<depend>rclcpp</depend>
<depend>rosbag2_cpp</depend>
<depend>rosbag2_storage</depend>
<depend>sensor_msgs</depend>
<depend>std_msgs</depend>
<depend>tf2</depend>
<depend>tf2_eigen</depend>
<depend>tf2_msgs</depend>
<depend>tf2_ros</depend>
<depend>urdf</depend>
<depend>visualization_msgs</depend>
<exec_depend>launch</exec_depend>
<exec_depend>robot_state_publisher</exec_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
@@ -0,0 +1,18 @@
#!/bin/bash
# Copyright 2018 The Cartographer Authors
#
# 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.
set -xe
cartographer_grpc_server $@
@@ -0,0 +1,74 @@
#!/bin/bash
# Copyright 2018 The Cartographer Authors
#
# 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.
set -o errexit
set -o verbose
MAPFILE="$1"
BAGFILE="$2"
if [ "$#" -ne 2 ]; then
echo "\n\nUsage: $0 <frozen_map_file> <bag_file>\n"
exit 1;
fi
LAUNCHSCRIPT='
<launch>
<node name="cartographer_offline_node" pkg="cartographer_ros"
required="true"
type="cartographer_offline_node" args="
-configuration_directory $(find cartographer_ros)/configuration_files
-configuration_basenames backpack_2d.lua
-urdf_filenames $(find cartographer_ros)/urdf/backpack_2d.urdf
-load_state_filename '$MAPFILE'
-bag_filenames '$BAGFILE'
">
<remap from="echoes" to="horizontal_laser_2d" />
</node>
</launch>'
echo $LAUNCHSCRIPT | roslaunch -
LAUNCHSCRIPT='
<launch>
<param name="/use_sim_time" value="true" />
<param name="robot_description"
textfile="$(find cartographer_ros)/urdf/backpack_2d.urdf" />
<node name="robot_state_publisher" pkg="robot_state_publisher"
type="robot_state_publisher" />
<node name="cartographer_node" pkg="cartographer_ros"
required="true"
type="cartographer_node" args="
-configuration_directory $(find cartographer_ros)/configuration_files
-configuration_basename backpack_2d_localization_evaluation.lua
-load_state_filename '$MAPFILE'
-load_frozen_state true
">
<remap from="echoes" to="horizontal_laser_2d" />
</node>
<node name="playbag" pkg="rosbag" type="play"
required="true"
args="--clock '$BAGFILE'" />
<node name="recordtf" pkg="rosbag" type="record"
args="
tf
-O '$BAGFILE'.tf-result
" />
</launch>
'
echo $LAUNCHSCRIPT | roslaunch -
rosrun cartographer_ros cartographer_dev_trajectory_comparison \
-bag_filename $BAGFILE.tf-result.bag \
-pbstream_filename $BAGFILE.pbstream
@@ -0,0 +1,191 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2018 Magazino GmbH
# The Cartographer Authors
#
# 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.
import itertools
import random
import rospy
from tf import transformations
from cartographer_ros_msgs.msg import LandmarkEntry, LandmarkList
DESC = '''
Samples a number of random landmarks at a specified rate.
Can be used to test the timing of landmark input or the effect of erroneous
landmarks with duplicate IDs (if --allow_duplicate_ids is set).
For example:
./publish_fake_random_landmarks.py \\
--publish_period 0.1 \\
--id_vocabulary A B C \\
--id_length 5 \\
--sample_period 1.0
will publish empty landmark lists at 10Hz and random landmarks every second.
IDs are also sampled, using the cartesian product of the provided "vocabulary".
In the above example, a sampled ID could be e.g. "AACBC" (length=5).
'''
TOPIC = "landmark"
class LandmarkSamplerOptions(object):
def __init__(self, *args, **kwargs):
self.allow_duplicate_ids = False
self.id_vocabulary = {}
self.id_length = 0
self.max_distance = 0.
self.num_landmarks = 0
self.rotation_weight = 0.
self.translation_weight = 0.
for name, arg in kwargs.items():
setattr(self, name, arg)
class LandmarkIdSampler(object):
def __init__(self, id_vocabulary, id_length):
# Precompute all combinations of the symbols in the vocabulary.
# WARNING: can be huge, check before potentially blocking the system.
if len(id_vocabulary)**id_length > 1e6:
raise ValueError("ID sampling space is too large")
self.sampling_space = list(
itertools.product(*(id_vocabulary for i in range(id_length))))
def sample_id(self):
# Draw a random combination of symbols and stringify it.
random_index = random.randint(0, len(self.sampling_space) - 1)
sampled_id = "".join(self.sampling_space[random_index])
return sampled_id
class LandmarkSampler(object):
def __init__(self, options):
if not isinstance(options, LandmarkSamplerOptions):
raise TypeError("expected LandmarkSamplerOptions")
self.options = options
rospy.loginfo("Initializing landmark ID sampler...")
self.landmark_id_sampler = LandmarkIdSampler(options.id_vocabulary,
options.id_length)
self._sampled_ids = []
def random_landmark(self):
landmark = LandmarkEntry()
landmark.translation_weight = self.options.translation_weight
landmark.rotation_weight = self.options.rotation_weight
landmark.id = self.landmark_id_sampler.sample_id()
if landmark.id in self._sampled_ids:
if not self.options.allow_duplicate_ids:
rospy.logwarn("Ignoring duplicate ID: {}".format(landmark.id))
return None
else:
rospy.logwarn("Duplicate ID: {}".format(landmark.id))
self._sampled_ids.append(landmark.id)
vector = transformations.random_vector(3) * self.options.max_distance
landmark.tracking_from_landmark_transform.position.x = vector[0]
landmark.tracking_from_landmark_transform.position.y = vector[1]
landmark.tracking_from_landmark_transform.position.z = vector[2]
quaternion = transformations.random_quaternion()
landmark.tracking_from_landmark_transform.orientation.x = quaternion[0]
landmark.tracking_from_landmark_transform.orientation.y = quaternion[1]
landmark.tracking_from_landmark_transform.orientation.z = quaternion[2]
landmark.tracking_from_landmark_transform.orientation.w = quaternion[3]
return landmark
def random_landmark_list(self):
landmark_list = LandmarkList()
landmark_list.header.stamp = rospy.Time.now()
for _ in range(self.options.num_landmarks):
random_landmark = self.random_landmark()
if random_landmark is not None:
landmark_list.landmarks.append(random_landmark)
return landmark_list
class SampledLandmarkPublisher(object):
def __init__(self, publish_period, sample_period, landmark_sampler_options):
self.landmark_sampler = LandmarkSampler(landmark_sampler_options)
rospy.loginfo("Publishing landmarks to topic: {}".format(TOPIC))
self.publisher = rospy.Publisher(TOPIC, LandmarkList, queue_size=1)
self.publish_timer = rospy.Timer(
rospy.Duration(publish_period), self.publish_empty_landmark_list)
self.sample_timer = rospy.Timer(
rospy.Duration(sample_period), self.publish_random_landmark_list)
def publish_random_landmark_list(self, timer_event):
self.publisher.publish(self.landmark_sampler.random_landmark_list())
def publish_empty_landmark_list(self, timer_event):
landmark_list = LandmarkList(rospy.Header(stamp=rospy.Time.now()), [])
self.publisher.publish(landmark_list)
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(
description=DESC, formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("--translation_weight", type=float, default=1e5)
parser.add_argument("--rotation_weight", type=float, default=1e5)
parser.add_argument(
"--publish_period",
type=float,
default=0.1,
help="Baseline period for publishing empty landmark lists.")
parser.add_argument(
"--sample_period",
type=float,
default=5.,
help="Period at which randomly sampled landmarks are published.")
parser.add_argument(
"--num_landmarks",
type=int,
default=5,
help="The number of random landmarks published simultaneously.")
parser.add_argument(
"--max_distance",
type=float,
default=1.0,
help="Maximum distance of a random landmark to the tracking frame.")
parser.add_argument(
"--id_vocabulary",
nargs='+',
default={"a", "b", "c", "1", "2", "3"},
help="Set of symbols that can appear in random landmark IDs.")
parser.add_argument(
"--id_length",
type=int,
default=5,
help="The length of the random landmark IDs (number of symbols).")
parser.add_argument(
"--allow_duplicate_ids",
action="store_true",
help="Publish landmarks with IDs that have already been published.")
args, unknown = parser.parse_known_args(rospy.myargv()[1:])
rospy.init_node("landmark_sampler")
landmark_sampler_options = LandmarkSamplerOptions(**args.__dict__)
sampler = SampledLandmarkPublisher(args.publish_period, args.sample_period,
landmark_sampler_options)
rospy.spin()
@@ -0,0 +1,53 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2016 The Cartographer Authors
#
# 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.
"""A simple tool to remove leading slashes from frame names."""
import argparse
import os
import rosbag
def ParseArgs():
argument_parser = argparse.ArgumentParser(
description="Removes leading slashes from frame names.")
argument_parser.add_argument("input", type=str, help="Input bag")
return argument_parser.parse_args()
def RewriteMsg(msg):
if hasattr(msg, "header"):
if msg.header.frame_id.startswith("/"):
msg.header.frame_id = msg.header.frame_id[1:]
if hasattr(msg, "child_frame_id"):
if msg.child_frame_id.startswith("/"):
msg.child_frame_id = msg.child_frame_id[1:]
if hasattr(msg, "transforms"):
for transform_msg in msg.transforms:
RewriteMsg(transform_msg)
def Main():
options = ParseArgs()
with rosbag.Bag(os.path.splitext(options.input)[0] + ".filtered.bag",
"w") as outbag:
for topic, msg, t in rosbag.Bag(options.input).read_messages():
RewriteMsg(msg)
outbag.write(topic, msg, msg.header.stamp if msg._has_header else t)
if __name__ == "__main__":
Main()
@@ -0,0 +1,40 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2016 The Cartographer Authors
#
# 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.
import rospy
from tf.msg import tfMessage
def main():
rospy.init_node('tf_remove_frames')
publisher = rospy.Publisher('/tf_out', tfMessage, queue_size=1)
remove_frames = rospy.get_param('~remove_frames', [])
def callback(msg):
msg.transforms = [
t for t in msg.transforms
if t.header.frame_id.lstrip('/') not in remove_frames and
t.child_frame_id.lstrip('/') not in remove_frames
]
publisher.publish(msg)
rospy.Subscriber('/tf_in', tfMessage, callback)
rospy.spin()
if __name__ == '__main__':
main()
@@ -0,0 +1,2 @@
BasedOnStyle: Google
DerivePointerAlignment: false
@@ -0,0 +1,310 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#include "cartographer_ros/assets_writer.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include "absl/memory/memory.h"
#include "cartographer/common/configuration_file_resolver.h"
#include "cartographer/common/math.h"
#include "cartographer/io/file_writer.h"
#include "cartographer/io/points_processor.h"
#include "cartographer/io/points_processor_pipeline_builder.h"
#include "cartographer/io/proto_stream.h"
#include "cartographer/io/proto_stream_deserializer.h"
#include "cartographer/mapping/proto/pose_graph.pb.h"
#include "cartographer/mapping/proto/trajectory_builder_options.pb.h"
#include "cartographer/sensor/point_cloud.h"
#include "cartographer/sensor/range_data.h"
#include "cartographer/transform/transform_interpolation_buffer.h"
#include "cartographer_ros/msg_conversion.h"
#include "cartographer_ros/ros_map_writing_points_processor.h"
#include "cartographer_ros/time_conversion.h"
#include "cartographer_ros/urdf_reader.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "builtin_interfaces/msg/time.hpp"
#include <rosbag2_cpp/reader.hpp>
#include <rosbag2_cpp/readers/sequential_reader.hpp>
#include "tf2_eigen/tf2_eigen.hpp"
#include "tf2_msgs/msg/tf_message.hpp"
#include "tf2_ros/buffer.h"
#ifdef USE_URDF_H_FILES
#include "urdf/model.h"
#else
#include "urdf/model.hpp"
#endif
namespace cartographer_ros {
namespace {
constexpr char kTfStaticTopic[] = "/tf_static";
namespace carto = ::cartographer;
std::unique_ptr<carto::io::PointsProcessorPipelineBuilder>
CreatePipelineBuilder(
const std::vector<carto::mapping::proto::Trajectory>& trajectories,
const std::string file_prefix) {
const auto file_writer_factory =
AssetsWriter::CreateFileWriterFactory(file_prefix);
auto builder = absl::make_unique<carto::io::PointsProcessorPipelineBuilder>();
carto::io::RegisterBuiltInPointsProcessors(trajectories, file_writer_factory,
builder.get());
builder->Register(RosMapWritingPointsProcessor::kConfigurationFileActionName,
[file_writer_factory](
carto::common::LuaParameterDictionary* const dictionary,
carto::io::PointsProcessor* const next)
-> std::unique_ptr<carto::io::PointsProcessor> {
return RosMapWritingPointsProcessor::FromDictionary(
file_writer_factory, dictionary, next);
});
return builder;
}
std::unique_ptr<carto::common::LuaParameterDictionary> LoadLuaDictionary(
const std::string& configuration_directory,
const std::string& configuration_basename) {
auto file_resolver =
absl::make_unique<carto::common::ConfigurationFileResolver>(
std::vector<std::string>{configuration_directory});
const std::string code =
file_resolver->GetFileContentOrDie(configuration_basename);
auto lua_parameter_dictionary =
absl::make_unique<carto::common::LuaParameterDictionary>(
code, std::move(file_resolver));
return lua_parameter_dictionary;
}
template <typename T>
std::unique_ptr<carto::io::PointsBatch> HandleMessage(
const T& message, const std::string& tracking_frame,
const std::shared_ptr<tf2_ros::Buffer> tf_buffer,
const carto::transform::TransformInterpolationBuffer&
transform_interpolation_buffer) {
const carto::common::Time start_time = FromRos(message->header.stamp);
auto points_batch = absl::make_unique<carto::io::PointsBatch>();
points_batch->start_time = start_time;
points_batch->frame_id = message->header.frame_id;
carto::sensor::PointCloudWithIntensities point_cloud;
carto::common::Time point_cloud_time;
std::tie(point_cloud, point_cloud_time) =
ToPointCloudWithIntensities(*message);
CHECK_EQ(point_cloud.intensities.size(), point_cloud.points.size());
for (size_t i = 0; i < point_cloud.points.size(); ++i) {
const carto::common::Time time =
point_cloud_time +
carto::common::FromSeconds(point_cloud.points[i].time);
if (!transform_interpolation_buffer.Has(time)) {
continue;
}
const carto::transform::Rigid3d tracking_to_map =
transform_interpolation_buffer.Lookup(time);
const carto::transform::Rigid3d sensor_to_tracking =
ToRigid3d(tf_buffer->lookupTransform(
tracking_frame, message->header.frame_id, ToRos(time)));
const carto::transform::Rigid3f sensor_to_map =
(tracking_to_map * sensor_to_tracking).cast<float>();
points_batch->points.push_back(
sensor_to_map *
carto::sensor::ToRangefinderPoint(point_cloud.points[i]));
points_batch->intensities.push_back(point_cloud.intensities[i]);
// We use the last transform for the origin, which is approximately correct.
points_batch->origin = sensor_to_map * Eigen::Vector3f::Zero();
}
if (points_batch->points.empty()) {
return nullptr;
}
return points_batch;
}
} // namespace
AssetsWriter::AssetsWriter(const std::string& pose_graph_filename,
const std::vector<std::string>& bag_filenames,
const std::string& output_file_prefix)
: bag_filenames_(bag_filenames),
pose_graph_(
carto::io::DeserializePoseGraphFromFile(pose_graph_filename)) {
CHECK_EQ(pose_graph_.trajectory_size(), bag_filenames_.size())
<< "Pose graphs contains " << pose_graph_.trajectory_size()
<< " trajectories while " << bag_filenames_.size()
<< " bags were provided. This tool requires one bag for each "
"trajectory in the same order as the correponding trajectories in the "
"pose graph proto.";
// This vector must outlive the pipeline.
all_trajectories_ = std::vector<::cartographer::mapping::proto::Trajectory>(
pose_graph_.trajectory().begin(), pose_graph_.trajectory().end());
const std::string file_prefix = !output_file_prefix.empty()
? output_file_prefix
: bag_filenames_.front() + "_";
point_pipeline_builder_ =
CreatePipelineBuilder(all_trajectories_, file_prefix);
}
void AssetsWriter::RegisterPointsProcessor(
const std::string& name,
cartographer::io::PointsProcessorPipelineBuilder::FactoryFunction factory) {
point_pipeline_builder_->Register(name, factory);
}
void AssetsWriter::Run(const std::string& configuration_directory,
const std::string& configuration_basename,
const std::string& urdf_filename,
const bool use_bag_transforms) {
const auto lua_parameter_dictionary =
LoadLuaDictionary(configuration_directory, configuration_basename);
std::vector<std::unique_ptr<carto::io::PointsProcessor>> pipeline =
point_pipeline_builder_->CreatePipeline(
lua_parameter_dictionary->GetDictionary("pipeline").get());
const std::string tracking_frame =
lua_parameter_dictionary->GetString("tracking_frame");
rclcpp::Clock::SharedPtr clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
do {
for (size_t trajectory_id = 0; trajectory_id < bag_filenames_.size();
++trajectory_id) {
const carto::mapping::proto::Trajectory& trajectory_proto =
pose_graph_.trajectory(trajectory_id);
const std::string& bag_filename = bag_filenames_[trajectory_id];
LOG(INFO) << "Processing " << bag_filename << "...";
if (trajectory_proto.node_size() == 0) {
continue;
}
std::shared_ptr<tf2_ros::Buffer> tf_buffer = std::make_shared<tf2_ros::Buffer>(clock);
tf_buffer->setUsingDedicatedThread(true);
if (!urdf_filename.empty()) {
ReadStaticTransformsFromUrdf(urdf_filename, tf_buffer);
}
const carto::transform::TransformInterpolationBuffer
transform_interpolation_buffer(trajectory_proto);
rosbag2_cpp::Reader bag_reader;
bag_reader.open(bag_filename);
rosbag2_storage::BagMetadata bag_metadata = bag_reader.get_metadata();
const rclcpp::Time begin_time(bag_metadata.starting_time.time_since_epoch().count());
// We need to keep 'tf_buffer' small because it becomes very inefficient
// otherwise. We make sure that tf_messages are published before any data
// messages, so that tf lookups always work.
std::deque<rosbag2_storage::SerializedBagMessage> delayed_messages;
// We publish tf messages one second earlier than other messages. Under
// the assumption of higher frequency tf this should ensure that tf can
// always interpolate.
const rclcpp::Duration kDelay(1.0,0.0);
auto serializer = rclcpp::Serialization<tf2_msgs::msg::TFMessage>();
auto laser_scan_serializer = rclcpp::Serialization<sensor_msgs::msg::LaserScan>();
auto multi_echo_laser_scan_serializer = rclcpp::Serialization<sensor_msgs::msg::MultiEchoLaserScan>();
auto pcl2_serializer = rclcpp::Serialization<sensor_msgs::msg::PointCloud2>();
while (bag_reader.has_next()) {
auto message = bag_reader.read_next();
if (use_bag_transforms && (message->topic_name == kTfStaticTopic || message->topic_name == "/tf")) {
tf2_msgs::msg::TFMessage tf_message;
rclcpp::SerializedMessage serialized_msg(*message->serialized_data);
serializer.deserialize_message(&serialized_msg, &tf_message);
for (const auto& transform : tf_message.transforms) {
try {
tf_buffer->setTransform(transform, "unused_authority",
message->topic_name == kTfStaticTopic);
} catch (const tf2::TransformException& ex) {
LOG(WARNING) << ex.what();
}
}
}
#ifdef PRE_JAZZY_SERIALIZED_BAG_MSG_FIELD_NAME
while (!delayed_messages.empty() && delayed_messages.front().time_stamp <
message->time_stamp - kDelay.nanoseconds()) {
#else
while (!delayed_messages.empty() && delayed_messages.front().recv_timestamp <
message->recv_timestamp - kDelay.nanoseconds()) {
#endif
const auto delayed_message =
delayed_messages.front();
std::unique_ptr<carto::io::PointsBatch> points_batch;
for (auto topic_info : bag_metadata.topics_with_message_count) {
if (topic_info.topic_metadata.name == delayed_message.topic_name){
rclcpp::SerializedMessage serialized_msg(*delayed_message.serialized_data);
if (topic_info.topic_metadata.type == "sensor_msgs/msg/LaserScan") {
sensor_msgs::msg::LaserScan::SharedPtr laser_scan_msg =
std::make_shared<sensor_msgs::msg::LaserScan>();
laser_scan_serializer.deserialize_message(&serialized_msg, laser_scan_msg.get());
points_batch = HandleMessage(
laser_scan_msg,
tracking_frame, tf_buffer, transform_interpolation_buffer);
} else if (topic_info.topic_metadata.type == "sensor_msgs/msg/MultiEchoLaserScan") {
sensor_msgs::msg::MultiEchoLaserScan::SharedPtr multi_echo_laser_scan_msg =
std::make_shared<sensor_msgs::msg::MultiEchoLaserScan>();
multi_echo_laser_scan_serializer.deserialize_message(&serialized_msg, multi_echo_laser_scan_msg.get());
points_batch = HandleMessage(
multi_echo_laser_scan_msg,
tracking_frame, tf_buffer, transform_interpolation_buffer);
}
else if (topic_info.topic_metadata.type == "sensor_msgs/msg/PointCloud2") {
sensor_msgs::msg::PointCloud2::SharedPtr pcl2_scan_msg =
std::make_shared<sensor_msgs::msg::PointCloud2>();
pcl2_serializer.deserialize_message(&serialized_msg, pcl2_scan_msg.get());
points_batch = HandleMessage(
pcl2_scan_msg,
tracking_frame, tf_buffer, transform_interpolation_buffer);
}
if (points_batch != nullptr) {
points_batch->trajectory_id = trajectory_id;
pipeline.back()->Process(std::move(points_batch));
}
delayed_messages.pop_front();
break;
}
}
}
delayed_messages.push_back(*message);
#ifdef PRE_JAZZY_SERIALIZED_BAG_MSG_FIELD_NAME
LOG_EVERY_N(INFO, 10000)
<< "Processed " << (message->time_stamp - begin_time.nanoseconds())/1e9
<< " of " << bag_metadata.duration.count()/1e9 << " bag time seconds...";
#else
LOG_EVERY_N(INFO, 10000)
<< "Processed " << (message->recv_timestamp - begin_time.nanoseconds())/1e9
<< " of " << bag_metadata.duration.count()/1e9 << " bag time seconds...";
#endif
}
}
} while (pipeline.back()->Flush() ==
carto::io::PointsProcessor::FlushResult::kRestartStream);
}
::cartographer::io::FileWriterFactory AssetsWriter::CreateFileWriterFactory(
const std::string& file_path) {
const auto file_writer_factory = [file_path](const std::string& filename) {
return absl::make_unique<carto::io::StreamFileWriter>(file_path + filename);
};
return file_writer_factory;
}
} // namespace cartographer_ros
@@ -0,0 +1,78 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#include "cartographer_ros/assets_writer.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "rclcpp/rclcpp.hpp"
#include <regex>
#include <string>
DEFINE_string(configuration_directory, "",
"First directory in which configuration files are searched, "
"second is always the Cartographer installation to allow "
"including files from there.");
DEFINE_string(configuration_basename, "",
"Basename, i.e. not containing any directory prefix, of the "
"configuration file.");
DEFINE_string(
urdf_filename, "",
"URDF file that contains static links for your sensor configuration.");
DEFINE_string(bag_filenames, "",
"Bags to process, must be in the same order as the trajectories "
"in 'pose_graph_filename'.");
DEFINE_string(pose_graph_filename, "",
"Proto stream file containing the pose graph.");
DEFINE_bool(use_bag_transforms, true,
"Whether to read and use the transforms from the bag.");
DEFINE_string(output_file_prefix, "",
"Will be prefixed to all output file names and can be used to "
"define the output directory. If empty, the first bag filename "
"will be used.");
int main(int argc, char** argv) {
// Init rclcpp first because gflags reorders command line flags in argv
rclcpp::init(argc, argv);
FLAGS_alsologtostderr = true;
google::AllowCommandLineReparsing();
google::InitGoogleLogging(argv[0]);
google::ParseCommandLineFlags(&argc, &argv, false);
CHECK(!FLAGS_configuration_directory.empty())
<< "-configuration_directory is missing.";
CHECK(!FLAGS_configuration_basename.empty())
<< "-configuration_basename is missing.";
CHECK(!FLAGS_bag_filenames.empty()) << "-bag_filenames is missing.";
CHECK(!FLAGS_pose_graph_filename.empty())
<< "-pose_graph_filename is missing.";
std::regex regex(",");
std::vector<std::string> bag_filenames(
std::sregex_token_iterator(
FLAGS_bag_filenames.begin(), FLAGS_bag_filenames.end(), regex, -1),
std::sregex_token_iterator()
);
::cartographer_ros::AssetsWriter asset_writer(
FLAGS_pose_graph_filename,
bag_filenames,
FLAGS_output_file_prefix);
asset_writer.Run(FLAGS_configuration_directory, FLAGS_configuration_basename,
FLAGS_urdf_filename, FLAGS_use_bag_transforms);
rclcpp::shutdown();
}
@@ -0,0 +1,117 @@
/*
* Copyright 2017 The Cartographer Authors
*
* 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.
*/
#include "absl/memory/memory.h"
#include "cartographer/cloud/client/map_builder_stub.h"
#include "cartographer_ros/node.h"
#include "cartographer_ros/node_options.h"
#include "cartographer_ros/ros_log_sink.h"
#include "gflags/gflags.h"
#include "tf2_ros/transform_listener.h"
DEFINE_bool(collect_metrics, false,
"Activates the collection of runtime metrics. If activated, the "
"metrics can be accessed via a ROS service.");
DEFINE_string(configuration_directory, "",
"First directory in which configuration files are searched, "
"second is always the Cartographer installation to allow "
"including files from there.");
DEFINE_string(configuration_basename, "",
"Basename, i.e. not containing any directory prefix, of the "
"configuration file.");
DEFINE_string(server_address, "localhost:50051",
"gRPC server address to stream the sensor data to.");
DEFINE_bool(
start_trajectory_with_default_topics, true,
"Enable to immediately start the first trajectory with default topics.");
DEFINE_string(
save_map_filename, "",
"If non-empty, serialize state and write it to disk before shutting down.");
DEFINE_string(load_state_filename, "",
"If non-empty, filename of a .pbstream file "
"to load, containing a saved SLAM state. "
"Unless --upload_load_state_file is set, the filepath refers "
"to the gRPC server's file system.");
DEFINE_bool(load_frozen_state, true,
"Load the saved state as frozen (non-optimized) trajectories.");
DEFINE_bool(upload_load_state_file, false,
"Upload the .pbstream file from a local path to the (remote) gRPC "
"server instead of loading it from the server file system.");
DEFINE_string(client_id, "",
"Cartographer client ID to use when connecting to the server.");
namespace cartographer_ros {
namespace {
void Run() {
constexpr double kTfBufferCacheTimeInSeconds = 10.;
tf2_ros::Buffer tf_buffer{::ros::Duration(kTfBufferCacheTimeInSeconds)};
tf2_ros::TransformListener tf(tf_buffer);
NodeOptions node_options;
TrajectoryOptions trajectory_options;
std::tie(node_options, trajectory_options) =
LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);
auto map_builder = absl::make_unique<::cartographer::cloud::MapBuilderStub>(
FLAGS_server_address, FLAGS_client_id);
if (!FLAGS_load_state_filename.empty() && !FLAGS_upload_load_state_file) {
map_builder->LoadStateFromFile(FLAGS_load_state_filename,
FLAGS_load_frozen_state);
}
Node node(node_options, std::move(map_builder), &tf_buffer,
FLAGS_collect_metrics);
if (!FLAGS_load_state_filename.empty() && FLAGS_upload_load_state_file) {
node.LoadState(FLAGS_load_state_filename, FLAGS_load_frozen_state);
}
if (FLAGS_start_trajectory_with_default_topics) {
node.StartTrajectoryWithDefaultTopics(trajectory_options);
}
::ros::spin();
node.FinishAllTrajectories();
node.RunFinalOptimization();
if (!FLAGS_save_map_filename.empty()) {
node.SerializeState(FLAGS_save_map_filename,
false /* include_unfinished_submaps */);
}
}
} // namespace
} // namespace cartographer_ros
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
google::ParseCommandLineFlags(&argc, &argv, true);
CHECK(!FLAGS_configuration_directory.empty())
<< "-configuration_directory is missing.";
CHECK(!FLAGS_configuration_basename.empty())
<< "-configuration_basename is missing.";
CHECK(!FLAGS_client_id.empty()) << "-client_id is missing.";
::ros::init(argc, argv, "cartographer_grpc_node");
::ros::start();
cartographer_ros::ScopedRosLogSink ros_log_sink;
cartographer_ros::Run();
::ros::shutdown();
}
@@ -0,0 +1,49 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#include "cartographer/cloud/client/map_builder_stub.h"
#include "cartographer_ros/offline_node.h"
#include "cartographer_ros/ros_log_sink.h"
#include "gflags/gflags.h"
#include "ros/ros.h"
DEFINE_string(server_address, "localhost:50051",
"gRPC server address to "
"stream the sensor data to.");
DEFINE_string(client_id, "",
"Cartographer client ID to use when connecting to the server.");
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
google::ParseCommandLineFlags(&argc, &argv, true);
CHECK(!FLAGS_client_id.empty()) << "-client_id is missing.";
::ros::init(argc, argv, "cartographer_grpc_offline_node");
::ros::start();
cartographer_ros::ScopedRosLogSink ros_log_sink;
const cartographer_ros::MapBuilderFactory map_builder_factory =
[](const ::cartographer::mapping::proto::MapBuilderOptions&) {
return absl::make_unique< ::cartographer::cloud::MapBuilderStub>(
FLAGS_server_address, FLAGS_client_id);
};
cartographer_ros::RunOfflineNode(map_builder_factory);
::ros::shutdown();
}
@@ -0,0 +1,44 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#include <string>
#include <vector>
#include "cartographer_ros/node_options.h"
#include "gtest/gtest.h"
#include "ros/package.h"
namespace cartographer_ros {
namespace {
class ConfigurationFilesTest : public ::testing::TestWithParam<const char*> {};
TEST_P(ConfigurationFilesTest, ValidateNodeOptions) {
EXPECT_NO_FATAL_FAILURE({
LoadOptions(
::ros::package::getPath("cartographer_ros") + "/configuration_files",
GetParam());
});
}
INSTANTIATE_TEST_CASE_P(
ValidateAllNodeOptions, ConfigurationFilesTest,
::testing::Values("backpack_2d.lua", "backpack_2d_localization.lua",
"backpack_3d.lua", "backpack_3d_localization.lua",
"pr2.lua", "revo_lds.lua", "taurob_tracker.lua"));
} // namespace
} // namespace cartographer_ros
@@ -0,0 +1,102 @@
/*
* Copyright 2019 The Cartographer Authors
*
* 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.
*/
#include <iostream>
#include <string>
#include <vector>
#include "absl/strings/str_cat.h"
#include "cartographer/transform/transform.h"
#include "cartographer_ros/msg_conversion.h"
#include "cartographer_ros/time_conversion.h"
#include "geometry_msgs/TransformStamped.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "rosbag/bag.h"
#include "tf2_msgs/TFMessage.h"
DEFINE_string(input, "", "pbstream file to process");
DEFINE_string(output, "", "Bag file to write to.");
DEFINE_string(parent_frame, "map", "Frame id to use as parent frame.");
namespace cartographer_ros {
namespace {
geometry_msgs::msg::TransformStamped ToTransformStamped(
int64_t timestamp_uts, const std::string& parent_frame_id,
const std::string& child_frame_id,
const cartographer::transform::proto::Rigid3d& parent_T_child) {
static int64_t seq = 0;
geometry_msgs::msg::TransformStamped transform_stamped;
transform_stamped.header.seq = ++seq;
transform_stamped.header.frame_id = parent_frame_id;
transform_stamped.header.stamp = cartographer_ros::ToRos(
::cartographer::common::FromUniversal(timestamp_uts));
transform_stamped.child_frame_id = child_frame_id;
transform_stamped.transform = cartographer_ros::ToGeometryMsgTransform(
::cartographer::transform::ToRigid3(parent_T_child));
return transform_stamped;
}
void pbstream_trajectories_to_bag(const std::string& pbstream_filename,
const std::string& output_bag_filename,
const std::string& parent_frame_id) {
const auto pose_graph =
cartographer::io::DeserializePoseGraphFromFile(FLAGS_input);
rosbag::Bag bag(output_bag_filename, rosbag::bagmode::Write);
for (const auto trajectory : pose_graph.trajectory()) {
const auto child_frame_id =
absl::StrCat("trajectory_", trajectory.trajectory_id());
LOG(INFO)
<< "Writing tf and geometry_msgs/TransformStamped for trajectory id "
<< trajectory.trajectory_id() << " with " << trajectory.node_size()
<< " nodes.";
for (const auto& node : trajectory.node()) {
tf2_msgs::TFMessage tf_msg;
geometry_msgs::msg::TransformStamped transform_stamped = ToTransformStamped(
node.timestamp(), parent_frame_id, child_frame_id, node.pose());
tf_msg.transforms.push_back(transform_stamped);
bag.write(child_frame_id, transform_stamped.header.stamp,
transform_stamped);
bag.write("/tf", transform_stamped.header.stamp, tf_msg);
}
}
}
} // namespace
} // namespace cartographer_ros
int main(int argc, char* argv[]) {
FLAGS_alsologtostderr = true;
google::InitGoogleLogging(argv[0]);
google::SetUsageMessage(
"\n\n"
"Extracts all trajectories from the pbstream and creates a bag file with "
"the trajectory poses stored in /tf.\nAdditionally, each trajectory is "
"also written separately to a geometry_msgs/TransformStamped topic named "
"after the TF child_frame_id of the trajectory.\n For each trajectory, "
"the tool will write transforms with the tf parent_frame_id set "
"according to the `parent_frame` commandline flag and child_frame_id to "
"`trajectory_i`, with `i` corresponding to the `trajectory_id`.");
google::ParseCommandLineFlags(&argc, &argv, true);
CHECK(!FLAGS_input.empty()) << "-input pbstream is missing.";
CHECK(!FLAGS_output.empty()) << "-output is missing.";
cartographer_ros::pbstream_trajectories_to_bag(FLAGS_input, FLAGS_output,
FLAGS_parent_frame);
return 0;
}
@@ -0,0 +1,148 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#include "cartographer/common/time.h"
#include "cartographer_ros/ros_log_sink.h"
#include "cartographer_ros/time_conversion.h"
#include "gflags/gflags.h"
#include "nav_msgs/Odometry.h"
#include "ros/ros.h"
#include "ros/time.h"
#include "rosbag/bag.h"
#include "rosbag/view.h"
#include "sensor_msgs/Imu.h"
#include "sensor_msgs/LaserScan.h"
#include "sensor_msgs/MultiEchoLaserScan.h"
#include "sensor_msgs/PointCloud2.h"
#include "tf2_msgs/TFMessage.h"
DEFINE_string(bag_filename, "", "Bag to publish.");
const int kQueueSize = 1;
template <typename MessagePtrType>
void PublishWithModifiedTimestamp(MessagePtrType message,
const ros::Publisher& publisher,
ros::Duration bag_to_current) {
rclcpp::Time& stamp = message->header.stamp;
stamp += bag_to_current;
publisher.publish(message);
}
template <>
void PublishWithModifiedTimestamp<tf2_msgs::TFMessage::Ptr>(
tf2_msgs::TFMessage::Ptr message, const ros::Publisher& publisher,
ros::Duration bag_to_current) {
for (const auto& transform : message->transforms) {
rclcpp::Time& stamp = const_cast<rclcpp::Time&>(transform.header.stamp);
stamp += bag_to_current;
}
publisher.publish(message);
}
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
google::SetUsageMessage(
"\n\n"
"This replays and publishes messages from a given bag file, modifying "
"their header timestamps to match current ROS time.\n\n"
"Messages are published in the same sequence and with the same delay "
"they were recorded."
"Contrary to rosbag play, it does not publish a clock, so time is"
"hopefully smoother and it should be possible to reproduce timing"
"issues.\n"
"It only plays message types related to Cartographer.\n");
google::ParseCommandLineFlags(&argc, &argv, true);
CHECK(!FLAGS_bag_filename.empty()) << "-bag_filename is missing.";
ros::init(argc, argv, "rosbag_publisher");
ros::start();
cartographer_ros::ScopedRosLogSink ros_log_sink;
rosbag::Bag bag;
bag.open(FLAGS_bag_filename, rosbag::bagmode::Read);
rosbag::View view(bag);
ros::NodeHandle node_handle;
bool use_sim_time;
node_handle.getParam("/use_sim_time", use_sim_time);
if (use_sim_time) {
LOG(ERROR) << "use_sim_time is true but not supported. Expect conflicting "
"rclcpp::Time and message header times or weird behavior.";
}
std::map<std::string, ros::Publisher> topic_to_publisher;
for (const rosbag::ConnectionInfo* c : view.getConnections()) {
const std::string& topic = c->topic;
if (topic_to_publisher.count(topic) == 0) {
ros::AdvertiseOptions options(c->topic, kQueueSize, c->md5sum,
c->datatype, c->msg_def);
topic_to_publisher[topic] = node_handle.advertise(options);
}
}
ros::Duration(1).sleep();
CHECK(ros::ok());
rclcpp::Time current_start = rclcpp::Clock().now();
rclcpp::Time bag_start = view.getBeginTime();
ros::Duration bag_to_current = current_start - bag_start;
for (const rosbag::MessageInstance& message : view) {
ros::Duration after_bag_start = message.getTime() - bag_start;
if (!::ros::ok()) {
break;
}
rclcpp::Time planned_publish_time = current_start + after_bag_start;
rclcpp::Time::sleepUntil(planned_publish_time);
ros::Publisher& publisher = topic_to_publisher.at(message.getTopic());
if (message.isType<sensor_msgs::msg::PointCloud2>()) {
PublishWithModifiedTimestamp(
message.instantiate<sensor_msgs::msg::PointCloud2>(), publisher,
bag_to_current);
} else if (message.isType<sensor_msgs::msg::MultiEchoLaserScan>()) {
PublishWithModifiedTimestamp(
message.instantiate<sensor_msgs::msg::MultiEchoLaserScan>(), publisher,
bag_to_current);
} else if (message.isType<sensor_msgs::msg::LaserScan>()) {
PublishWithModifiedTimestamp(
message.instantiate<sensor_msgs::msg::LaserScan>(), publisher,
bag_to_current);
} else if (message.isType<sensor_msgs::msg::Imu>()) {
PublishWithModifiedTimestamp(message.instantiate<sensor_msgs::msg::Imu>(),
publisher, bag_to_current);
} else if (message.isType<nav_msgs::msg::Odometry>()) {
PublishWithModifiedTimestamp(message.instantiate<nav_msgs::msg::Odometry>(),
publisher, bag_to_current);
} else if (message.isType<tf2_msgs::TFMessage>()) {
PublishWithModifiedTimestamp(message.instantiate<tf2_msgs::TFMessage>(),
publisher, bag_to_current);
} else {
LOG(WARNING) << "Skipping message with type " << message.getDataType();
}
rclcpp::Time current_time = rclcpp::Clock().now();
double simulation_delay = cartographer::common::ToSeconds(
cartographer_ros::FromRos(current_time) -
cartographer_ros::FromRos(planned_publish_time));
if (std::abs(simulation_delay) > 0.001) {
LOG(WARNING) << "Playback delayed by " << simulation_delay
<< " s. planned_publish_time: " << planned_publish_time
<< " current_time: " << current_time;
}
}
bag.close();
ros::shutdown();
}
@@ -0,0 +1,143 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "cartographer/common/math.h"
#include "cartographer/io/proto_stream_deserializer.h"
#include "cartographer/mapping/proto/pose_graph.pb.h"
#include "cartographer/transform/transform_interpolation_buffer.h"
#include "cartographer_ros/msg_conversion.h"
#include "cartographer_ros/time_conversion.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "ros/ros.h"
#include "ros/time.h"
#include "rosbag/bag.h"
#include "rosbag/view.h"
#include "tf2_eigen/tf2_eigen.hpp"
#include "tf2_msgs/TFMessage.h"
DEFINE_string(bag_filename, "",
"Bag file containing TF messages of the trajectory that will be "
"compared against the trajectory in the .pbstream file.");
DEFINE_string(tf_parent_frame, "map",
"The parent frame ID of the TF trajectory from the bag file.");
DEFINE_string(tf_child_frame, "base_link",
"The child frame ID of the TF trajectory from the bag file.");
DEFINE_string(pbstream_filename, "",
"Proto stream file containing the pose graph. The last "
"trajectory will be used for comparison.");
namespace cartographer_ros {
namespace {
double FractionSmallerThan(const std::vector<double>& v, double x) {
return static_cast<double>(std::count_if(
v.begin(), v.end(), [=](double value) { return value < x; })) /
v.size();
}
std::string QuantilesToString(std::vector<double>* v) {
if (v->empty()) return "(empty vector)";
std::sort(v->begin(), v->end());
std::stringstream result;
const int kNumQuantiles = 10;
for (int i = 0; i < kNumQuantiles; ++i) {
auto value = v->at(v->size() * i / kNumQuantiles);
auto percentage = 100 * i / kNumQuantiles;
result << percentage << "%: " << value << "\n";
}
result << "100%: " << v->back() << "\n";
return result.str();
}
void Run(const std::string& pbstream_filename,
const std::string& bag_filename) {
cartographer::mapping::proto::PoseGraph pose_graph_proto =
cartographer::io::DeserializePoseGraphFromFile(pbstream_filename);
const cartographer::mapping::proto::Trajectory& last_trajectory_proto =
*pose_graph_proto.mutable_trajectory()->rbegin();
const cartographer::transform::TransformInterpolationBuffer
transform_interpolation_buffer(last_trajectory_proto);
rosbag::Bag bag;
bag.open(bag_filename, rosbag::bagmode::Read);
rosbag::View view(bag);
std::vector<double> deviation_translation, deviation_rotation;
const double signal_maximum = std::numeric_limits<double>::max();
for (const rosbag::MessageInstance& message : view) {
if (!message.isType<tf2_msgs::TFMessage>()) {
continue;
}
auto tf_message = message.instantiate<tf2_msgs::TFMessage>();
for (const auto& transform : tf_message->transforms) {
if (transform.header.frame_id != FLAGS_tf_parent_frame ||
transform.child_frame_id != FLAGS_tf_child_frame) {
continue;
}
const cartographer::common::Time transform_time =
FromRos(message.getTime());
if (!transform_interpolation_buffer.Has(transform_time)) {
deviation_translation.push_back(signal_maximum);
deviation_rotation.push_back(signal_maximum);
continue;
}
auto optimized_transform =
transform_interpolation_buffer.Lookup(transform_time);
auto published_transform = ToRigid3d(transform);
deviation_translation.push_back((published_transform.translation() -
optimized_transform.translation())
.norm());
deviation_rotation.push_back(
published_transform.rotation().angularDistance(
optimized_transform.rotation()));
}
}
bag.close();
LOG(INFO) << "Distribution of translation difference:\n"
<< QuantilesToString(&deviation_translation);
LOG(INFO) << "Distribution of rotation difference:\n"
<< QuantilesToString(&deviation_rotation);
LOG(INFO) << "Fraction of translation difference smaller than 1m: "
<< FractionSmallerThan(deviation_translation, 1);
LOG(INFO) << "Fraction of translation difference smaller than 0.1m: "
<< FractionSmallerThan(deviation_translation, 0.1);
LOG(INFO) << "Fraction of translation difference smaller than 0.05m: "
<< FractionSmallerThan(deviation_translation, 0.05);
LOG(INFO) << "Fraction of translation difference smaller than 0.01m: "
<< FractionSmallerThan(deviation_translation, 0.01);
}
} // namespace
} // namespace cartographer_ros
int main(int argc, char** argv) {
FLAGS_alsologtostderr = true;
google::InitGoogleLogging(argv[0]);
google::SetUsageMessage(
"\n\n"
"This compares a trajectory from a bag file against the "
"last trajectory in a pbstream file.\n");
google::ParseCommandLineFlags(&argc, &argv, true);
CHECK(!FLAGS_bag_filename.empty()) << "-bag_filename is missing.";
CHECK(!FLAGS_pbstream_filename.empty()) << "-pbstream_filename is missing.";
::cartographer_ros::Run(FLAGS_pbstream_filename, FLAGS_bag_filename);
}
@@ -0,0 +1,543 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#include "cartographer_ros/map_builder_bridge.h"
#include "absl/memory/memory.h"
#include "cartographer/io/color.h"
#include "cartographer/io/proto_stream.h"
#include "cartographer_ros/msg_conversion.h"
#include "cartographer_ros/time_conversion.h"
#include "cartographer_ros_msgs/msg/status_code.hpp"
#include "cartographer_ros_msgs/msg/status_response.hpp"
namespace cartographer_ros {
namespace {
using ::cartographer::transform::Rigid3d;
constexpr double kTrajectoryLineStripMarkerScale = 0.07;
constexpr double kLandmarkMarkerScale = 0.2;
constexpr double kConstraintMarkerScale = 0.025;
::std_msgs::msg::ColorRGBA ToMessage(const cartographer::io::FloatColor& color) {
::std_msgs::msg::ColorRGBA result;
result.r = color[0];
result.g = color[1];
result.b = color[2];
result.a = 1.f;
return result;
}
visualization_msgs::msg::Marker CreateTrajectoryMarker(const int trajectory_id,
const std::string& frame_id,
rclcpp::Time node_time) {
visualization_msgs::msg::Marker marker;
marker.ns = "Trajectory " + std::to_string(trajectory_id);
marker.id = 0;
marker.type = visualization_msgs::msg::Marker::LINE_STRIP;
marker.header.stamp = node_time;
marker.header.frame_id = frame_id;
marker.color = ToMessage(cartographer::io::GetColor(trajectory_id));
marker.scale.x = kTrajectoryLineStripMarkerScale;
marker.pose.orientation.w = 1.;
marker.pose.position.z = 0.05;
return marker;
}
int GetLandmarkIndex(
const std::string& landmark_id,
std::unordered_map<std::string, int>* landmark_id_to_index) {
auto it = landmark_id_to_index->find(landmark_id);
if (it == landmark_id_to_index->end()) {
const int new_index = landmark_id_to_index->size();
landmark_id_to_index->emplace(landmark_id, new_index);
return new_index;
}
return it->second;
}
visualization_msgs::msg::Marker CreateLandmarkMarker(int landmark_index,
const Rigid3d& landmark_pose,
const std::string& frame_id,
rclcpp::Time node_time) {
visualization_msgs::msg::Marker marker;
marker.ns = "Landmarks";
marker.id = landmark_index;
marker.type = visualization_msgs::msg::Marker::SPHERE;
marker.header.stamp = node_time;
marker.header.frame_id = frame_id;
marker.scale.x = kLandmarkMarkerScale;
marker.scale.y = kLandmarkMarkerScale;
marker.scale.z = kLandmarkMarkerScale;
marker.color = ToMessage(cartographer::io::GetColor(landmark_index));
marker.pose = ToGeometryMsgPose(landmark_pose);
return marker;
}
void PushAndResetLineMarker(visualization_msgs::msg::Marker* marker,
std::vector<visualization_msgs::msg::Marker>* markers) {
markers->push_back(*marker);
++marker->id;
marker->points.clear();
}
} // namespace
MapBuilderBridge::MapBuilderBridge(
const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
tf2_ros::Buffer* const tf_buffer)
: node_options_(node_options),
map_builder_(std::move(map_builder)),
tf_buffer_(tf_buffer) {}
void MapBuilderBridge::LoadState(const std::string& state_filename,
bool load_frozen_state) {
// Check if suffix of the state file is ".pbstream".
const std::string suffix = ".pbstream";
CHECK_EQ(state_filename.substr(
std::max<int>(state_filename.size() - suffix.size(), 0)),
suffix)
<< "The file containing the state to be loaded must be a "
".pbstream file.";
LOG(INFO) << "Loading saved state '" << state_filename << "'...";
cartographer::io::ProtoStreamReader stream(state_filename);
map_builder_->LoadState(&stream, load_frozen_state);
}
int MapBuilderBridge::AddTrajectory(
const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& trajectory_options) {
const int trajectory_id = map_builder_->AddTrajectoryBuilder(
expected_sensor_ids, trajectory_options.trajectory_builder_options,
[this](const int trajectory_id, const ::cartographer::common::Time time,
const Rigid3d local_pose,
::cartographer::sensor::RangeData range_data_in_local,
const std::unique_ptr<
const ::cartographer::mapping::TrajectoryBuilderInterface::
InsertionResult>) {
OnLocalSlamResult(trajectory_id, time, local_pose, range_data_in_local);
});
LOG(INFO) << "Added trajectory with ID '" << trajectory_id << "'.";
// Make sure there is no trajectory with 'trajectory_id' yet.
CHECK_EQ(sensor_bridges_.count(trajectory_id), 0);
sensor_bridges_[trajectory_id] = absl::make_unique<SensorBridge>(
trajectory_options.num_subdivisions_per_laser_scan,
trajectory_options.tracking_frame,
node_options_.lookup_transform_timeout_sec, tf_buffer_,
map_builder_->GetTrajectoryBuilder(trajectory_id));
auto emplace_result =
trajectory_options_.emplace(trajectory_id, trajectory_options);
CHECK(emplace_result.second == true);
return trajectory_id;
}
void MapBuilderBridge::FinishTrajectory(const int trajectory_id) {
LOG(INFO) << "Finishing trajectory with ID '" << trajectory_id << "'...";
// Make sure there is a trajectory with 'trajectory_id'.
CHECK(GetTrajectoryStates().count(trajectory_id));
map_builder_->FinishTrajectory(trajectory_id);
sensor_bridges_.erase(trajectory_id);
}
void MapBuilderBridge::RunFinalOptimization() {
LOG(INFO) << "Running final trajectory optimization...";
map_builder_->pose_graph()->RunFinalOptimization();
}
bool MapBuilderBridge::SerializeState(const std::string& filename,
const bool include_unfinished_submaps) {
return map_builder_->SerializeStateToFile(include_unfinished_submaps,
filename);
}
void MapBuilderBridge::HandleSubmapQuery(
const cartographer_ros_msgs::srv::SubmapQuery::Request::SharedPtr request,
cartographer_ros_msgs::srv::SubmapQuery::Response::SharedPtr response) {
cartographer::mapping::proto::SubmapQuery::Response response_proto;
cartographer::mapping::SubmapId submap_id{request->trajectory_id,
request->submap_index};
const std::string error =
map_builder_->SubmapToProto(submap_id, &response_proto);
if (!error.empty()) {
LOG(ERROR) << error;
response->status.code = cartographer_ros_msgs::msg::StatusCode::NOT_FOUND;
response->status.message = error;
return;
}
response->submap_version = response_proto.submap_version();
for (const auto& texture_proto : response_proto.textures()) {
response->textures.emplace_back();
auto& texture = response->textures.back();
texture.cells.insert(texture.cells.begin(), texture_proto.cells().begin(),
texture_proto.cells().end());
texture.width = texture_proto.width();
texture.height = texture_proto.height();
texture.resolution = texture_proto.resolution();
texture.slice_pose = ToGeometryMsgPose(
cartographer::transform::ToRigid3(texture_proto.slice_pose()));
}
response->status.message = "Success.";
response->status.code = cartographer_ros_msgs::msg::StatusCode::OK;
}
std::map<int, ::cartographer::mapping::PoseGraphInterface::TrajectoryState>
MapBuilderBridge::GetTrajectoryStates() {
auto trajectory_states = map_builder_->pose_graph()->GetTrajectoryStates();
// Add active trajectories that are not yet in the pose graph, but are e.g.
// waiting for input sensor data and thus already have a sensor bridge.
for (const auto& sensor_bridge : sensor_bridges_) {
trajectory_states.insert(std::make_pair(
sensor_bridge.first,
::cartographer::mapping::PoseGraphInterface::TrajectoryState::ACTIVE));
}
return trajectory_states;
}
cartographer_ros_msgs::msg::SubmapList MapBuilderBridge::GetSubmapList(rclcpp::Time node_time) {
cartographer_ros_msgs::msg::SubmapList submap_list;
submap_list.header.stamp = node_time;
submap_list.header.frame_id = node_options_.map_frame;
for (const auto& submap_id_pose :
map_builder_->pose_graph()->GetAllSubmapPoses()) {
cartographer_ros_msgs::msg::SubmapEntry submap_entry;
submap_entry.is_frozen = map_builder_->pose_graph()->IsTrajectoryFrozen(
submap_id_pose.id.trajectory_id);
submap_entry.trajectory_id = submap_id_pose.id.trajectory_id;
submap_entry.submap_index = submap_id_pose.id.submap_index;
submap_entry.submap_version = submap_id_pose.data.version;
submap_entry.pose = ToGeometryMsgPose(submap_id_pose.data.pose);
submap_list.submap.push_back(submap_entry);
}
return submap_list;
}
std::unordered_map<int, MapBuilderBridge::LocalTrajectoryData>
MapBuilderBridge::GetLocalTrajectoryData() {
std::unordered_map<int, LocalTrajectoryData> local_trajectory_data;
for (const auto& entry : sensor_bridges_) {
const int trajectory_id = entry.first;
const SensorBridge& sensor_bridge = *entry.second;
std::shared_ptr<const LocalTrajectoryData::LocalSlamData> local_slam_data;
{
absl::MutexLock lock(&mutex_);
if (local_slam_data_.count(trajectory_id) == 0) {
continue;
}
local_slam_data = local_slam_data_.at(trajectory_id);
}
// Make sure there is a trajectory with 'trajectory_id'.
CHECK_EQ(trajectory_options_.count(trajectory_id), 1);
local_trajectory_data[trajectory_id] = {
local_slam_data,
map_builder_->pose_graph()->GetLocalToGlobalTransform(trajectory_id),
sensor_bridge.tf_bridge().LookupToTracking(
local_slam_data->time,
trajectory_options_[trajectory_id].published_frame),
trajectory_options_[trajectory_id]};
}
return local_trajectory_data;
}
void MapBuilderBridge::HandleTrajectoryQuery(
const cartographer_ros_msgs::srv::TrajectoryQuery::Request::SharedPtr request,
cartographer_ros_msgs::srv::TrajectoryQuery::Response::SharedPtr response) {
// This query is safe if the trajectory doesn't exist (returns 0 poses).
// However, we can filter unwanted states at the higher level in the node.
const auto node_poses = map_builder_->pose_graph()->GetTrajectoryNodePoses();
for (const auto& node_id_data :
node_poses.trajectory(request->trajectory_id)) {
if (!node_id_data.data.constant_pose_data.has_value()) {
continue;
}
geometry_msgs::msg::PoseStamped pose_stamped;
pose_stamped.header.frame_id = node_options_.map_frame;
pose_stamped.header.stamp =
ToRos(node_id_data.data.constant_pose_data.value().time);
pose_stamped.pose = ToGeometryMsgPose(node_id_data.data.global_pose);
response->trajectory.push_back(pose_stamped);
}
response->status.code = cartographer_ros_msgs::msg::StatusCode::OK;
response->status.message =
"Retrieved " + std::to_string(response->trajectory.size()) +
" trajectory nodes from trajectory " + std::to_string(request->trajectory_id) + ".";
}
visualization_msgs::msg::MarkerArray MapBuilderBridge::GetTrajectoryNodeList(
rclcpp::Time node_time)
{
visualization_msgs::msg::MarkerArray trajectory_node_list;
const auto node_poses = map_builder_->pose_graph()->GetTrajectoryNodePoses();
// Find the last node indices for each trajectory that have either
// inter-submap or inter-trajectory constraints.
std::map<int, int /* node_index */>
trajectory_to_last_inter_submap_constrained_node;
std::map<int, int /* node_index */>
trajectory_to_last_inter_trajectory_constrained_node;
for (const int trajectory_id : node_poses.trajectory_ids()) {
trajectory_to_last_inter_submap_constrained_node[trajectory_id] = 0;
trajectory_to_last_inter_trajectory_constrained_node[trajectory_id] = 0;
}
const auto constraints = map_builder_->pose_graph()->constraints();
for (const auto& constraint : constraints) {
if (constraint.tag ==
cartographer::mapping::PoseGraphInterface::Constraint::INTER_SUBMAP) {
if (constraint.node_id.trajectory_id ==
constraint.submap_id.trajectory_id) {
trajectory_to_last_inter_submap_constrained_node[constraint.node_id
.trajectory_id] =
std::max(trajectory_to_last_inter_submap_constrained_node.at(
constraint.node_id.trajectory_id),
constraint.node_id.node_index);
} else {
trajectory_to_last_inter_trajectory_constrained_node
[constraint.node_id.trajectory_id] =
std::max(trajectory_to_last_inter_submap_constrained_node.at(
constraint.node_id.trajectory_id),
constraint.node_id.node_index);
}
}
}
for (const int trajectory_id : node_poses.trajectory_ids()) {
visualization_msgs::msg::Marker marker =
CreateTrajectoryMarker(trajectory_id, node_options_.map_frame, node_time);
int last_inter_submap_constrained_node = std::max(
node_poses.trajectory(trajectory_id).begin()->id.node_index,
trajectory_to_last_inter_submap_constrained_node.at(trajectory_id));
int last_inter_trajectory_constrained_node = std::max(
node_poses.trajectory(trajectory_id).begin()->id.node_index,
trajectory_to_last_inter_trajectory_constrained_node.at(trajectory_id));
last_inter_submap_constrained_node =
std::max(last_inter_submap_constrained_node,
last_inter_trajectory_constrained_node);
if (map_builder_->pose_graph()->IsTrajectoryFrozen(trajectory_id)) {
last_inter_submap_constrained_node =
(--node_poses.trajectory(trajectory_id).end())->id.node_index;
last_inter_trajectory_constrained_node =
last_inter_submap_constrained_node;
}
marker.color.a = 1.0;
for (const auto& node_id_data : node_poses.trajectory(trajectory_id)) {
if (!node_id_data.data.constant_pose_data.has_value()) {
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
continue;
}
const ::geometry_msgs::msg::Point node_point =
ToGeometryMsgPoint(node_id_data.data.global_pose.translation());
marker.points.push_back(node_point);
if (node_id_data.id.node_index ==
last_inter_trajectory_constrained_node) {
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
marker.points.push_back(node_point);
marker.color.a = 0.5;
}
if (node_id_data.id.node_index == last_inter_submap_constrained_node) {
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
marker.points.push_back(node_point);
marker.color.a = 0.25;
}
// Work around the 16384 point limit in RViz by splitting the
// trajectory into multiple markers.
if (marker.points.size() == 16384) {
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
// Push back the last point, so the two markers appear connected.
marker.points.push_back(node_point);
}
}
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
size_t current_last_marker_id = static_cast<size_t>(marker.id - 1);
if (trajectory_to_highest_marker_id_.count(trajectory_id) == 0) {
trajectory_to_highest_marker_id_[trajectory_id] = current_last_marker_id;
} else {
marker.action = visualization_msgs::msg::Marker::DELETE;
while (static_cast<size_t>(marker.id) <=
trajectory_to_highest_marker_id_[trajectory_id]) {
trajectory_node_list.markers.push_back(marker);
++marker.id;
}
trajectory_to_highest_marker_id_[trajectory_id] = current_last_marker_id;
}
}
return trajectory_node_list;
}
visualization_msgs::msg::MarkerArray MapBuilderBridge::GetLandmarkPosesList(
rclcpp::Time node_time)
{
visualization_msgs::msg::MarkerArray landmark_poses_list;
const std::map<std::string, Rigid3d> landmark_poses =
map_builder_->pose_graph()->GetLandmarkPoses();
for (const auto& id_to_pose : landmark_poses) {
landmark_poses_list.markers.push_back(CreateLandmarkMarker(
GetLandmarkIndex(id_to_pose.first, &landmark_to_index_),
id_to_pose.second, node_options_.map_frame, node_time));
}
return landmark_poses_list;
}
visualization_msgs::msg::MarkerArray MapBuilderBridge::GetConstraintList(rclcpp::Time node_time) {
visualization_msgs::msg::MarkerArray constraint_list;
int marker_id = 0;
visualization_msgs::msg::Marker constraint_intra_marker;
constraint_intra_marker.id = marker_id++;
constraint_intra_marker.ns = "Intra constraints";
constraint_intra_marker.type = visualization_msgs::msg::Marker::LINE_LIST;
constraint_intra_marker.header.stamp = node_time;
constraint_intra_marker.header.frame_id = node_options_.map_frame;
constraint_intra_marker.scale.x = kConstraintMarkerScale;
constraint_intra_marker.pose.orientation.w = 1.0;
visualization_msgs::msg::Marker residual_intra_marker = constraint_intra_marker;
residual_intra_marker.id = marker_id++;
residual_intra_marker.ns = "Intra residuals";
// This and other markers which are less numerous are set to be slightly
// above the intra constraints marker in order to ensure that they are
// visible.
residual_intra_marker.pose.position.z = 0.1;
visualization_msgs::msg::Marker constraint_inter_same_trajectory_marker =
constraint_intra_marker;
constraint_inter_same_trajectory_marker.id = marker_id++;
constraint_inter_same_trajectory_marker.ns =
"Inter constraints, same trajectory";
constraint_inter_same_trajectory_marker.pose.position.z = 0.1;
visualization_msgs::msg::Marker residual_inter_same_trajectory_marker =
constraint_intra_marker;
residual_inter_same_trajectory_marker.id = marker_id++;
residual_inter_same_trajectory_marker.ns = "Inter residuals, same trajectory";
residual_inter_same_trajectory_marker.pose.position.z = 0.1;
visualization_msgs::msg::Marker constraint_inter_diff_trajectory_marker =
constraint_intra_marker;
constraint_inter_diff_trajectory_marker.id = marker_id++;
constraint_inter_diff_trajectory_marker.ns =
"Inter constraints, different trajectories";
constraint_inter_diff_trajectory_marker.pose.position.z = 0.1;
visualization_msgs::msg::Marker residual_inter_diff_trajectory_marker =
constraint_intra_marker;
residual_inter_diff_trajectory_marker.id = marker_id++;
residual_inter_diff_trajectory_marker.ns =
"Inter residuals, different trajectories";
residual_inter_diff_trajectory_marker.pose.position.z = 0.1;
const auto trajectory_node_poses =
map_builder_->pose_graph()->GetTrajectoryNodePoses();
const auto submap_poses = map_builder_->pose_graph()->GetAllSubmapPoses();
const auto constraints = map_builder_->pose_graph()->constraints();
for (const auto& constraint : constraints) {
visualization_msgs::msg::Marker *constraint_marker, *residual_marker;
std_msgs::msg::ColorRGBA color_constraint, color_residual;
if (constraint.tag ==
cartographer::mapping::PoseGraphInterface::Constraint::INTRA_SUBMAP) {
constraint_marker = &constraint_intra_marker;
residual_marker = &residual_intra_marker;
// Color mapping for submaps of various trajectories - add trajectory id
// to ensure different starting colors. Also add a fixed offset of 25
// to avoid having identical colors as trajectories.
color_constraint = ToMessage(
cartographer::io::GetColor(constraint.submap_id.submap_index +
constraint.submap_id.trajectory_id + 25));
color_residual.a = 1.0;
color_residual.r = 1.0;
} else {
if (constraint.node_id.trajectory_id ==
constraint.submap_id.trajectory_id) {
constraint_marker = &constraint_inter_same_trajectory_marker;
residual_marker = &residual_inter_same_trajectory_marker;
// Bright yellow
color_constraint.a = 1.0;
color_constraint.r = color_constraint.g = 1.0;
} else {
constraint_marker = &constraint_inter_diff_trajectory_marker;
residual_marker = &residual_inter_diff_trajectory_marker;
// Bright orange
color_constraint.a = 1.0;
color_constraint.r = 1.0;
color_constraint.g = 165. / 255.;
}
// Bright cyan
color_residual.a = 1.0;
color_residual.b = color_residual.g = 1.0;
}
for (int i = 0; i < 2; ++i) {
constraint_marker->colors.push_back(color_constraint);
residual_marker->colors.push_back(color_residual);
}
const auto submap_it = submap_poses.find(constraint.submap_id);
if (submap_it == submap_poses.end()) {
continue;
}
const auto& submap_pose = submap_it->data.pose;
const auto node_it = trajectory_node_poses.find(constraint.node_id);
if (node_it == trajectory_node_poses.end()) {
continue;
}
const auto& trajectory_node_pose = node_it->data.global_pose;
const Rigid3d constraint_pose = submap_pose * constraint.pose.zbar_ij;
constraint_marker->points.push_back(
ToGeometryMsgPoint(submap_pose.translation()));
constraint_marker->points.push_back(
ToGeometryMsgPoint(constraint_pose.translation()));
residual_marker->points.push_back(
ToGeometryMsgPoint(constraint_pose.translation()));
residual_marker->points.push_back(
ToGeometryMsgPoint(trajectory_node_pose.translation()));
}
constraint_list.markers.push_back(constraint_intra_marker);
constraint_list.markers.push_back(residual_intra_marker);
constraint_list.markers.push_back(constraint_inter_same_trajectory_marker);
constraint_list.markers.push_back(residual_inter_same_trajectory_marker);
constraint_list.markers.push_back(constraint_inter_diff_trajectory_marker);
constraint_list.markers.push_back(residual_inter_diff_trajectory_marker);
return constraint_list;
}
SensorBridge* MapBuilderBridge::sensor_bridge(const int trajectory_id) {
return sensor_bridges_.at(trajectory_id).get();
}
void MapBuilderBridge::OnLocalSlamResult(
const int trajectory_id, const ::cartographer::common::Time time,
const Rigid3d local_pose,
::cartographer::sensor::RangeData range_data_in_local) {
std::shared_ptr<const LocalTrajectoryData::LocalSlamData> local_slam_data =
std::make_shared<LocalTrajectoryData::LocalSlamData>(
LocalTrajectoryData::LocalSlamData{time, local_pose,
std::move(range_data_in_local)});
absl::MutexLock lock(&mutex_);
local_slam_data_[trajectory_id] = std::move(local_slam_data);
}
} // namespace cartographer_ros
@@ -0,0 +1,69 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#include "cartographer_ros/metrics/family_factory.h"
#include "absl/memory/memory.h"
namespace cartographer_ros {
namespace metrics {
using BucketBoundaries = ::cartographer::metrics::Histogram::BucketBoundaries;
::cartographer::metrics::Family<::cartographer::metrics::Counter>*
FamilyFactory::NewCounterFamily(const std::string& name,
const std::string& description) {
auto wrapper = absl::make_unique<CounterFamily>(name, description);
auto* ptr = wrapper.get();
counter_families_.emplace_back(std::move(wrapper));
return ptr;
}
::cartographer::metrics::Family<::cartographer::metrics::Gauge>*
FamilyFactory::NewGaugeFamily(const std::string& name,
const std::string& description) {
auto wrapper = absl::make_unique<GaugeFamily>(name, description);
auto* ptr = wrapper.get();
gauge_families_.emplace_back(std::move(wrapper));
return ptr;
}
::cartographer::metrics::Family<::cartographer::metrics::Histogram>*
FamilyFactory::NewHistogramFamily(const std::string& name,
const std::string& description,
const BucketBoundaries& boundaries) {
auto wrapper =
absl::make_unique<HistogramFamily>(name, description, boundaries);
auto* ptr = wrapper.get();
histogram_families_.emplace_back(std::move(wrapper));
return ptr;
}
void FamilyFactory::ReadMetrics(
cartographer_ros_msgs::srv::ReadMetrics::Response::SharedPtr response) const {
for (const auto& counter_family : counter_families_) {
response->metric_families.push_back(counter_family->ToRosMessage());
}
for (const auto& gauge_family : gauge_families_) {
response->metric_families.push_back(gauge_family->ToRosMessage());
}
for (const auto& histogram_family : histogram_families_) {
response->metric_families.push_back(histogram_family->ToRosMessage());
}
}
} // namespace metrics
} // namespace cartographer_ros
@@ -0,0 +1,82 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#include "cartographer_ros/metrics/internal/family.h"
#include "absl/memory/memory.h"
#include "cartographer_ros/metrics/internal/counter.h"
#include "cartographer_ros/metrics/internal/gauge.h"
#include "cartographer_ros/metrics/internal/histogram.h"
namespace cartographer_ros {
namespace metrics {
using BucketBoundaries = ::cartographer::metrics::Histogram::BucketBoundaries;
Counter* CounterFamily::Add(const std::map<std::string, std::string>& labels) {
auto wrapper = absl::make_unique<Counter>(labels);
auto* ptr = wrapper.get();
wrappers_.emplace_back(std::move(wrapper));
return ptr;
}
cartographer_ros_msgs::msg::MetricFamily CounterFamily::ToRosMessage() {
cartographer_ros_msgs::msg::MetricFamily family_msg;
family_msg.name = name_;
family_msg.description = description_;
for (const auto& wrapper : wrappers_) {
family_msg.metrics.push_back(wrapper->ToRosMessage());
}
return family_msg;
}
Gauge* GaugeFamily::Add(const std::map<std::string, std::string>& labels) {
auto wrapper = absl::make_unique<Gauge>(labels);
auto* ptr = wrapper.get();
wrappers_.emplace_back(std::move(wrapper));
return ptr;
}
cartographer_ros_msgs::msg::MetricFamily GaugeFamily::ToRosMessage() {
cartographer_ros_msgs::msg::MetricFamily family_msg;
family_msg.name = name_;
family_msg.description = description_;
for (const auto& wrapper : wrappers_) {
family_msg.metrics.push_back(wrapper->ToRosMessage());
}
return family_msg;
}
Histogram* HistogramFamily::Add(
const std::map<std::string, std::string>& labels) {
auto wrapper = absl::make_unique<Histogram>(labels, boundaries_);
auto* ptr = wrapper.get();
wrappers_.emplace_back(std::move(wrapper));
return ptr;
}
cartographer_ros_msgs::msg::MetricFamily HistogramFamily::ToRosMessage() {
cartographer_ros_msgs::msg::MetricFamily family_msg;
family_msg.name = name_;
family_msg.description = description_;
for (const auto& wrapper : wrappers_) {
family_msg.metrics.push_back(wrapper->ToRosMessage());
}
return family_msg;
}
} // namespace metrics
} // namespace cartographer_ros
@@ -0,0 +1,90 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#include "cartographer_ros/metrics/internal/histogram.h"
#include <algorithm>
#include <numeric>
#include "glog/logging.h"
namespace cartographer_ros {
namespace metrics {
using BucketBoundaries = ::cartographer::metrics::Histogram::BucketBoundaries;
Histogram::Histogram(const std::map<std::string, std::string>& labels,
const BucketBoundaries& bucket_boundaries)
: labels_(labels),
bucket_boundaries_(bucket_boundaries),
bucket_counts_(bucket_boundaries.size() + 1) {
absl::MutexLock lock(&mutex_);
CHECK(std::is_sorted(std::begin(bucket_boundaries_),
std::end(bucket_boundaries_)));
}
void Histogram::Observe(double value) {
auto bucket_index =
std::distance(bucket_boundaries_.begin(),
std::upper_bound(bucket_boundaries_.begin(),
bucket_boundaries_.end(), value));
absl::MutexLock lock(&mutex_);
sum_ += value;
bucket_counts_[bucket_index] += 1;
}
std::map<double, double> Histogram::CountsByBucket() {
absl::MutexLock lock(&mutex_);
std::map<double, double> counts_by_bucket;
// Add the finite buckets.
for (size_t i = 0; i < bucket_boundaries_.size(); ++i) {
counts_by_bucket[bucket_boundaries_.at(i)] = bucket_counts_.at(i);
}
// Add the "infinite" bucket.
counts_by_bucket[kInfiniteBoundary] = bucket_counts_.back();
return counts_by_bucket;
}
double Histogram::Sum() {
absl::MutexLock lock(&mutex_);
return sum_;
}
double Histogram::CumulativeCount() {
absl::MutexLock lock(&mutex_);
return std::accumulate(bucket_counts_.begin(), bucket_counts_.end(), 0.);
}
cartographer_ros_msgs::msg::Metric Histogram::ToRosMessage() {
cartographer_ros_msgs::msg::Metric msg;
msg.type = cartographer_ros_msgs::msg::Metric::TYPE_HISTOGRAM;
for (const auto& label : labels_) {
cartographer_ros_msgs::msg::MetricLabel label_msg;
label_msg.key = label.first;
label_msg.value = label.second;
msg.labels.push_back(label_msg);
}
for (const auto& bucket : CountsByBucket()) {
cartographer_ros_msgs::msg::HistogramBucket bucket_msg;
bucket_msg.bucket_boundary = bucket.first;
bucket_msg.count = bucket.second;
msg.counts_by_bucket.push_back(bucket_msg);
}
return msg;
}
} // namespace metrics
} // namespace cartographer_ros
@@ -0,0 +1,104 @@
/*
* Copyright 2018 The Cartographer Authors
*
* 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.
*/
#include <algorithm>
#include <array>
#include <numeric>
#include "cartographer/metrics/histogram.h"
#include "cartographer_ros/metrics/internal/counter.h"
#include "cartographer_ros/metrics/internal/gauge.h"
#include "cartographer_ros/metrics/internal/histogram.h"
#include "gtest/gtest.h"
namespace cartographer_ros {
namespace metrics {
TEST(Metrics, GaugeTest) {
Gauge gauge({});
EXPECT_EQ(gauge.Value(), 0.);
gauge.Increment(1.2);
EXPECT_EQ(gauge.Value(), 1.2);
gauge.Increment();
EXPECT_EQ(gauge.Value(), 2.2);
gauge.Decrement(2.2);
EXPECT_EQ(gauge.Value(), 0.);
gauge.Decrement();
EXPECT_EQ(gauge.Value(), -1.);
}
TEST(Metrics, CounterTest) {
Counter counter({});
EXPECT_EQ(counter.Value(), 0.);
counter.Increment(1.2);
EXPECT_EQ(counter.Value(), 1.2);
counter.Increment(0.8);
EXPECT_EQ(counter.Value(), 2.);
counter.Increment();
EXPECT_EQ(counter.Value(), 3.);
}
TEST(Metrics, HistogramFixedWidthTest) {
auto boundaries = ::cartographer::metrics::Histogram::FixedWidth(1, 3);
Histogram histogram({}, boundaries);
// Observe some values that fit in finite buckets.
std::array<double, 3> values = {{0., 2, 2.5}};
for (const auto& value : values) {
histogram.Observe(value);
}
// 1 2 3 inf
// 1 | 0 | 2 | 0 |
EXPECT_EQ(histogram.CountsByBucket()[1], 1);
EXPECT_EQ(histogram.CountsByBucket()[2], 0);
EXPECT_EQ(histogram.CountsByBucket()[3], 2);
EXPECT_EQ(histogram.CumulativeCount(), values.size());
EXPECT_EQ(histogram.Sum(), std::accumulate(values.begin(), values.end(), 0.));
// Values above the last bucket boundary should go to the "infinite" bucket.
histogram.Observe(3.5);
// 1 2 3 inf
// 1 | 0 | 2 | 1 |
EXPECT_EQ(histogram.CountsByBucket()[kInfiniteBoundary], 1);
}
TEST(Metrics, HistogramScaledPowersOfTest) {
auto boundaries =
::cartographer::metrics::Histogram::ScaledPowersOf(2, 1, 2048);
Histogram histogram({}, boundaries);
// Observe some values that fit in finite buckets.
std::array<double, 3> values = {{256, 512, 666}};
for (const auto& value : values) {
histogram.Observe(value);
}
// ... 256 512 1024 inf
// ... | 1 | 2 | 0 |
EXPECT_EQ(histogram.CountsByBucket()[256], 0);
EXPECT_EQ(histogram.CountsByBucket()[512], 1);
EXPECT_EQ(histogram.CountsByBucket()[1024], 2);
EXPECT_EQ(histogram.CumulativeCount(), values.size());
EXPECT_EQ(histogram.Sum(), std::accumulate(values.begin(), values.end(), 0.));
// Values above the last bucket boundary should go to the "infinite" bucket.
histogram.Observe(2048);
// ... 256 512 1024 inf
// ... | 1 | 2 | 1 |
EXPECT_EQ(histogram.CountsByBucket()[kInfiniteBoundary], 1);
}
} // namespace metrics
} // namespace cartographer_ros
@@ -0,0 +1,421 @@
/*
* Copyright 2016 The Cartographer Authors
*
* 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.
*/
#include "cartographer_ros/msg_conversion.h"
#include <cmath>
#include "cartographer/common/math.h"
#include "cartographer/common/port.h"
#include "cartographer/common/time.h"
#include "cartographer/io/submap_painter.h"
#include "cartographer/transform/proto/transform.pb.h"
#include "cartographer/transform/transform.h"
#include "cartographer_ros/time_conversion.h"
#include "geometry_msgs/msg/pose.hpp"
#include "geometry_msgs/msg/quaternion.hpp"
#include "geometry_msgs/msg/transform.hpp"
#include "geometry_msgs/msg/transform_stamped.hpp"
#include "geometry_msgs/msg/vector3.hpp"
#include "glog/logging.h"
#include "nav_msgs/msg/occupancy_grid.hpp"
#include "pcl/point_cloud.h"
#include "pcl/point_types.h"
#include "pcl_conversions/pcl_conversions.h"
#include "builtin_interfaces/msg/time.hpp"
//#include "ros/serialization.h"
#include "sensor_msgs/msg/imu.hpp"
#include "sensor_msgs/msg/laser_scan.hpp"
#include "sensor_msgs/msg/multi_echo_laser_scan.hpp"
#include "sensor_msgs/msg/point_cloud2.hpp"
namespace {
// Sizes of PCL point types have to be 4n floats for alignment, as described in
// http://pointclouds.org/documentation/tutorials/adding_custom_ptype.php
struct PointXYZT {
float x;
float y;
float z;
float time;
};
struct PointXYZIT {
PCL_ADD_POINT4D;
float intensity;
float time;
float unused_padding[2];
};
} // namespace
POINT_CLOUD_REGISTER_POINT_STRUCT(
PointXYZT, (float, x, x)(float, y, y)(float, z, z)(float, time, time))
POINT_CLOUD_REGISTER_POINT_STRUCT(
PointXYZIT,
(float, x, x)(float, y, y)(float, z, z)(float, intensity,
intensity)(float, time, time))
namespace cartographer_ros {
namespace {
// The ros::sensor_msgs::msg::PointCloud2 binary data contains 4 floats for each
// point. The last one must be this value or RViz is not showing the point cloud
// properly.
constexpr float kPointCloudComponentFourMagic = 1.;
using ::cartographer::sensor::LandmarkData;
using ::cartographer::sensor::LandmarkObservation;
using ::cartographer::sensor::PointCloudWithIntensities;
using ::cartographer::transform::Rigid3d;
using ::cartographer_ros_msgs::msg::LandmarkEntry;
using ::cartographer_ros_msgs::msg::LandmarkList;
sensor_msgs::msg::PointCloud2 PreparePointCloud2Message(const int64_t timestamp,
const std::string& frame_id,
const int num_points) {
sensor_msgs::msg::PointCloud2 msg;
msg.header.stamp = ToRos(::cartographer::common::FromUniversal(timestamp));
msg.header.frame_id = frame_id;
msg.height = 1;
msg.width = num_points;
msg.fields.resize(3);
msg.fields[0].name = "x";
msg.fields[0].offset = 0;
msg.fields[0].datatype = sensor_msgs::msg::PointField::FLOAT32;
msg.fields[0].count = 1;
msg.fields[1].name = "y";
msg.fields[1].offset = 4;
msg.fields[1].datatype = sensor_msgs::msg::PointField::FLOAT32;
msg.fields[1].count = 1;
msg.fields[2].name = "z";
msg.fields[2].offset = 8;
msg.fields[2].datatype = sensor_msgs::msg::PointField::FLOAT32;
msg.fields[2].count = 1;
msg.is_bigendian = false;
msg.point_step = 16;
msg.row_step = 16 * msg.width;
msg.is_dense = true;
msg.data.resize(16 * num_points);
return msg;
}
// For sensor_msgs::msg::LaserScan.
bool HasEcho(float) { return true; }
float GetFirstEcho(float range) { return range; }
// For sensor_msgs::msg::MultiEchoLaserScan.
bool HasEcho(const sensor_msgs::msg::LaserEcho& echo) {
return !echo.echoes.empty();
}
float GetFirstEcho(const sensor_msgs::msg::LaserEcho& echo) {
return echo.echoes[0];
}
// For sensor_msgs::msg::LaserScan and sensor_msgs::msg::MultiEchoLaserScan.
template <typename LaserMessageType>
std::tuple<PointCloudWithIntensities, ::cartographer::common::Time>
LaserScanToPointCloudWithIntensities(const LaserMessageType& msg) {
CHECK_GE(msg.range_min, 0.f);
CHECK_GE(msg.range_max, msg.range_min);
if (msg.angle_increment > 0.f) {
CHECK_GT(msg.angle_max, msg.angle_min);
} else {
CHECK_GT(msg.angle_min, msg.angle_max);
}
PointCloudWithIntensities point_cloud;
float angle = msg.angle_min;
for (size_t i = 0; i < msg.ranges.size(); ++i) {
const auto& echoes = msg.ranges[i];
if (HasEcho(echoes)) {
const float first_echo = GetFirstEcho(echoes);
if (msg.range_min <= first_echo && first_echo <= msg.range_max) {
const Eigen::AngleAxisf rotation(angle, Eigen::Vector3f::UnitZ());
const cartographer::sensor::TimedRangefinderPoint point{
rotation * (first_echo * Eigen::Vector3f::UnitX()),
i * msg.time_increment};
point_cloud.points.push_back(point);
if (msg.intensities.size() > 0) {
CHECK_EQ(msg.intensities.size(), msg.ranges.size());
const auto& echo_intensities = msg.intensities[i];
CHECK(HasEcho(echo_intensities));
point_cloud.intensities.push_back(GetFirstEcho(echo_intensities));
} else {
point_cloud.intensities.push_back(0.f);
}
}
}
angle += msg.angle_increment;
}
::cartographer::common::Time timestamp = FromRos(msg.header.stamp);
if (!point_cloud.points.empty()) {
const double duration = point_cloud.points.back().time;
timestamp += cartographer::common::FromSeconds(duration);
for (auto& point : point_cloud.points) {
point.time -= duration;
}
}
return std::make_tuple(point_cloud, timestamp);
}
bool PointCloud2HasField(const sensor_msgs::msg::PointCloud2& pc2,
const std::string& field_name) {
for (const auto& field : pc2.fields) {
if (field.name == field_name) {
return true;
}
}
return false;
}
} // namespace
sensor_msgs::msg::PointCloud2 ToPointCloud2Message(
const int64_t timestamp, const std::string& frame_id,
const ::cartographer::sensor::TimedPointCloud& point_cloud) {
auto msg = PreparePointCloud2Message(timestamp, frame_id, point_cloud.size());
size_t offset = 0;
float * const data = reinterpret_cast<float*>(&msg.data[0]);
for (const auto& point : point_cloud) {
data[offset++] = point.position.x();
data[offset++] = point.position.y();
data[offset++] = point.position.z();
data[offset++] = kPointCloudComponentFourMagic;
}
return msg;
}
std::tuple<::cartographer::sensor::PointCloudWithIntensities,
::cartographer::common::Time>
ToPointCloudWithIntensities(const sensor_msgs::msg::LaserScan& msg) {
return LaserScanToPointCloudWithIntensities(msg);
}
std::tuple<::cartographer::sensor::PointCloudWithIntensities,
::cartographer::common::Time>
ToPointCloudWithIntensities(const sensor_msgs::msg::MultiEchoLaserScan& msg) {
return LaserScanToPointCloudWithIntensities(msg);
}
std::tuple<::cartographer::sensor::PointCloudWithIntensities,
::cartographer::common::Time>
ToPointCloudWithIntensities(const sensor_msgs::msg::PointCloud2& msg) {
PointCloudWithIntensities point_cloud;
// We check for intensity field here to avoid run-time warnings if we pass in
// a PointCloud2 without intensity.
if (PointCloud2HasField(msg, "intensity")) {
if (PointCloud2HasField(msg, "time")) {
pcl::PointCloud<PointXYZIT> pcl_point_cloud;
pcl::fromROSMsg(msg, pcl_point_cloud);
point_cloud.points.reserve(pcl_point_cloud.size());
point_cloud.intensities.reserve(pcl_point_cloud.size());
for (const auto& point : pcl_point_cloud) {
point_cloud.points.push_back(
{Eigen::Vector3f{point.x, point.y, point.z}, point.time});
point_cloud.intensities.push_back(point.intensity);
}
} else {
pcl::PointCloud<pcl::PointXYZI> pcl_point_cloud;
pcl::fromROSMsg(msg, pcl_point_cloud);
point_cloud.points.reserve(pcl_point_cloud.size());
point_cloud.intensities.reserve(pcl_point_cloud.size());
for (const auto& point : pcl_point_cloud) {
point_cloud.points.push_back(
{Eigen::Vector3f{point.x, point.y, point.z}, 0.f});
point_cloud.intensities.push_back(point.intensity);
}
}
} else {
// If we don't have an intensity field, just copy XYZ and fill in 1.0f.
if (PointCloud2HasField(msg, "time")) {
pcl::PointCloud<PointXYZT> pcl_point_cloud;
pcl::fromROSMsg(msg, pcl_point_cloud);
point_cloud.points.reserve(pcl_point_cloud.size());
point_cloud.intensities.reserve(pcl_point_cloud.size());
for (const auto& point : pcl_point_cloud) {
point_cloud.points.push_back(
{Eigen::Vector3f{point.x, point.y, point.z}, point.time});
point_cloud.intensities.push_back(1.0f);
}
} else {
pcl::PointCloud<pcl::PointXYZ> pcl_point_cloud;
pcl::fromROSMsg(msg, pcl_point_cloud);
point_cloud.points.reserve(pcl_point_cloud.size());
point_cloud.intensities.reserve(pcl_point_cloud.size());
for (const auto& point : pcl_point_cloud) {
point_cloud.points.push_back(
{Eigen::Vector3f{point.x, point.y, point.z}, 0.f});
point_cloud.intensities.push_back(1.0f);
}
}
}
::cartographer::common::Time timestamp = FromRos(msg.header.stamp);
if (!point_cloud.points.empty()) {
const double duration = point_cloud.points.back().time;
timestamp += cartographer::common::FromSeconds(duration);
for (auto& point : point_cloud.points) {
point.time -= duration;
CHECK_LE(point.time, 0.f)
<< "Encountered a point with a larger stamp than "
"the last point in the cloud.";
}
}
return std::make_tuple(point_cloud, timestamp);
}
LandmarkData ToLandmarkData(const LandmarkList& landmark_list) {
LandmarkData landmark_data;
landmark_data.time = FromRos(landmark_list.header.stamp);
for (const LandmarkEntry& entry : landmark_list.landmarks) {
landmark_data.landmark_observations.push_back(
{entry.id, ToRigid3d(entry.tracking_from_landmark_transform),
entry.translation_weight, entry.rotation_weight});
}
return landmark_data;
}
Rigid3d ToRigid3d(const geometry_msgs::msg::TransformStamped& transform) {
return Rigid3d(ToEigen(transform.transform.translation),
ToEigen(transform.transform.rotation));
}
Rigid3d ToRigid3d(const geometry_msgs::msg::Pose& pose) {
return Rigid3d({pose.position.x, pose.position.y, pose.position.z},
ToEigen(pose.orientation));
}
Eigen::Vector3d ToEigen(const geometry_msgs::msg::Vector3& vector3) {
return Eigen::Vector3d(vector3.x, vector3.y, vector3.z);
}
Eigen::Quaterniond ToEigen(const geometry_msgs::msg::Quaternion& quaternion) {
return Eigen::Quaterniond(quaternion.w, quaternion.x, quaternion.y,
quaternion.z);
}
geometry_msgs::msg::Transform ToGeometryMsgTransform(const Rigid3d& rigid3d) {
geometry_msgs::msg::Transform transform;
transform.translation.x = rigid3d.translation().x();
transform.translation.y = rigid3d.translation().y();
transform.translation.z = rigid3d.translation().z();
transform.rotation.w = rigid3d.rotation().w();
transform.rotation.x = rigid3d.rotation().x();
transform.rotation.y = rigid3d.rotation().y();
transform.rotation.z = rigid3d.rotation().z();
return transform;
}
geometry_msgs::msg::Pose ToGeometryMsgPose(const Rigid3d& rigid3d) {
geometry_msgs::msg::Pose pose;
pose.position = ToGeometryMsgPoint(rigid3d.translation());
pose.orientation.w = rigid3d.rotation().w();
pose.orientation.x = rigid3d.rotation().x();
pose.orientation.y = rigid3d.rotation().y();
pose.orientation.z = rigid3d.rotation().z();
return pose;
}
geometry_msgs::msg::Point ToGeometryMsgPoint(const Eigen::Vector3d& vector3d) {
geometry_msgs::msg::Point point;
point.x = vector3d.x();
point.y = vector3d.y();
point.z = vector3d.z();
return point;
}
Eigen::Vector3d LatLongAltToEcef(const double latitude, const double longitude,
const double altitude) {
// https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#From_geodetic_to_ECEF_coordinates
constexpr double a = 6378137.; // semi-major axis, equator to center.
constexpr double f = 1. / 298.257223563;
constexpr double b = a * (1. - f); // semi-minor axis, pole to center.
constexpr double a_squared = a * a;
constexpr double b_squared = b * b;
constexpr double e_squared = (a_squared - b_squared) / a_squared;
const double sin_phi = std::sin(cartographer::common::DegToRad(latitude));
const double cos_phi = std::cos(cartographer::common::DegToRad(latitude));
const double sin_lambda = std::sin(cartographer::common::DegToRad(longitude));
const double cos_lambda = std::cos(cartographer::common::DegToRad(longitude));
const double N = a / std::sqrt(1 - e_squared * sin_phi * sin_phi);
const double x = (N + altitude) * cos_phi * cos_lambda;
const double y = (N + altitude) * cos_phi * sin_lambda;
const double z = (b_squared / a_squared * N + altitude) * sin_phi;
return Eigen::Vector3d(x, y, z);
}
cartographer::transform::Rigid3d ComputeLocalFrameFromLatLong(
const double latitude, const double longitude) {
const Eigen::Vector3d translation = LatLongAltToEcef(latitude, longitude, 0.);
const Eigen::Quaterniond rotation =
Eigen::AngleAxisd(cartographer::common::DegToRad(latitude - 90.),
Eigen::Vector3d::UnitY()) *
Eigen::AngleAxisd(cartographer::common::DegToRad(-longitude),
Eigen::Vector3d::UnitZ());
return cartographer::transform::Rigid3d(rotation * -translation, rotation);
}
std::unique_ptr<nav_msgs::msg::OccupancyGrid> CreateOccupancyGridMsg(
const cartographer::io::PaintSubmapSlicesResult& painted_slices,
const double resolution, const std::string& frame_id,
const rclcpp::Time& time) {
auto occupancy_grid = absl::make_unique<nav_msgs::msg::OccupancyGrid>();
const int width = cairo_image_surface_get_width(painted_slices.surface.get());
const int height =
cairo_image_surface_get_height(painted_slices.surface.get());
occupancy_grid->header.stamp = time;
occupancy_grid->header.frame_id = frame_id;
occupancy_grid->info.map_load_time = time;
occupancy_grid->info.resolution = resolution;
occupancy_grid->info.width = width;
occupancy_grid->info.height = height;
occupancy_grid->info.origin.position.x =
-painted_slices.origin.x() * resolution;
occupancy_grid->info.origin.position.y =
(-height + painted_slices.origin.y()) * resolution;
occupancy_grid->info.origin.position.z = 0.;
occupancy_grid->info.origin.orientation.w = 1.;
occupancy_grid->info.origin.orientation.x = 0.;
occupancy_grid->info.origin.orientation.y = 0.;
occupancy_grid->info.origin.orientation.z = 0.;
const uint32_t* pixel_data = reinterpret_cast<uint32_t*>(
cairo_image_surface_get_data(painted_slices.surface.get()));
occupancy_grid->data.reserve(width * height);
for (int y = height - 1; y >= 0; --y) {
for (int x = 0; x < width; ++x) {
const uint32_t packed = pixel_data[y * width + x];
const unsigned char color = packed >> 16;
const unsigned char observed = packed >> 8;
const int value =
observed == 0
? -1
: ::cartographer::common::RoundToInt((1. - color / 255.) * 100.);
CHECK_LE(-1, value);
CHECK_GE(100, value);
occupancy_grid->data.push_back(value);
}
}
return occupancy_grid;
}
} // namespace cartographer_ros

Some files were not shown because too many files have changed in this diff Show More