├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── config
├── laser_to_gridmap.yaml
└── pcl_to_gridmap.yaml
├── costmap_plugins.xml
├── include
└── hypergrid
│ ├── conversions
│ ├── laserscan_converter.hpp
│ └── lidar_converter.hpp
│ ├── costmap_layer.hpp
│ ├── gridmap.hpp
│ └── utils
│ ├── point.hpp
│ └── raytracing.hpp
├── launch
├── laser_to_gridmap.launch
└── pcl_to_gridmap.launch
├── package.xml
└── src
├── costmap_layer.cpp
├── gridmap_test.cpp
├── hypergrid
├── conversions
│ ├── laserscan_converter.cpp
│ └── lidar_converter.cpp
├── gridmap.cpp
└── utils
│ ├── raytracing.cpp
│ └── raytracing.cu
├── laser_to_gridmap.cpp
└── pcl_to_gridmap.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | CMakeLists.txt.user
2 | CMakeLists.txt.user*
3 | CMakeCache.txt
4 | CMakeFiles
5 | CMakeScripts
6 | Testing
7 | Makefile
8 | cmake_install.cmake
9 | install_manifest.txt
10 | compile_commands.json
11 | CTestTestfile.cmake
12 | _deps
13 |
14 | devel/
15 | logs/
16 | build/
17 | bin/
18 | lib/
19 | msg_gen/
20 | srv_gen/
21 | build_isolated/
22 | devel_isolated/
23 |
24 | *.cfgc
25 | /cfg/cpp/
26 | /cfg/*.py
27 |
28 | CATKIN_IGNORE
29 |
30 | .DS_Store
31 | .cproject
32 | .project
33 | .pydevproject
34 | .vscode/
35 |
36 | *~
37 | *.orig
38 | *.pyc
39 | .#*
40 | *.cpp.autosave.*
41 |
42 | launch/costmap_launch/
43 |
44 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(hypergrid)
3 |
4 | ## Compile as C++11, supported in ROS Kinetic and newer
5 | add_compile_options(-std=c++11)
6 |
7 | ## Find catkin macros and libraries
8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
9 | ## is used, also find other catkin packages
10 | find_package(catkin REQUIRED COMPONENTS
11 | costmap_2d
12 | geometry_msgs
13 | nav_msgs
14 | pcl_conversions
15 | pcl_ros
16 | pluginlib
17 | roscpp
18 | sensor_msgs
19 | tf
20 | tf_conversions
21 | )
22 |
23 | ## System dependencies are found with CMake's conventions
24 | find_package(ArrayFire REQUIRED)
25 | find_package(CUDA)
26 |
27 |
28 | ## Uncomment this if the package has a setup.py. This macro ensures
29 | ## modules and global scripts declared therein get installed
30 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
31 | # catkin_python_setup()
32 |
33 | ################################################
34 | ## Declare ROS messages, services and actions ##
35 | ################################################
36 |
37 | ## To declare and build messages, services or actions from within this
38 | ## package, follow these steps:
39 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in
40 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
41 | ## * In the file package.xml:
42 | ## * add a build_depend tag for "message_generation"
43 | ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
44 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
45 | ## but can be declared for certainty nonetheless:
46 | ## * add a exec_depend tag for "message_runtime"
47 | ## * In this file (CMakeLists.txt):
48 | ## * add "message_generation" and every package in MSG_DEP_SET to
49 | ## find_package(catkin REQUIRED COMPONENTS ...)
50 | ## * add "message_runtime" and every package in MSG_DEP_SET to
51 | ## catkin_package(CATKIN_DEPENDS ...)
52 | ## * uncomment the add_*_files sections below as needed
53 | ## and list every .msg/.srv/.action file to be processed
54 | ## * uncomment the generate_messages entry below
55 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
56 |
57 | ## Generate messages in the 'msg' folder
58 | # add_message_files(
59 | # FILES
60 | # Message1.msg
61 | # Message2.msg
62 | # )
63 |
64 | ## Generate services in the 'srv' folder
65 | # add_service_files(
66 | # FILES
67 | # Service1.srv
68 | # Service2.srv
69 | # )
70 |
71 | ## Generate actions in the 'action' folder
72 | # add_action_files(
73 | # FILES
74 | # Action1.action
75 | # Action2.action
76 | # )
77 |
78 | ## Generate added messages and services with any dependencies listed here
79 | # generate_messages(
80 | # DEPENDENCIES
81 | # geometry_msgs# nav_msgs# sensor_msgs
82 | # )
83 |
84 | ################################################
85 | ## Declare ROS dynamic reconfigure parameters ##
86 | ################################################
87 |
88 | ## To declare and build dynamic reconfigure parameters within this
89 | ## package, follow these steps:
90 | ## * In the file package.xml:
91 | ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
92 | ## * In this file (CMakeLists.txt):
93 | ## * add "dynamic_reconfigure" to
94 | ## find_package(catkin REQUIRED COMPONENTS ...)
95 | ## * uncomment the "generate_dynamic_reconfigure_options" section below
96 | ## and list every .cfg file to be processed
97 |
98 | ## Generate dynamic reconfigure parameters in the 'cfg' folder
99 | # generate_dynamic_reconfigure_options(
100 | # cfg/DynReconf1.cfg
101 | # cfg/DynReconf2.cfg
102 | # )
103 |
104 | ###################################
105 | ## catkin specific configuration ##
106 | ###################################
107 | ## The catkin_package macro generates cmake config files for your package
108 | ## Declare things to be passed to dependent projects
109 | ## INCLUDE_DIRS: uncomment this if your package contains header files
110 | ## LIBRARIES: libraries you create in this project that dependent projects also need
111 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need
112 | ## DEPENDS: system dependencies of this project that dependent projects also need
113 | catkin_package(
114 | INCLUDE_DIRS include
115 | # LIBRARIES hypergrid
116 | # CATKIN_DEPENDS costmap_2d geometry_msgs nav_msgs pcl_conversions pcl_ros pluginlib roscpp sensor_msgs tf
117 | # DEPENDS system_lib
118 | )
119 |
120 | ###########
121 | ## Build ##
122 | ###########
123 |
124 | ## Specify additional locations of header files
125 | ## Your package locations should be listed before other locations
126 | include_directories(
127 | include
128 | ${catkin_INCLUDE_DIRS}
129 | )
130 |
131 | ## Declare a C++ library
132 | add_library(gridmap
133 | src/hypergrid/gridmap.cpp
134 | )
135 |
136 | add_library(conversions
137 | src/hypergrid/conversions/laserscan_converter.cpp
138 | src/hypergrid/conversions/lidar_converter.cpp
139 | )
140 |
141 | add_library(hypergrid_layer src/costmap_layer.cpp)
142 |
143 | ## Add cmake target dependencies of the library
144 | ## as an example, code may need to be generated before libraries
145 | ## either from message generation or dynamic reconfigure
146 | add_dependencies(gridmap ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
147 | add_dependencies(conversions ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
148 |
149 | # Manual flag to disable CUDA compilation and test CPU version
150 | # SET(CUDA_FOUND FALSE)
151 | if (${CUDA_FOUND})
152 |
153 | message(STATUS "Using custom CUDA kernels")
154 |
155 | CUDA_ADD_LIBRARY(raytracing
156 | src/hypergrid/utils/raytracing.cu
157 | )
158 | target_link_libraries(raytracing
159 | ${ArrayFire_CUDA_LIBRARIES}
160 | )
161 |
162 | target_link_libraries(gridmap
163 | raytracing
164 | ${catkin_LIBRARIES}
165 | ${ArrayFire_CUDA_LIBRARIES}
166 | )
167 |
168 | target_link_libraries(conversions
169 | gridmap
170 | ${ArrayFire_CUDA_LIBRARIES}
171 | )
172 |
173 | target_link_libraries(hypergrid_layer
174 | gridmap
175 | conversions
176 | ${catkin_LIBRARIES}
177 | ${ArrayFire_CUDA_LIBRARIES}
178 | )
179 |
180 | else()
181 |
182 | add_library(raytracing
183 | src/hypergrid/utils/raytracing.cpp
184 | )
185 | target_link_libraries(raytracing
186 | ${ArrayFire_CPU_LIBRARIES}
187 | )
188 |
189 | target_link_libraries(gridmap
190 | raytracing
191 | ${catkin_LIBRARIES}
192 | ${ArrayFire_CPU_LIBRARIES}
193 | )
194 |
195 | target_link_libraries(conversions
196 | gridmap
197 | ${ArrayFire_CPU_LIBRARIES}
198 | )
199 |
200 | target_link_libraries(hypergrid_layer
201 | gridmap
202 | conversions
203 | ${catkin_LIBRARIES}
204 | ${ArrayFire_CPU_LIBRARIES}
205 | )
206 |
207 | endif()
208 |
209 |
210 | ## Declare a C++ executable
211 | ## With catkin_make all packages are built within a single CMake context
212 | ## The recommended prefix ensures that target names across packages don't collide
213 | add_executable(gridmap_test src/gridmap_test.cpp)
214 | add_executable(laser_to_gridmap src/laser_to_gridmap.cpp)
215 | add_executable(pcl_to_gridmap src/pcl_to_gridmap.cpp)
216 |
217 | ## Rename C++ executable without prefix
218 | ## The above recommended prefix causes long target names, the following renames the
219 | ## target back to the shorter version for ease of user use
220 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
221 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
222 |
223 | ## Add cmake target dependencies of the executable
224 | ## same as for the library above
225 | add_dependencies(gridmap_test ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
226 | add_dependencies(laser_to_gridmap ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
227 | add_dependencies(pcl_to_gridmap ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
228 |
229 | ## Specify libraries to link a library or executable target against
230 | target_link_libraries(laser_to_gridmap
231 | gridmap
232 | conversions
233 | ${catkin_LIBRARIES}
234 | )
235 |
236 | target_link_libraries(pcl_to_gridmap
237 | gridmap
238 | conversions
239 | ${catkin_LIBRARIES}
240 | )
241 |
242 | target_link_libraries(gridmap_test
243 | gridmap
244 | raytracing
245 | ${catkin_LIBRARIES}
246 | )
247 |
248 | #############
249 | ## Install ##
250 | #############
251 |
252 | # all install targets should use catkin DESTINATION variables
253 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
254 |
255 | ## Mark executable scripts (Python etc.) for installation
256 | ## in contrast to setup.py, you can choose the destination
257 | # install(PROGRAMS
258 | # scripts/my_python_script
259 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
260 | # )
261 |
262 | ## Mark executables and/or libraries for installation
263 | # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
264 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
265 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
266 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
267 | # )
268 |
269 | ## Mark cpp header files for installation
270 | # install(DIRECTORY include/${PROJECT_NAME}/
271 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
272 | # FILES_MATCHING PATTERN "*.h"
273 | # PATTERN ".svn" EXCLUDE
274 | # )
275 |
276 | ## Mark other files for installation (e.g. launch and bag files, etc.)
277 | # install(FILES
278 | # # myfile1
279 | # # myfile2
280 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
281 | # )
282 |
283 | #############
284 | ## Testing ##
285 | #############
286 |
287 | ## Add gtest based cpp test target and link libraries
288 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_hypergrid.cpp)
289 | # if(TARGET ${PROJECT_NAME}-test)
290 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
291 | # endif()
292 |
293 | ## Add folders to be run by python nosetests
294 | # catkin_add_nosetests(test)
295 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hypergrid
2 |
3 | Hypergrid is a ROS package for building local maps from multiple sensors in the blink of an eye. Hypergrid relies on [Arrayfire](https://github.com/arrayfire/arrayfire), in order to parallelize the computation.
4 |
5 | ## Dependencies
6 |
7 | * [Arrayfire](https://github.com/arrayfire/arrayfire)
8 |
9 |
10 | ## What's inside
11 |
12 | ### Library
13 | Hypergrid is packaged with catkin and provides several libraries to work with grid maps and to convert the raw sensor data to this format.
14 |
15 | ### Costmap Plugin
16 | The main contribution of this package is a [costmap_2d](http://wiki.ros.org/costmap_2d/) plugin, meant to replace the default *obstacle_layer* inside the *local_costmap* of *move_base*. The typical *local_costmap_params.yaml* configuration file can be configured as follows:
17 |
18 | ```yaml
19 | local_costmap:
20 |
21 | # ...
22 |
23 | plugins:
24 | - {name: hypergrid_layer, type: "hypergrid::HypergridLayer"}
25 |
26 | hypergrid_layer:
27 | # LaserScan input topics
28 | laser_topics: ["icab1/scan"]
29 | # LiDAR PointCloud2 input topics
30 | lidar_topics: ["icab1/velodyne_points"]
31 | # Frame of the output local map
32 | map_frame_id: icab1/base_footprint
33 | # Map size (in meters)
34 | width: 100
35 | height: 100
36 | # Map resolution (in meters / cell)
37 | cell_size: 0.1
38 | # Remove floor points in pointcloud with heightmap algorithm
39 | floor_filter: true
40 | # Heightmap algorithm parameters
41 | heightmap_threshold: 0.15
42 | heightmap_cell_size: 0.25
43 | # Remove all points higher than max_height
44 | max_height: 2.5
45 | # Remove all points inside the vehicle box
46 | # All points with |x| < vehicle_box_size or |y| < vehicle_box_size will be filtered.
47 | vehicle_box_size: 2.0
48 | # Enable debug console output
49 | DEBUG: true
50 | ```
51 |
52 |
53 | ### Nodes
54 | In addition to the library and the costmap_2d plugin, Hypergrid also includes stand-alone conversion nodes, which subscribe to the sensor messages and publish the output instantaneous local map.
55 |
56 | * laser_to_gridmap: Conversion node from [LaserScan](http://docs.ros.org/melodic/api/sensor_msgs/html/msg/LaserScan.html) msgs to [OccupancyGrid](http://docs.ros.org/melodic/api/nav_msgs/html/msg/OccupancyGrid.html) maps.
57 |
58 | * pcl_to_gridmap: Conversion node from LiDAR [PointCloud2](http://docs.ros.org/melodic/api/sensor_msgs/html/msg/PointCloud2.html) msgs to [OccupancyGrid](http://docs.ros.org/melodic/api/nav_msgs/html/msg/OccupancyGrid.html) maps.
59 |
60 | The launch and configuration files are inside the [launch](launch) and [config](config) directories, respectively.
61 |
62 |
--------------------------------------------------------------------------------
/config/laser_to_gridmap.yaml:
--------------------------------------------------------------------------------
1 | height: 50
2 | width: 50
3 | cell_size: 0.5
4 | DEBUG: true
5 |
--------------------------------------------------------------------------------
/config/pcl_to_gridmap.yaml:
--------------------------------------------------------------------------------
1 | height: 50.0
2 | width: 50.0
3 | cell_size: 0.4
4 | DEBUG: true
5 | floor_filter: true
6 | heightmap_threshold: 0.15
7 | heightmap_cell_size: 0.25
8 | max_height: 2.5
9 |
--------------------------------------------------------------------------------
/costmap_plugins.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hypergrid Obstacle Layer
4 |
5 |
6 |
--------------------------------------------------------------------------------
/include/hypergrid/conversions/laserscan_converter.hpp:
--------------------------------------------------------------------------------
1 | #ifndef HYPERGRID_LASERSCAN_CONVERTER_HPP
2 | #define HYPERGRID_LASERSCAN_CONVERTER_HPP
3 |
4 | #include
5 |
6 | #include
7 | #include
8 |
9 |
10 | namespace hypergrid
11 | {
12 |
13 | class LaserScanConverter
14 | {
15 | public:
16 |
17 | /* Smart Pointers typedefs */
18 | typedef std::shared_ptr Ptr;
19 | typedef std::shared_ptr ConstPtr;
20 |
21 | /* Constructor */
22 | LaserScanConverter(double width, double height, double cell_size,
23 | geometry_msgs::Pose origin = geometry_msgs::Pose(),
24 | std::string map_frame_id = "base_footprint", bool DEBUG_ = true);
25 |
26 | /* Convert a sensor_msgs::LaserScan to a hypergrid::GridMap */
27 | GridMap convert(const sensor_msgs::LaserScan& scan_msg, const tf::StampedTransform transform) const;
28 | GridMap convert(const sensor_msgs::LaserScanPtr& scan_msg, const tf::StampedTransform transform) const;
29 | GridMap convert(const sensor_msgs::LaserScanConstPtr& scan_msg, const tf::StampedTransform transform) const;
30 |
31 | protected:
32 | double width_;
33 | double height_;
34 | double cell_size_;
35 | geometry_msgs::Pose origin_;
36 | std::string map_frame_id_;
37 | bool DEBUG_;
38 | };
39 |
40 |
41 | } // hypergrid namespace
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/include/hypergrid/conversions/lidar_converter.hpp:
--------------------------------------------------------------------------------
1 | #ifndef HYPERGRID_LIDAR_CONVERTER_HPP
2 | #define HYPERGRID_LIDAR_CONVERTER_HPP
3 |
4 | #include
5 |
6 | #include
7 | #include
8 |
9 |
10 | namespace hypergrid
11 | {
12 |
13 | class LIDARConverter
14 | {
15 | public:
16 |
17 | /* Smart Pointers typedefs */
18 | typedef std::shared_ptr Ptr;
19 | typedef std::shared_ptr ConstPtr;
20 |
21 | /* Constructor */
22 | LIDARConverter(double width, double height, double cell_size,
23 | geometry_msgs::Pose origin = geometry_msgs::Pose(),
24 | std::string map_frame_id = "base_footprint",
25 | double heightmap_threshold = 0.15,
26 | double heightmap_cell_size = 0.25,
27 | double max_height = 2.5,
28 | double vehicle_box_size = 2.0,
29 | bool DEBUG = true);
30 |
31 | /* Convert a sensor_msgs::PointCloud2 to a hypergrid::GridMap */
32 | GridMap convert(sensor_msgs::PointCloud2& cloud_msg, const tf::StampedTransform transform) const;
33 | GridMap convert(sensor_msgs::PointCloud2Ptr& cloud_msg, const tf::StampedTransform transform) const;
34 |
35 | /*remove floor */
36 | void remove_floor(af::array& cloud) const;
37 |
38 | protected:
39 | double width_;
40 | double height_;
41 | double cell_size_;
42 | geometry_msgs::Pose origin_;
43 | std::string map_frame_id_;
44 |
45 | double heightmap_threshold_;
46 | double heightmap_cell_size_;
47 | double max_height_;
48 | double vehicle_box_size_;
49 | bool DEBUG_;
50 | };
51 |
52 |
53 | } // hypergrid namespace
54 |
55 | #endif
56 |
--------------------------------------------------------------------------------
/include/hypergrid/costmap_layer.hpp:
--------------------------------------------------------------------------------
1 | #ifndef HYPERGRID_COSTMAP_LAYER_H_
2 | #define HYPERGRID_COSTMAP_LAYER_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 | #include
12 | #include
13 |
14 |
15 | namespace hypergrid
16 | {
17 |
18 | class HypergridLayer : public costmap_2d::Layer, public costmap_2d::Costmap2D
19 | {
20 | public:
21 | HypergridLayer();
22 |
23 | virtual void onInitialize();
24 | virtual void updateBounds(double robot_x, double robot_y, double robot_yaw,
25 | double* min_x, double* min_y, double* max_x, double* max_y);
26 | virtual void updateCosts(costmap_2d::Costmap2D& master_grid, int min_i, int min_j,
27 | int max_i, int max_j);
28 | bool isDiscretized()
29 | {
30 | return true;
31 | }
32 |
33 | virtual void matchSize();
34 |
35 | void laser_callback(const sensor_msgs::LaserScanPtr scan_msg);
36 | void lidar_callback(sensor_msgs::PointCloud2Ptr cloud_msg);
37 |
38 |
39 |
40 | private:
41 | std::vector new_maps_;
42 | std::vector laserscan_subs_;
43 | std::vector lidar_subs_;
44 | ros::Publisher merged_map_pub_;
45 | std::vector laser_topics_;
46 | std::vector lidar_topics_;
47 | tf::TransformListener* tf_listener_;
48 | hypergrid::LaserScanConverter* laser_converter_;
49 | hypergrid::LIDARConverter* lidar_converter_;
50 |
51 | double width_;
52 | double height_;
53 | double cell_size_;
54 | double heightmap_threshold_;
55 | double heightmap_cell_size_;
56 | double max_height_;
57 | double vehicle_box_size_;
58 | bool rolling_window_;
59 | std::string map_frame_id_;
60 | bool DEBUG_;
61 |
62 | };
63 |
64 |
65 | } // hypergrid namespace
66 |
67 | #endif
68 |
--------------------------------------------------------------------------------
/include/hypergrid/gridmap.hpp:
--------------------------------------------------------------------------------
1 | #ifndef HYPERGRID_GRIDMAP_HPP
2 | #define HYPERGRID_GRIDMAP_HPP
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include
20 | #include
21 |
22 |
23 | namespace hypergrid
24 | {
25 |
26 | class GridMap
27 | {
28 | public:
29 | /* Map labels.
30 | Please note that cells can have values in the range [0-100] to indicate occupation probability.
31 | */
32 | enum Label
33 | {
34 | UNKNOWN = -1,
35 | FREE = 0,
36 | OBSTACLE = 100
37 | };
38 |
39 | /* Smart Pointers typedefs */
40 | typedef std::shared_ptr Ptr;
41 | typedef std::shared_ptr ConstPtr;
42 |
43 | /* Constructors */
44 | GridMap();
45 | GridMap(double width, double height, double cell_size,
46 | geometry_msgs::Pose origin = geometry_msgs::Pose(),
47 | std::string map_frame_id = "base_footprint");
48 | GridMap(const nav_msgs::OccupancyGrid map_msg);
49 | GridMap(const nav_msgs::OccupancyGridConstPtr map_msg);
50 | /* Copy constructor */
51 | GridMap(const GridMap& other_map);
52 | /* Move constructor */
53 | GridMap(GridMap&& other_map) noexcept;
54 | /* Assignement operator */
55 | GridMap& operator = (const GridMap& other_map);
56 |
57 | /* Bool conversion operator to check if the map has been initialized */
58 | inline explicit operator bool() const {return !grid.isempty();}
59 |
60 | /* Convert to ROS nav_msgs::OccupancyGrid msg */
61 | void toMapMsg(nav_msgs::OccupancyGrid& map_msg);
62 | nav_msgs::OccupancyGrid toMapMsg();
63 |
64 | /* Resize the map to a different resolution (size in meters remains, number of cells changes) */
65 | void resize(double output_cell_size);
66 | /* Apply a rotation to the map */
67 | void rotate(double angle);
68 |
69 | /* Clear the map and set all cells to UNKNOWN */
70 | void clear();
71 |
72 | /* Return a copy of the grid matrix */
73 | inline double getWidth() const {return width_;}
74 | inline double getHeight() const {return height_;}
75 | inline double getCellSize() const {return cell_size_;}
76 | inline std::string getMapFrameId() const {return map_frame_id_;}
77 | inline geometry_msgs::Pose getOrigin() const {return origin_;}
78 | inline void setOrigin(double x, double y ){ origin_.position.x = x; origin_.position.y = y; }
79 | /* Check if the cell / local coordinates lay on the map */
80 | template
81 | inline bool isCellInside(T x, T y) {return (x >= 0 && y >= 0 && x < grid.dims(0) && y < grid.dims(1));}
82 | inline bool isCellInside(Cell c) {return isCellInside(c.x, c.y);}
83 | inline af::array isCellInside(af::array obs){return (obs(af::span,0) >= 0 && obs(af::span,1) >= 0 && obs(af::span,0) < grid.dims(0)
84 | && obs(af::span,1) < grid.dims(1)); }
85 |
86 | template
87 | inline bool isLocalInside(T x, T y) {return isCellInside(cellCoordsFromLocal(x, y));}
88 | template
89 | inline bool isLocalInside(Point p) {return isLocalInside(p.x, p.y);}
90 |
91 | /* Direct cell access */
92 | inline af::array::array_proxy operator[](Cell c) {return grid(c.x, c.y);}
93 | inline af::array::array_proxy cell(size_t x, size_t y) {return grid(x, y);}
94 | inline af::array::array_proxy cell(Cell c) {return grid(c.x, c.y);}
95 |
96 | /* Cell coordinates from local coordinates */
97 | template
98 | Cell cellCoordsFromLocal(T x, T y);
99 | template
100 | inline Cell cellCoordsFromLocal(Point p) {return cellCoordsFromLocal(p.x, p.y);}
101 | af::array cellCoordsFromLocal(af::array local_points);
102 |
103 | /* Local coordinates from cell coords */
104 | template
105 | Point localCoordsFromCell(size_t x, size_t y);
106 | template
107 | inline Point localCoordsFromCell(Cell c) {return localCoordsFromCell(c.x, c.y);}
108 |
109 | /* Cell access from local coordinates */
110 | template
111 | af::array::array_proxy cellFromLocal(T x, T y);
112 | template
113 | inline af::array::array_proxy cellFromLocal(Point p) {return cellFromLocal(p.x, p.y);}
114 |
115 | /* Add a free line from the vehicle to the given cell */
116 | void addFreeLine(Cell end);
117 | inline void addFreeLine(size_t x,size_t y) {addFreeLine(Cell(x,y));}
118 | /* Add a free line from the start cell to the end cell */
119 | void addFreeLine(Cell start, Cell end);
120 | inline void addFreeLine(size_t x1, size_t y1, size_t x2, size_t y2)
121 | {
122 | addFreeLine(Cell(x1, y1), Cell(x2, y2));
123 | }
124 | /* Add multiple free lines from a given point to given end points */
125 | void addFreeLines(Cell start, af::array endpoints);
126 |
127 | /* 2D matrix containing the map. Data type is 32 bit signed integer to avoid conversion in the GPU. */
128 | af::array grid;
129 |
130 | protected:
131 |
132 | double width_; // meters
133 | double height_; // meters
134 | double cell_size_; // meters / cell
135 |
136 | std::string map_frame_id_;
137 | geometry_msgs::Pose origin_;
138 |
139 | /* Apply the inverse map origin transformation to get the cell (in meters) from a local point */
140 | Pointd originFromLocal_(Pointd src) const;
141 | /* Apply the map origin transformation to get the local point from a cell point (in meters) */
142 | Pointd localFromOrigin_(Pointd src) const;
143 | /* Get the homogeneous matrix of the origin transform */
144 | af::array getOriginTransform_() const;
145 |
146 | };
147 |
148 |
149 | } // hypergrid namespace
150 |
151 | #endif
152 |
--------------------------------------------------------------------------------
/include/hypergrid/utils/point.hpp:
--------------------------------------------------------------------------------
1 | #ifndef HYPERGRID_POINT_HPP
2 | #define HYPERGRID_POINT_HPP
3 |
4 | #include
5 |
6 | namespace hypergrid
7 | {
8 |
9 | template
10 | class Point
11 | {
12 | public:
13 | T x;
14 | T y;
15 |
16 | /* Empty constructor */
17 | Point()
18 | {
19 | this->x = 0.0;
20 | this->y = 0.0;
21 | }
22 | /*Create constractor*/
23 | Point(T x, T y){
24 | this->x = x;
25 | this->y = y;
26 | }
27 | /* Copy constructor */
28 | Point(const Point& other_point)
29 | {
30 | this->x = other_point.x;
31 | this->y = other_point.y;
32 | }
33 | /* Move constructor */
34 | Point(Point&& other_point) noexcept
35 | {
36 | this->x = other_point.x;
37 | this->y = other_point.y;
38 | }
39 | /* Assignement operator */
40 | Point& operator = (const Point& other_point)
41 | {
42 | // check for self-assignment
43 | if(&other_point == this) return *this;
44 |
45 | this->x = other_point.x;
46 | this->y = other_point.y;
47 | return *this;
48 | }
49 |
50 | /* Conversions */
51 | std::pair toStdPair()
52 | {
53 | return {this->x, this->y};
54 | }
55 |
56 | std::string str()
57 | {
58 | return "[" + std::to_string(this->x) + ", " + std::to_string(this->y) + "]";
59 | }
60 |
61 | };
62 |
63 | /* Point arithmetic operators */
64 | template
65 | inline Point operator+(Point p1, Point p2) {return Point(p1.x + p2.x, p1.y + p2.y);}
66 |
67 | template
68 | inline Point operator-(Point p1, Point p2) {return Point(p1.x - p2.x, p1.y - p2.y);}
69 |
70 | template
71 | inline Point operator+(Point p, S scalar) {return Point(p.x + scalar, p.y + scalar);}
72 |
73 | template
74 | inline Point operator+(S scalar, Point p) {return (p + scalar);}
75 |
76 | template
77 | inline Point operator-(Point p, S scalar) {return Point(p.x - scalar, p.y - scalar);}
78 |
79 | template
80 | inline Point operator*(Point p, S scalar) {return Point(p.x * scalar, p.y * scalar);}
81 |
82 | template
83 | inline Point operator*(S scalar, Point p) {return (p * scalar);}
84 |
85 | template
86 | inline Point operator/(Point p, S scalar) {return (scalar == 0.0 ?
87 | Point(0,0) :
88 | Point(p.x / scalar, p.y / scalar));}
89 |
90 | template
91 | inline Point operator*=(Point p, S scalar) {return p * scalar;}
92 |
93 | template
94 | inline Point operator/=(Point p, S scalar) {return p / scalar;}
95 |
96 |
97 | using Cell = Point;
98 | using Pointf = Point;
99 | using Pointd = Point;
100 |
101 | } // hypergrid namespace
102 |
103 | #endif
104 |
--------------------------------------------------------------------------------
/include/hypergrid/utils/raytracing.hpp:
--------------------------------------------------------------------------------
1 | #ifndef HYPERGRID_RAYTRACING_HPP
2 | #define HYPERGRID_RAYTRACING_HPP
3 |
4 | #include
5 |
6 | namespace hypergrid
7 | {
8 | void add_lines(af::array& grid, int value,
9 | size_t start_x, size_t start_y,
10 | af::array endpoints);
11 |
12 | void add_line(af::array& grid, int value,
13 | size_t start_x, size_t start_y,
14 | size_t end_x, size_t end_y);
15 |
16 | /*
17 | DDA algorithm to draw line from one point to another in the occupancy grid.
18 | */
19 | void DDA(af::array& grid, int value,
20 | float start_x, float start_y,
21 | float end_x, float end_y);
22 |
23 | } // hypergrid namespace
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/launch/laser_to_gridmap.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/launch/pcl_to_gridmap.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | hypergrid
4 | 0.0.0
5 | The hypergrid package
6 |
7 |
8 |
9 |
10 | Francisco Miguel Moreno
11 |
12 |
13 |
14 |
15 |
16 | TODO
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Francisco Miguel Moreno
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | catkin
52 | costmap_2d
53 | geometry_msgs
54 | nav_msgs
55 | pcl_conversions
56 | pcl_ros
57 | pluginlib
58 | roscpp
59 | sensor_msgs
60 | tf
61 | costmap_2d
62 | geometry_msgs
63 | nav_msgs
64 | pcl_conversions
65 | pcl_ros
66 | pluginlib
67 | roscpp
68 | sensor_msgs
69 | tf
70 | costmap_2d
71 | geometry_msgs
72 | nav_msgs
73 | pcl_conversions
74 | pcl_ros
75 | pluginlib
76 | roscpp
77 | sensor_msgs
78 | tf
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/costmap_layer.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | const std::string TIMING_PATH = "/home/sobky/costmap_output";
5 |
6 | PLUGINLIB_EXPORT_CLASS(hypergrid::HypergridLayer, costmap_2d::Layer)
7 |
8 | namespace hypergrid
9 | {
10 |
11 | HypergridLayer::HypergridLayer() {}
12 |
13 | void HypergridLayer::onInitialize()
14 | {
15 | af::info();
16 | ros::NodeHandle private_nh("~/" + name_);
17 | ros::NodeHandle public_nh;
18 |
19 | current_ = true;
20 | rolling_window_ = layered_costmap_->isRolling();
21 |
22 | default_value_ = costmap_2d::NO_INFORMATION;
23 | matchSize();
24 |
25 | tf_listener_ = new tf::TransformListener();
26 |
27 | private_nh.param("map_frame_id", map_frame_id_, "base_footprint");
28 | private_nh.param("height", height_, 50.0);
29 | private_nh.param("width", width_, 50.0);
30 | private_nh.param("cell_size", cell_size_, 0.2);
31 | private_nh.param("DEBUG", DEBUG_, false);
32 | private_nh.param("heightmap_threshold", heightmap_threshold_, 0.15);
33 | private_nh.param("heightmap_cell_size", heightmap_cell_size_, 0.25);
34 | private_nh.param("max_height", max_height_, 2.5);
35 | private_nh.param("vehicle_box_size", vehicle_box_size_, 2.0);
36 | private_nh.getParam("laser_topics", laser_topics_);
37 | std::cout << "laser topics size: " << laser_topics_.size() << std::endl;
38 | private_nh.getParam("lidar_topics", lidar_topics_);
39 | std::cout << "lidar topics size: " << lidar_topics_.size() << std::endl;
40 |
41 |
42 | geometry_msgs::Pose origin;
43 | origin.position.x = - (width_ / 2) + cell_size_;
44 | origin.position.y = - (height_ / 2) + cell_size_;
45 | origin.orientation.w = 1;
46 |
47 | laser_converter_ = new hypergrid::LaserScanConverter(width_, height_, cell_size_,
48 | origin, map_frame_id_, DEBUG_);
49 |
50 | lidar_converter_ = new hypergrid::LIDARConverter(width_, height_, cell_size_,
51 | origin, map_frame_id_,
52 | heightmap_threshold_,
53 | heightmap_cell_size_,
54 | max_height_,
55 | vehicle_box_size_, DEBUG_);
56 |
57 | laserscan_subs_.resize(laser_topics_.size());
58 | for (int i = 0; i < laser_topics_.size(); ++i)
59 | {
60 | laserscan_subs_[i] = public_nh.subscribe(laser_topics_[i], 5, &HypergridLayer::laser_callback, this);
61 | if (DEBUG_) std::cout << "Subscribed to " << laserscan_subs_[i].getTopic() << std::endl;
62 | }
63 |
64 | lidar_subs_.resize(lidar_topics_.size());
65 | for (int i = 0; i < lidar_topics_.size(); ++i)
66 | {
67 | lidar_subs_[i] = public_nh.subscribe(lidar_topics_[i], 5, &HypergridLayer::lidar_callback, this);
68 | if (DEBUG_) std::cout << "Subscribed to " << lidar_subs_[i].getTopic() << std::endl;
69 | }
70 |
71 | merged_map_pub_ = public_nh.advertise("hypergrid/laser_to_mergedgridmap", 2);
72 | }
73 |
74 | void HypergridLayer::matchSize()
75 | {
76 | Costmap2D* master = layered_costmap_->getCostmap();
77 | resizeMap(master->getSizeInCellsX(), master->getSizeInCellsY(),
78 | master->getResolution(), master->getOriginX(), master->getOriginY());
79 | }
80 |
81 | void HypergridLayer::updateBounds(double robot_x, double robot_y, double robot_yaw,
82 | double* min_x, double* min_y, double* max_x, double* max_y)
83 | {
84 | // auto t0 = std::chrono::high_resolution_clock::now();
85 |
86 | if (rolling_window_)
87 | {
88 | updateOrigin(robot_x - getSizeInMetersX() / 2, robot_y - getSizeInMetersY() / 2);
89 | }
90 |
91 | *min_x = std::min(*min_x, getOriginX());
92 | *min_y = std::min(*min_y, getOriginY());
93 | *max_x = std::max(*max_x, getSizeInMetersX() + getOriginX());
94 | *max_y = std::max(*max_y, getSizeInMetersY() + getOriginY());
95 |
96 | // auto end = std::chrono::high_resolution_clock::now();
97 | // double tt = std::chrono::duration_cast(end - t0).count();
98 | // std::ofstream time_file(TIMING_PATH + "/hypergrid_layer_updateBounds.csv", std::ios_base::app);
99 | // time_file << tt << std::setprecision(std::numeric_limits::digits10 + 1) << std::endl;
100 | // time_file.close();
101 | }
102 |
103 | void HypergridLayer::updateCosts(costmap_2d::Costmap2D& master_grid, int min_i, int min_j,
104 | int max_i, int max_j)
105 | {
106 | // auto t0 = std::chrono::high_resolution_clock::now();
107 |
108 | if(new_maps_.size()==0)
109 | {
110 | ROS_WARN("Now new map received yet: costmap will NOT be updated");
111 | return;
112 | }
113 | else if (DEBUG_) std::cout << "Number of maps: " << new_maps_.size() << std::endl;
114 |
115 |
116 | hypergrid::GridMap Merged_gridmap = new_maps_[0];
117 | merged_map_pub_.publish(Merged_gridmap.toMapMsg());
118 | for (int i = 1; i < new_maps_.size(); i++)
119 | {
120 | Merged_gridmap.grid = af::max(Merged_gridmap.grid, new_maps_[i].grid);
121 | }
122 |
123 | hypergrid::Cell coords = Merged_gridmap.cellCoordsFromLocal(0, 0);
124 | Merged_gridmap.grid.eval();
125 |
126 | int width_cells = this->width_ / this->cell_size_;
127 | int height_cells = this->height_ / this->cell_size_;
128 |
129 | // Lookup table
130 | unsigned char gridmap_costmap_lut[256];
131 | for (int i = 0; i < 256; ++i) gridmap_costmap_lut[i] = costmap_2d::NO_INFORMATION;
132 | gridmap_costmap_lut[(unsigned char)hypergrid::GridMap::OBSTACLE] = costmap_2d::LETHAL_OBSTACLE;
133 | gridmap_costmap_lut[(unsigned char)hypergrid::GridMap::FREE] = costmap_2d::FREE_SPACE;
134 |
135 | unsigned char* master_grid_ptr = master_grid.getCharMap();
136 | int* merged_grid_ptr = Merged_gridmap.grid.host();
137 |
138 | for (int i = 0; i < width_cells * height_cells; ++i)
139 | {
140 | master_grid_ptr[i] = gridmap_costmap_lut[(unsigned char)merged_grid_ptr[i]];
141 | }
142 |
143 | new_maps_.clear();
144 |
145 | // auto end = std::chrono::high_resolution_clock::now();
146 | // double tt = std::chrono::duration_cast(end - t0).count();
147 | // std::ofstream time_file(TIMING_PATH + "/hypergrid_layer_updateCosts.csv", std::ios_base::app);
148 | // time_file << tt << std::setprecision(std::numeric_limits::digits10 + 1) << std::endl;
149 | // time_file.close();
150 | }
151 |
152 | void HypergridLayer::laser_callback(const sensor_msgs::LaserScanPtr scan_msg)
153 | {
154 | // auto t0 = std::chrono::high_resolution_clock::now();
155 |
156 | tf::StampedTransform laser_footprint_transform;
157 | try
158 | {
159 | tf_listener_->lookupTransform(map_frame_id_, scan_msg->header.frame_id, ros::Time(0), laser_footprint_transform);
160 | }
161 | catch(tf::TransformException &ex)
162 | {
163 | ROS_ERROR("%s", ex.what());
164 | return;
165 | }
166 |
167 | hypergrid::GridMap gridmap = laser_converter_->convert(scan_msg, laser_footprint_transform);
168 | new_maps_.push_back(gridmap);
169 |
170 | // auto end = std::chrono::high_resolution_clock::now();
171 | // double tt = std::chrono::duration_cast(end - t0).count();
172 | // std::ofstream time_file(TIMING_PATH + "/hypergrid_layer_laser_callback.csv", std::ios_base::app);
173 | // time_file << tt << std::setprecision(std::numeric_limits::digits10 + 1) << std::endl;
174 | // time_file.close();
175 | }
176 |
177 | void HypergridLayer::lidar_callback(sensor_msgs::PointCloud2Ptr cloud_msg)
178 | {
179 | // auto t0 = std::chrono::high_resolution_clock::now();
180 |
181 | tf::StampedTransform lidar_footprint_transform;
182 | try
183 | {
184 | tf_listener_->lookupTransform(map_frame_id_, cloud_msg->header.frame_id, ros::Time(0), lidar_footprint_transform);
185 | }
186 | catch(tf::TransformException &ex)
187 | {
188 | ROS_ERROR("%s", ex.what());
189 | return;
190 | }
191 |
192 | new_maps_.push_back(lidar_converter_->convert(cloud_msg, lidar_footprint_transform));
193 |
194 | // auto end = std::chrono::high_resolution_clock::now();
195 | // double tt = std::chrono::duration_cast(end - t0).count();
196 | // std::ofstream time_file(TIMING_PATH + "/hypergrid_layer_lidar_callback.csv", std::ios_base::app);
197 | // time_file << tt << std::setprecision(std::numeric_limits::digits10 + 1) << std::endl;
198 | // time_file.close();
199 | }
200 |
201 | } // end namespace
202 |
--------------------------------------------------------------------------------
/src/gridmap_test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 |
5 | int main(int argc, char **argv)
6 | {
7 | af::info();
8 |
9 | ros::init(argc, argv, "gridmap_test");
10 | ros::NodeHandle public_nh, private_nh("~");
11 |
12 | ros::Publisher map_pub = public_nh.advertise("gridmap_test", 5);
13 | ros::Publisher map_pub_2 = public_nh.advertise("gridmap_test_2", 5);
14 |
15 | af::array test_rand_array = af::randu(10, 10, f32);
16 | // af_print(test_rand_array);
17 |
18 | double width = 28.0;
19 | double height = 22.0;
20 | double cell_size = 2.0;
21 | geometry_msgs::Pose origin;
22 | origin.position.x = - (width /2);
23 | origin.position.y = - (height /2);
24 |
25 | hypergrid::GridMap gridmap(width, height, cell_size, origin);
26 | hypergrid::GridMap gridmap2(width, height, cell_size, origin);
27 |
28 | // Set some cells
29 | /*
30 | gridmap.grid(0, 0) = hypergrid::GridMap::FREE;
31 | gridmap.grid(4, 1) = hypergrid::GridMap::FREE;
32 | gridmap.grid(0, 1) = hypergrid::GridMap::OBSTACLE;
33 | gridmap.grid(1, 1) = hypergrid::GridMap::OBSTACLE;
34 | gridmap.grid(2, 1) = hypergrid::GridMap::OBSTACLE;
35 | gridmap.grid(5, 3) = hypergrid::GridMap::OBSTACLE;
36 | gridmap.grid(0, 3) = hypergrid::GridMap::OBSTACLE;
37 | gridmap.grid(0, 2) = hypergrid::GridMap::OBSTACLE;
38 | gridmap.grid(1, 3) = hypergrid::GridMap::OBSTACLE;
39 | gridmap.grid(1, 2) = hypergrid::GridMap::OBSTACLE;
40 | */
41 | // hypergrid::Cell c = gridmap.cellCoordsFromLocal(1, -1);
42 |
43 |
44 | //obstacles = af::join(0,obesracle_af,obstacles);
45 |
46 | // gridmap.grid(c.x,c.y) = hypergrid::GridMap::OBSTACLE;
47 | // gridmap.grid(6, 7) = hypergrid::GridMap::OBSTACLE;
48 |
49 | // af_print(gridmap.grid);
50 |
51 |
52 | float a[] = {1,2,3,4};
53 | af::array a_arr(4,a);
54 |
55 | float b[] = {0,5,6,7};
56 | af::array b_arr(4,b);
57 |
58 | af_print(af::min(a_arr,b_arr));
59 |
60 |
61 | gridmap.addFreeLine(gridmap.cellCoordsFromLocal(hypergrid::Point(10, 5)));
62 | gridmap.addFreeLine(gridmap.cellCoordsFromLocal(hypergrid::Point(10, -10)));
63 | gridmap.addFreeLine(gridmap.cellCoordsFromLocal(hypergrid::Point(-5, 10)));
64 | gridmap.addFreeLine(gridmap.cellCoordsFromLocal(hypergrid::Point(-10, -10)));
65 | gridmap.addFreeLine(gridmap.cellCoordsFromLocal(hypergrid::Point(-11, -9)));
66 |
67 | gridmap.cellFromLocal(hypergrid::Point(10, 5)) = hypergrid::GridMap::OBSTACLE;
68 | gridmap.cellFromLocal(hypergrid::Point(10, -10)) = hypergrid::GridMap::OBSTACLE;
69 | gridmap.cellFromLocal(hypergrid::Point(-5, 10)) = hypergrid::GridMap::OBSTACLE;
70 | gridmap.cellFromLocal(hypergrid::Point(-10, -10)) = hypergrid::GridMap::OBSTACLE;
71 | gridmap.cellFromLocal(hypergrid::Point(-11, -9)) = hypergrid::GridMap::OBSTACLE;
72 |
73 |
74 | // hypergrid::Cell start = gridmap2.cellCoordsFromLocal(0, 0);
75 | // hypergrid::Cell end = gridmap2.cellCoordsFromLocal(10, 5);
76 |
77 | // hypergrid::LineIterator it(gridmap2.grid, start, end, 4);
78 |
79 | // for (int i = 0; i < it.size(); i++, it++)
80 | // {
81 | // // std::cout << "Iterator pos: " << it().str() << std::endl;
82 | // gridmap2[it()] = hypergrid::GridMap::FREE;
83 | // }
84 | // draw_line_local(gridmap2, hypergrid::Point(0, 0), hypergrid::Point(10, 5));
85 | // draw_line_local(gridmap2, hypergrid::Point(0, 0), hypergrid::Point(10, -10));
86 | // draw_line_local(gridmap2, hypergrid::Point(0, 0), hypergrid::Point(-5, 10));
87 | // draw_line_local(gridmap2, hypergrid::Point(0, 0), hypergrid::Point(-10, -10));
88 | // draw_line_local(gridmap2, hypergrid::Point(0, 0), hypergrid::Point(-11, -9));
89 |
90 | hypergrid::Cell start_c = gridmap2.cellCoordsFromLocal(hypergrid::Point(0, 0));
91 | af::array endpoints(5, 2, s32);
92 | endpoints(0, 0) = gridmap2.cellCoordsFromLocal(hypergrid::Point(10, 5)).x;
93 | endpoints(0, 1) = gridmap2.cellCoordsFromLocal(hypergrid::Point(10, 5)).y;
94 | endpoints(1, 0) = gridmap2.cellCoordsFromLocal(hypergrid::Point(10, -10)).x;
95 | endpoints(1, 1) = gridmap2.cellCoordsFromLocal(hypergrid::Point(10, -10)).y;
96 | endpoints(2, 0) = gridmap2.cellCoordsFromLocal(hypergrid::Point(-5, 10)).x;
97 | endpoints(2, 1) = gridmap2.cellCoordsFromLocal(hypergrid::Point(-5, 10)).y;
98 | endpoints(3, 0) = gridmap2.cellCoordsFromLocal(hypergrid::Point(-10, -10)).x;
99 | endpoints(3, 1) = gridmap2.cellCoordsFromLocal(hypergrid::Point(-10, -10)).y;
100 | endpoints(4, 0) = gridmap2.cellCoordsFromLocal(hypergrid::Point(-11, -9)).x;
101 | endpoints(4, 1) = gridmap2.cellCoordsFromLocal(hypergrid::Point(-11, -9)).y;
102 | af_print(endpoints);
103 |
104 | hypergrid::add_lines(gridmap2.grid, hypergrid::GridMap::FREE, start_c.x, start_c.y, endpoints);
105 |
106 | gridmap2.cellFromLocal(hypergrid::Point(10, 5)) = hypergrid::GridMap::OBSTACLE;
107 | gridmap2.cellFromLocal(hypergrid::Point(10, -10)) = hypergrid::GridMap::OBSTACLE;
108 | gridmap2.cellFromLocal(hypergrid::Point(-5, 10)) = hypergrid::GridMap::OBSTACLE;
109 | gridmap2.cellFromLocal(hypergrid::Point(-10, -10)) = hypergrid::GridMap::OBSTACLE;
110 | gridmap2.cellFromLocal(hypergrid::Point(-11, -9)) = hypergrid::GridMap::OBSTACLE;
111 |
112 | af_print(gridmap2.grid);
113 | // int example1[] = {1,2,3,4,5,6,7,8,9};
114 | // int example2[] = {11,22,33,44,55,66,77,88,99};
115 | // int example3[] = {111,222,333,444,555,666,777,888,999};
116 |
117 | // af::array join1(3,3,example1);
118 | // af::array join2(3,3,example2);
119 | // af::array join3(3,3,example3);
120 |
121 | // af_print(af::join(0,join1,join2));
122 | // af_print(af::join(1,join1,join2));
123 | // af_print(af::join(2,join1,join2));
124 |
125 | /*
126 | gfor(af::seq i ,2,2 ,join1.dims(0))
127 | {
128 | af_print(join1(i));
129 | }
130 | */
131 |
132 | // gridmap.clear();
133 |
134 | // std::cout << "Local [1, 1] -> Cell coords " << gridmap.cellCoordsFromLocal(1.0, 1.0).str() << std::endl;
135 | // std::cout << "Local [1, 1] cell: " << gridmap.cellFromLocal(1.0, 1.0).scalar() << std::endl;
136 |
137 | // size_t a = 4;
138 | // size_t b = 3;
139 | // c = hypergrid::Cell(a, b);
140 | // hypergrid::Point p = gridmap.localCoordsFromCell(a, b);
141 | // std::cout << "Cell coords [4, 3] -> Local " << gridmap.localCoordsFromCell(a, b).str() << std::endl;
142 |
143 | // Test direct cell access
144 | // std::cout << "Cell [4, 3]: " << gridmap[c].scalar() << std::endl;
145 | // std::cout << "Cell [4, 3]: " << gridmap.cell(c).scalar() << std::endl;
146 | // std::cout << "Cell [4, 3]: " << gridmap.cell(a, b).scalar() << std::endl;
147 | // std::cout << "Cell from local [1.5, 1.5]: " << gridmap.cellFromLocal(1.5, 1.5).scalar() << std::endl;
148 |
149 | // Direct cell modification
150 | // gridmap[c] = hypergrid::GridMap::FREE;
151 | // gridmap.cellFromLocal(1.5, 1.5) = hypergrid::GridMap::FREE;
152 | // std::cout << "Cell [4, 3]: " << gridmap[c].scalar() << std::endl;
153 | // std::cout << "Cell from local [1.5, 1.5]: " << gridmap.cellFromLocal(1.5, 1.5).scalar() << std::endl;
154 |
155 | // gridmap.rotate(af::Pi/4);
156 | // gridmap.resize(1);
157 |
158 | // hypergrid::Cell z(3,2);
159 | // gridmap.localCoordsFromCell(a,b);
160 |
161 | nav_msgs::OccupancyGrid map_msg = gridmap.toMapMsg();
162 | nav_msgs::OccupancyGrid map_msg2 = gridmap2.toMapMsg();
163 |
164 | // hypergrid::GridMap converted_grid(map_msg);
165 | // af_print(converted_grid.grid);
166 |
167 | ros::Rate rate(1);
168 | while(ros::ok())
169 | {
170 | map_pub.publish(map_msg);
171 | map_pub_2.publish(map_msg2);
172 | rate.sleep();
173 | }
174 |
175 | return 0;
176 | }
--------------------------------------------------------------------------------
/src/hypergrid/conversions/laserscan_converter.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 |
4 | namespace hypergrid
5 | {
6 |
7 | /* Constructor */
8 | LaserScanConverter::LaserScanConverter(double width, double height, double cell_size,
9 | geometry_msgs::Pose origin, std::string map_frame_id, bool DEBUG) :
10 | origin_(origin)
11 | {
12 | width_ = width;
13 | height_ = height;
14 | cell_size_ = cell_size;
15 | map_frame_id_ = map_frame_id;
16 | DEBUG_ = DEBUG;
17 | }
18 |
19 | /* Convert a sensor_msgs::LaserScan to a hypergrid::GridMap */
20 | GridMap LaserScanConverter::convert(const sensor_msgs::LaserScan& scan_msg, const tf::StampedTransform transform) const
21 | {
22 | ros::Time t0 = ros::Time::now();
23 | if (DEBUG_) std::cout << "\n------------------------\nNew laser" << std::endl;
24 |
25 | hypergrid::GridMap gridmap(width_, height_, cell_size_, origin_, map_frame_id_);
26 |
27 | af::array ranges(scan_msg.ranges.size(), 1, scan_msg.ranges.data());
28 | af::array scan_angle(scan_msg.ranges.size(), 1);
29 |
30 | af::array ranges_seq = af::seq(0, scan_msg.ranges.size() - 1);
31 | scan_angle = scan_msg.angle_min + ranges_seq * scan_msg.angle_increment;
32 |
33 | // Remove NaNs and Inf values
34 | af::array ranges_nan_inf = af::isNaN(ranges) || af::isInf(ranges);
35 | af::replace(ranges, !ranges_nan_inf, scan_msg.range_max);
36 |
37 | if (DEBUG_) std::cout << "Init time: " << ros::Time::now() - t0 << std::endl;
38 | t0 = ros::Time::now();
39 |
40 | af::array obstacles = af::constant(1.0, scan_msg.ranges.size(), 3, f64);
41 |
42 | obstacles(af::span, 0) = ranges * af::cos(scan_angle);
43 | obstacles(af::span, 1) = ranges * af::sin(scan_angle);
44 |
45 | // Get Rotation and translation from TF transform
46 | tf::Vector3 trans = transform.getOrigin();
47 | double theta = tf::getYaw(transform.getRotation());
48 | double t_r_array[] = {std::cos(theta), std::sin(theta), 0,
49 | -std::sin(theta), std::cos(theta), 0,
50 | trans.getX(), trans.getY(), 1};
51 | af::array transformation(3, 3, t_r_array);
52 | // Transform the obstacles to the map frame
53 | obstacles = af::matmul(transformation, obstacles.T()).T();
54 |
55 | if (DEBUG_) std::cout << "Obstacles transform time: " << ros::Time::now() - t0 << std::endl;
56 | t0 = ros::Time::now();
57 |
58 | // Get obstacle cell coordinates
59 | af::array obstacle_coords = gridmap.cellCoordsFromLocal(obstacles);
60 |
61 | // Remove outside obstacles
62 | // Use the sort function only to get the indices array
63 | af::array cond;
64 | af::array indices_inside;
65 | af::sort(cond, indices_inside, gridmap.isCellInside(obstacle_coords), 0, false);
66 |
67 | // Get ony the indices of the obstacles
68 | indices_inside = indices_inside(af::seq(af::sum(cond).scalar()));
69 |
70 | // inside_obstacles_coords = inside_obstacles_coords(af::seq(num_obs_inside), af::span);
71 |
72 | af::array inside_obstacles_coords = af::lookup(obstacle_coords(af::span, af::seq(2)), indices_inside);
73 |
74 | if (DEBUG_) std::cout << "Remove outside obstacles time: " << ros::Time::now() - t0 << std::endl;
75 | t0 = ros::Time::now();
76 |
77 | // Add a free line to each obstacle inside the grid
78 | // Set the origin of the lines at the sensor point
79 | hypergrid::Cell start = gridmap.cellCoordsFromLocal(trans.getX(), trans.getY());
80 | gridmap.addFreeLines(start, inside_obstacles_coords);
81 |
82 | if (DEBUG_) std::cout << "Set free lines time: " << ros::Time::now() - t0 << std::endl;
83 | t0 = ros::Time::now();
84 |
85 | // Set the obstacles in the map
86 | af::array indices = inside_obstacles_coords(af::span, 1).as(s32) * gridmap.grid.dims(0) + inside_obstacles_coords(af::span, 0).as(s32);
87 | gridmap.grid(indices) = hypergrid::GridMap::OBSTACLE;
88 |
89 | if (DEBUG_) std::cout << "Set obstacles time: " << ros::Time::now() - t0 << std::endl;
90 | t0 = ros::Time::now();
91 |
92 | return gridmap;
93 | }
94 |
95 | GridMap LaserScanConverter::convert(const sensor_msgs::LaserScanPtr& scan_msg, const tf::StampedTransform transform) const
96 | {
97 | return convert(*scan_msg, transform);
98 | }
99 |
100 | GridMap LaserScanConverter::convert(const sensor_msgs::LaserScanConstPtr& scan_msg, const tf::StampedTransform transform) const
101 | {
102 | return convert(*scan_msg, transform);
103 | }
104 |
105 |
106 | } // hypergrid namespace
107 |
--------------------------------------------------------------------------------
/src/hypergrid/conversions/lidar_converter.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 |
4 | namespace hypergrid
5 | {
6 |
7 | /* Constructor */
8 | LIDARConverter::LIDARConverter(double width, double height, double cell_size,
9 | geometry_msgs::Pose origin, std::string map_frame_id,
10 | double heightmap_threshold, double heightmap_cell_size,
11 | double max_height, double vehicle_box_size, bool DEBUG) :
12 | origin_(origin)
13 | {
14 | width_ = width;
15 | height_ = height;
16 | cell_size_ = cell_size;
17 | map_frame_id_ = map_frame_id;
18 | heightmap_threshold_ = heightmap_threshold;
19 | heightmap_cell_size_ = heightmap_cell_size;
20 | max_height_ = max_height;
21 | vehicle_box_size_ = vehicle_box_size;
22 | DEBUG_ = DEBUG;
23 | }
24 |
25 | /* Convert a sensor_msgs::PointCloud2 to a hypergrid::GridMap */
26 | GridMap LIDARConverter::convert(sensor_msgs::PointCloud2& cloud_msg, const tf::StampedTransform transform) const
27 | {
28 | auto start = std::chrono::high_resolution_clock::now();
29 |
30 | // ros::Time t0 = ros::Time::now();
31 | // ros::Time t_start = t0;
32 | if (DEBUG_) std::cout << "\n------------------------\nNew pcl" << std::endl;
33 |
34 | // Convert PointCloud2 to ArrayFire array
35 | float* data_f = reinterpret_cast(cloud_msg.data.data());
36 | af::array pcl_points(8, cloud_msg.width*cloud_msg.height, data_f);
37 |
38 | // Remove Intenisty and Ring Bytes
39 | pcl_points = pcl_points(af::seq(3), af::span);
40 |
41 | if (DEBUG_)
42 | {
43 | std::cout << "Convert PointCloud2 to ArrayFire array time: " << std::fixed
44 | << (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count()) * 1e-9
45 | << std::setprecision(9) << " sec" << std::endl;
46 | start = std::chrono::high_resolution_clock::now();
47 | }
48 |
49 | hypergrid::GridMap gridmap(width_, height_, cell_size_, origin_, map_frame_id_);
50 |
51 | Eigen::Affine3d e;
52 | tf::transformTFToEigen(transform, e);
53 |
54 | double t_r_array[] = { e(0,0), e(1,0), e(2,0), e(3,0),
55 | e(0,1), e(1,1), e(2,1), e(3,1),
56 | e(0,2), e(1,2), e(2,2), e(3,2),
57 | e(0,3), e(1,3), e(2,3), e(3,3) };
58 |
59 | af::array transformation(4, 4, t_r_array);
60 | af::array ones = af::constant(1, 1, pcl_points.dims(1));
61 | pcl_points = af::join(0,pcl_points, ones);
62 |
63 | // Transform the obstacles to the map frame
64 | pcl_points = (af::matmul(transformation, pcl_points.as(f64))).as(f32);
65 | pcl_points = pcl_points(af::seq(3), af::span);
66 |
67 | if (DEBUG_)
68 | {
69 | std::cout << "Obstacles transform time: " << std::fixed
70 | << (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count()) * 1e-9
71 | << std::setprecision(9) << " sec" << std::endl;
72 | start = std::chrono::high_resolution_clock::now();
73 | }
74 |
75 | if (DEBUG_) std::cout << "points before: " << pcl_points.dims(1) << std::endl;
76 |
77 | // Remove the floor points
78 | remove_floor(pcl_points);
79 |
80 | if (DEBUG_) std::cout << "points after: " << pcl_points.dims(1) << std::endl;
81 |
82 | if (DEBUG_)
83 | {
84 | std::cout << "remove floor time: " << std::fixed
85 | << (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count()) * 1e-9
86 | << std::setprecision(9) << " sec" << std::endl;
87 | start = std::chrono::high_resolution_clock::now();
88 | }
89 |
90 | pcl_points.eval();
91 | af::array obs = (af::join(0, pcl_points(af::seq(2), af::span), ones(af::span, af::seq(pcl_points.dims(1) )))).as(f64);
92 |
93 | pcl_points = pcl_points.T();
94 | af::array obstacle_coords = gridmap.cellCoordsFromLocal(obs.T())(af::span, af::seq(2));
95 |
96 | if (DEBUG_)
97 | {
98 | std::cout << "Remove outside obstacles time: " << std::fixed
99 | << (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count()) * 1e-9
100 | << std::setprecision(9) << " sec" << std::endl;
101 | start = std::chrono::high_resolution_clock::now();
102 | }
103 |
104 | // Add a free line to each obstacle inside the grid
105 | // Set the origin of the lines at the sensor point
106 | hypergrid::Cell start_cell = gridmap.cellCoordsFromLocal(transform.getOrigin().getX(), transform.getOrigin().getY());
107 | gridmap.addFreeLines(start_cell, obstacle_coords);
108 |
109 | if (DEBUG_)
110 | {
111 | std::cout << "Set free lines time: " << std::fixed
112 | << (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count()) * 1e-9
113 | << std::setprecision(9) << " sec" << std::endl;
114 | start = std::chrono::high_resolution_clock::now();
115 | }
116 |
117 | // Set the obstacles in the map
118 | af::array indices = obstacle_coords(af::span, 1).as(s32) * gridmap.grid.dims(0) + obstacle_coords(af::span, 0).as(s32);
119 | gridmap.grid(indices) = hypergrid::GridMap::OBSTACLE;
120 |
121 | if (DEBUG_)
122 | {
123 | std::cout << "Set obstacles time: " << std::fixed
124 | << (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count()) * 1e-9
125 | << std::setprecision(9) << " sec" << std::endl;
126 | start = std::chrono::high_resolution_clock::now();
127 | }
128 |
129 | return gridmap;
130 | }
131 |
132 | GridMap LIDARConverter::convert( sensor_msgs::PointCloud2Ptr& cloud_msg, const tf::StampedTransform transform) const
133 | {
134 | return convert(*cloud_msg, transform);
135 | }
136 |
137 | /* Removes all the points in the floor with a heightmap algorithm */
138 | void LIDARConverter::remove_floor(af::array& cloud) const
139 | {
140 | float* x = cloud(0, af::span).host();
141 | float* y = cloud(1, af::span).host();
142 | float* z = cloud(2, af::span).host();
143 |
144 | int height_cells = height_ / heightmap_cell_size_;
145 | int width_cells = width_ / heightmap_cell_size_;
146 |
147 | af::array x_arr = (width_cells / 2) + (cloud(0, af::span) / heightmap_cell_size_);
148 | af::array y_arr = (height_cells / 2) + (cloud(1, af::span) / heightmap_cell_size_);
149 | af::array z_arr = cloud(2, af::span);
150 |
151 | float* min = new float[width_cells * height_cells];
152 | float* max = new float[width_cells * height_cells];
153 |
154 | // Init maps
155 | for (int i = 0; i < width_cells; ++i)
156 | {
157 | for (int j = 0; j < height_cells; ++j)
158 | {
159 | int index = i * height_cells + j;
160 | min[index] = 9999.9;
161 | max[index] = -9999.9;
162 | }
163 | }
164 |
165 | std::vector indices;
166 | // Build height map and remove points outside, too high or inside the vehicle box
167 | for (int i = 0; i < cloud.dims(1); ++i)
168 | {
169 | int x_idx = (width_cells / 2) + (x[i] / heightmap_cell_size_);
170 | int y_idx = (height_cells / 2) + (y[i] / heightmap_cell_size_);
171 | bool valid_point = ((x_idx >= 0) && (x_idx < width_cells) && (y_idx >= 0) && (y_idx < height_cells)) && // Point is inside the grid
172 | ((z[i] < max_height_)) && // Point is inside height limit
173 | (std::isfinite(x[i]) && std::isfinite(y[i]) && std::isfinite(z[i])) && // Point is not NaN or Inf
174 | ((abs(x[i]) > vehicle_box_size_) || (abs(y[i]) > vehicle_box_size_)); // Point is not inside the vehicle box
175 | if (valid_point)
176 | {
177 | // Mark the point for removal
178 | indices.push_back(i);
179 |
180 | // Add the point to the heightmap
181 | if (x_idx >= 0 && x_idx < width_cells && y_idx >= 0 && y_idx < height_cells)
182 | {
183 | int index = x_idx * height_cells + y_idx;
184 | min[index] = std::min(min[index], z[i]);
185 | max[index] = std::max(max[index], z[i]);
186 | }
187 | }
188 | }
189 |
190 | af::array indices_arr(indices.size(), indices.data());
191 | delete[] x;
192 | delete[] y;
193 | delete[] z;
194 | cloud = af::lookup(cloud, indices_arr, 1);
195 | cloud.eval();
196 | indices.clear();
197 |
198 | x = cloud(0, af::span).host();
199 | y = cloud(1, af::span).host();
200 |
201 | // Remove the floor points
202 | for (int i = 0; i < cloud.dims(1); ++i)
203 | {
204 | int x_idx = (width_cells / 2) + (x[i] / heightmap_cell_size_);
205 | int y_idx = (height_cells / 2) + (y[i] / heightmap_cell_size_);
206 |
207 | if (x_idx >= 0 && x_idx < width_cells && y_idx >= 0 && y_idx < height_cells)
208 | {
209 | int index = x_idx * height_cells + y_idx;
210 | if ((max[index] - min[index]) > heightmap_threshold_)
211 | {
212 | indices.push_back(i);
213 | }
214 | }
215 | }
216 |
217 | indices_arr = af::array(indices.size(), indices.data());
218 | delete[] x;
219 | delete[] y;
220 | delete[] min;
221 | delete[] max;
222 |
223 | cloud = af::lookup(cloud, indices_arr, 1);
224 | }
225 |
226 | } // hypergrid namespace
227 |
--------------------------------------------------------------------------------
/src/hypergrid/gridmap.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | namespace hypergrid
4 | {
5 |
6 | /* Constructors */
7 | GridMap::GridMap() :
8 | origin_()
9 | {
10 | width_ = 0.0;
11 | height_ = 0.0;
12 | cell_size_ = 1.0;
13 | map_frame_id_ = "";
14 | }
15 |
16 | GridMap::GridMap(double width, double height, double cell_size,
17 | geometry_msgs::Pose origin, std::string map_frame_id) :
18 | origin_(origin)
19 | {
20 | width_ = width;
21 | height_ = height;
22 | cell_size_ = cell_size;
23 | map_frame_id_ = map_frame_id;
24 | // Check for empty origin pose and fix the quaternion
25 | if (origin_.orientation.x == 0.0 &&
26 | origin_.orientation.y == 0.0 &&
27 | origin_.orientation.z == 0.0 &&
28 | origin_.orientation.w == 0.0)
29 | {
30 | origin_.orientation.w = 1.0;
31 | }
32 | int width_cells = width_ / cell_size_;
33 | int height_cells = height_ / cell_size_;
34 | grid = af::constant((int)Label::UNKNOWN, width_cells, height_cells, s32);
35 | }
36 |
37 | GridMap::GridMap(const nav_msgs::OccupancyGrid map_msg)
38 | {
39 | map_frame_id_ = map_msg.header.frame_id;
40 | origin_ = map_msg.info.origin;
41 | cell_size_ = map_msg.info.resolution;
42 | width_ = map_msg.info.width * cell_size_;
43 | height_ = map_msg.info.height * cell_size_;
44 |
45 | // Convert the 8 bit data from the ROS msg to 32 bits
46 | int32_t* array_data = new int32_t[map_msg.data.size()];
47 | for (int i = 0; i < map_msg.data.size(); ++i)
48 | {
49 | array_data[i] = map_msg.data[i];
50 | }
51 |
52 | grid = af::array(map_msg.info.width, map_msg.info.height, array_data, afHost);
53 | }
54 |
55 | GridMap::GridMap(const nav_msgs::OccupancyGridConstPtr map_msg) : GridMap(*map_msg){}
56 |
57 | /* Copy constructor */
58 | GridMap::GridMap(const GridMap& other_map)
59 | {
60 | grid = other_map.grid;
61 | origin_ = other_map.getOrigin();
62 | width_ = other_map.getWidth();
63 | height_ = other_map.getHeight();
64 | cell_size_ = other_map.getCellSize();
65 | map_frame_id_ = other_map.getMapFrameId();
66 | }
67 |
68 | /* Move constructor */
69 | GridMap::GridMap(GridMap&& other_map) noexcept :
70 | grid(std::move(other_map.grid)),
71 | map_frame_id_(std::move(other_map.getMapFrameId()))
72 |
73 | {
74 | origin_ = other_map.getOrigin();
75 | width_ = other_map.getWidth();
76 | height_ = other_map.getHeight();
77 | cell_size_ = other_map.getCellSize();
78 | }
79 |
80 | /* Assignement operator */
81 | GridMap& GridMap::operator = (const GridMap& other_map)
82 | {
83 | // check for self-assignment
84 | if(&other_map == this) return *this;
85 |
86 | grid = other_map.grid;
87 | origin_ = other_map.getOrigin();
88 | this->width_ = other_map.getWidth();
89 | this->height_ = other_map.getHeight();
90 | this->cell_size_ = other_map.getCellSize();
91 | this->map_frame_id_ = other_map.getMapFrameId();
92 |
93 | return *this;
94 | }
95 |
96 |
97 | /* Convert to ROS nav_msgs::OccupancyGrid msg */
98 | void GridMap::toMapMsg(nav_msgs::OccupancyGrid& map_msg)
99 | {
100 | map_msg = toMapMsg();
101 | }
102 |
103 | /* Convert to ROS nav_msgs::OccupancyGrid msg */
104 | nav_msgs::OccupancyGrid GridMap::toMapMsg()
105 | {
106 | nav_msgs::OccupancyGrid map_msg;
107 | map_msg.header.stamp = ros::Time::now();
108 | map_msg.header.frame_id = map_frame_id_;
109 |
110 | nav_msgs::MapMetaData map_info;
111 | map_info.map_load_time = map_msg.header.stamp;
112 | map_info.resolution = cell_size_;
113 | map_info.width = grid.dims(0);
114 | map_info.height = grid.dims(1);
115 |
116 | // Set the map origin pose
117 | map_info.origin = origin_;
118 | map_msg.info = map_info;
119 |
120 | // Get the data from the device to a host pointer
121 | int32_t* array_data = grid.host();
122 |
123 | size_t total_size = grid.dims(0) * grid.dims(1);
124 | map_msg.data.resize(total_size);
125 |
126 | // Perform a casting from 32 bit to 8
127 | for (int i = 0; i < total_size; ++i)
128 | {
129 | map_msg.data[i] = array_data[i] & 0xFF;
130 | }
131 |
132 | delete[] array_data;
133 | return map_msg;
134 | }
135 |
136 | /* Resize the map to a different resolution (size in meters remains, number of cells changes).
137 | Works only if cell_size > output_cell_size
138 | */
139 | void GridMap::resize(double output_cell_size)
140 | {
141 | grid = af::resize(cell_size_ / output_cell_size, grid, AF_INTERP_LOWER);
142 | cell_size_ = output_cell_size;
143 | }
144 |
145 | /* Apply a rotation to the map */
146 | void GridMap::rotate(double angle)
147 | {
148 | // Original Dimension
149 | long dim0 = grid.dims(0);
150 | long dim1 = grid.dims(1);
151 | // Adding grid.dim(0) rows to each side then adding grid.dim(1) columns to each side to modfiy rotate function
152 | af::array bigger0 = af::constant((int)Label::UNKNOWN, grid.dims(0), grid.dims(1), s32);
153 | af::array bigger1 = af::constant((int)Label::UNKNOWN, grid.dims(0) * 3, grid.dims(1), s32);
154 |
155 | // Rows
156 | grid = af::join(0, grid, bigger0);
157 | grid = af::join(0, bigger0, grid);
158 | // Columns
159 | grid = af::join(1, grid, bigger1);
160 | grid = af::join(1, bigger1, grid);
161 | // Rotate
162 | grid = af::rotate(grid, angle, true);
163 | // Return to original size
164 | grid = grid(af::seq(dim0, grid.dims(0) - dim0 - 1), af::seq(dim1, grid.dims(1) - dim1 - 1));
165 | }
166 |
167 | /* Clear the map and set all cells to UNKNOWN */
168 | void GridMap::clear()
169 | {
170 | grid = UNKNOWN;
171 | }
172 |
173 | /* Cell coordinates from local coordinates */
174 | template
175 | Cell GridMap::cellCoordsFromLocal(T x, T y)
176 | {
177 | Pointd t_point = originFromLocal_(Pointd(x, y));
178 | return Cell(std::floor(t_point.x / cell_size_), std::floor(t_point.y / cell_size_));
179 | }
180 |
181 | af::array GridMap::cellCoordsFromLocal(af::array local_points)
182 | {
183 | af::array transform = getOriginTransform_();
184 | af::array coords = af::matmul(af::inverse(transform), local_points.T()).T();
185 | coords = af::floor(coords / cell_size_).as(s32);
186 | return coords;
187 | }
188 |
189 | /* Local coordinates from cell coords */
190 | template
191 | Point GridMap::localCoordsFromCell(size_t x, size_t y)
192 | {
193 | // Get the local point in the center of the cell
194 | Pointd t_point = localFromOrigin_(Pointd(x * cell_size_ + cell_size_/2, y * cell_size_ + cell_size_/2));
195 | return Point(t_point.x, t_point.y);
196 | }
197 |
198 | /* Cell access from local coordinates */
199 | template
200 | af::array::array_proxy GridMap::cellFromLocal(T x, T y)
201 | {
202 | Cell p = cellCoordsFromLocal(x, y);
203 | if (!isCellInside(p)) throw std::out_of_range("Index out of map bounds");
204 | return cell(p);
205 | }
206 |
207 | /* Add a free line from the vehicle to the given cell */
208 | void GridMap::addFreeLine(Cell end)
209 | {
210 | Cell start = cellCoordsFromLocal(0, 0);
211 | DDA(grid, FREE, start.x, start.y, end.x, end.y);
212 | }
213 |
214 | /* Add a free line from the start cell to the end cell */
215 | void GridMap::addFreeLine(Cell start, Cell end)
216 | {
217 | DDA(grid, FREE, start.x, start.y, end.x, end.y);
218 | }
219 |
220 | /* Add multiple free lines from a given point */
221 | void GridMap::addFreeLines(Cell start, af::array endpoints)
222 | {
223 | add_lines(grid, FREE, start.x, start.y, endpoints);
224 | }
225 |
226 |
227 | /* Apply the inverse map origin transformation to get the cell (in meters) from a local point */
228 | Pointd GridMap::originFromLocal_(Pointd src) const
229 | {
230 | double src_arr[] = {src.x, src.y, 1};
231 | af::array af_src(3, 1, src_arr);
232 | af::array t_src = af::matmul(af::inverse(getOriginTransform_()), af_src);
233 | return Pointd(t_src(0).scalar(), t_src(1).scalar());
234 | }
235 |
236 | /* Apply the map origin transformation to get the local point from a cell point (in meters) */
237 | Pointd GridMap::localFromOrigin_(Pointd src) const
238 | {
239 | double src_arr[] = {src.x, src.y, 1};
240 | af::array af_src(3, 1, src_arr);
241 | af::array t_src = af::matmul(getOriginTransform_(), af_src);
242 | return Pointd(t_src(0).scalar(), t_src(1).scalar());
243 | }
244 |
245 | /* Get the Origin Transform matrix */
246 | af::array GridMap::getOriginTransform_() const
247 | {
248 | // Get Theta
249 | double theta = tf::getYaw(origin_.orientation);
250 |
251 | // Create the 2D translation and rotation matrix
252 | double t_r_array[] = {std::cos(theta), std::sin(theta), 0,
253 | -std::sin(theta), std::cos(theta), 0,
254 | origin_.position.x, origin_.position.y, 1};
255 | af::array t_r_matrix(3, 3, t_r_array);
256 | return t_r_matrix;
257 | }
258 |
259 |
260 | /* Macro to instantiate all template functions for a given type */
261 | #define INSTANTIATE_TEMPLATES(TYPE) \
262 | template Cell GridMap::cellCoordsFromLocal(TYPE x, TYPE y); \
263 | template Point GridMap::localCoordsFromCell(size_t x, size_t y); \
264 | template af::array::array_proxy GridMap::cellFromLocal(TYPE x, TYPE y);
265 |
266 |
267 | INSTANTIATE_TEMPLATES(char)
268 | INSTANTIATE_TEMPLATES(unsigned char)
269 | INSTANTIATE_TEMPLATES(short)
270 | INSTANTIATE_TEMPLATES(unsigned short)
271 | INSTANTIATE_TEMPLATES(int)
272 | INSTANTIATE_TEMPLATES(unsigned int)
273 | INSTANTIATE_TEMPLATES(long)
274 | INSTANTIATE_TEMPLATES(unsigned long)
275 | INSTANTIATE_TEMPLATES(long long)
276 | INSTANTIATE_TEMPLATES(unsigned long long)
277 | INSTANTIATE_TEMPLATES(float)
278 | INSTANTIATE_TEMPLATES(double)
279 | INSTANTIATE_TEMPLATES(long double)
280 |
281 |
282 | } // hypergrid namespace
283 |
--------------------------------------------------------------------------------
/src/hypergrid/utils/raytracing.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | namespace hypergrid
6 | {
7 |
8 | /*
9 | DDA algorithm to draw line from one point to another in the occupancy grid.
10 | */
11 | std::mutex dda_grid_mutex;
12 | void DDA(af::array& grid, int value,
13 | float start_x, float start_y,
14 | float end_x, float end_y)
15 | {
16 | float dx = std::abs(end_x - start_x);
17 | float dy = std::abs(end_y - start_y);
18 |
19 | // float step = dx >= dy ? dx : dy;
20 | float step = ((int)(dx >= dy) * dx) + ((int)(dx < dy) * dy);
21 | if (step == 0) return;
22 | dx = (end_x - start_x) / step;
23 | dy = (end_y - start_y) / step;
24 |
25 | af::array x_arr = af::constant(start_x, step);
26 | af::array y_arr = af::constant(start_y, step);
27 | af::array count = af::seq(0, step - 1);
28 |
29 | x_arr += dx * count;
30 | y_arr += dy * count;
31 |
32 | af::array indices = y_arr.as(s32) * grid.dims(0) + x_arr.as(s32);
33 | std::lock_guard grid_lock(dda_grid_mutex);
34 | grid(indices) = value;
35 | }
36 |
37 | void add_lines_worker(af::array& grid, int start_idx, int end_idx,
38 | int value, size_t start_x, size_t start_y,
39 | std::vector endpoints_x, std::vector endpoints_y)
40 | {
41 | end_idx = std::min(end_idx, (int)endpoints_x.size());
42 | for (int i = start_idx; i < end_idx; ++i)
43 | {
44 | DDA(grid, value, start_x, start_y,
45 | endpoints_x[i], endpoints_y[i]);
46 | }
47 | }
48 |
49 | void add_lines(af::array& grid, int value,
50 | size_t start_x, size_t start_y,
51 | af::array endpoints)
52 | {
53 | // Obtain raw pointer from array object
54 | int *device_end_x = endpoints(af::span, 0).device();
55 | int *device_end_y = endpoints(af::span, 1).device();
56 |
57 | // Remove duplicated endpoints
58 | size_t lut_size = grid.dims(0) * grid.dims(1);
59 | std::vector index_lut(lut_size, false);
60 | std::vector unique_end_x;
61 | unique_end_x.reserve(endpoints.dims(0));
62 | std::vector unique_end_y;
63 | unique_end_y.reserve(endpoints.dims(0));
64 |
65 | for (int i = 0; i < endpoints.dims(0); ++i)
66 | {
67 | int global_idx = device_end_x[i] * grid.dims(0) + device_end_y[i];
68 | if (global_idx >= lut_size) continue;
69 | if (!index_lut[global_idx])
70 | {
71 | unique_end_x.push_back(device_end_x[i]);
72 | unique_end_y.push_back(device_end_y[i]);
73 | index_lut[global_idx] = true;
74 | }
75 | }
76 |
77 | int n_threads = std::thread::hardware_concurrency();
78 | int splitted_size = (unique_end_x.size() + n_threads - 1) / n_threads;
79 |
80 | std::vector thread_pool;
81 | for (int i = 0; i < n_threads; ++i)
82 | {
83 | thread_pool.push_back(std::thread(add_lines_worker, std::ref(grid),
84 | i*splitted_size, (i+1)*splitted_size,
85 | value, start_x, start_y,
86 | unique_end_x, unique_end_y));
87 | }
88 | for (auto& t : thread_pool) t.join();
89 | }
90 |
91 |
92 | } // hypergrid namespace
93 |
--------------------------------------------------------------------------------
/src/hypergrid/utils/raytracing.cu:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 |
5 | namespace hypergrid
6 | {
7 |
8 | __global__
9 | void raytracing_kernel(int* grid, int value,
10 | size_t start_x, size_t start_y,
11 | int* end_x, int* end_y,
12 | size_t dim_x, size_t dim_y,
13 | size_t endpoints_size)
14 | {
15 | int idx = threadIdx.x + blockIdx.x * blockDim.x;
16 | if (idx >= endpoints_size ||
17 | end_x[idx] >= dim_x ||
18 | end_y[idx] >= dim_x)
19 | {
20 | return;
21 | }
22 |
23 | size_t bt_pix0 = 1;
24 | size_t bt_pix = bt_pix0;
25 | size_t istep = dim_x;
26 |
27 | int dx = end_x[idx] - (int)start_x;
28 | int dy = end_y[idx] - (int)start_y;
29 | int s = dx < 0 ? -1 : 0;
30 |
31 | dx = (dx ^ s) - s;
32 | bt_pix = (bt_pix ^ s) - s;
33 |
34 | size_t ptr_ = start_y * istep + start_x;
35 |
36 | s = dy < 0 ? -1 : 0;
37 | dy = (dy ^ s) - s;
38 | istep = (istep ^ s) - s;
39 |
40 | s = dy > dx ? -1 : 0;
41 |
42 | // Conditional swaps
43 | dx ^= dy & s;
44 | dy ^= dx & s;
45 | dx ^= dy & s;
46 |
47 | bt_pix ^= istep & s;
48 | istep ^= bt_pix & s;
49 | bt_pix ^= istep & s;
50 |
51 | int minus_delta_ = 0;
52 | int plus_delta_ = 0;
53 | int minus_step_ = 0;
54 | int plus_step_ = 0;
55 | int error_ = 0;
56 | size_t size_ = 0;
57 |
58 | // Connectivity 4
59 | // error_ = 0;
60 | // plus_delta_ = (dx + dx) + (dy + dy);
61 | // minus_delta_ = -(dy + dy);
62 | // plus_step_ = (int)(istep - bt_pix);
63 | // minus_step_ = (int)bt_pix;
64 | // size_ = dx + dy + 1;
65 |
66 | // Connectivity 8
67 | error_ = dx - (dy + dy);
68 | plus_delta_ = dx + dx;
69 | minus_delta_ = -(dy + dy);
70 | plus_step_ = (int)istep;
71 | minus_step_ = (int)bt_pix;
72 | size_ = dx + 1;
73 |
74 | size_t grid_size = dim_x * dim_y;
75 | int mask = 0;
76 | for (int i = 0; i < size_; i++)
77 | {
78 | // Check if current cell is obstacle
79 | if (grid[ptr_] == 100) return;
80 |
81 | // Set cell value
82 | grid[ptr_] = value;
83 |
84 | // Update state
85 | mask = error_ < 0 ? -1 : 0;
86 | error_ += minus_delta_ + (plus_delta_ & mask);
87 | ptr_ += minus_step_ + (plus_step_ & mask);
88 |
89 | // Check if out of bounds
90 | if (ptr_ >= grid_size) return;
91 | }
92 | }
93 |
94 | /*
95 | DDA algorithm to draw line from one point to another in the occupancy grid.
96 | */
97 | void DDA(af::array& grid, int value,
98 | float start_x, float start_y,
99 | float end_x, float end_y)
100 | {
101 | float dx = abs(end_x - start_x);
102 | float dy = abs(end_y - start_y);
103 |
104 | // float step = dx >= dy ? dx : dy;
105 | float step = ((int)(dx >= dy) * dx) + ((int)(dx < dy) * dy);
106 |
107 | dx = (end_x - start_x) / step;
108 | dy = (end_y - start_y) / step;
109 |
110 | af::array x_arr = af::constant(start_x, step);
111 | af::array y_arr = af::constant(start_y, step);
112 | af::array count = af::seq(0, step - 1);
113 |
114 | x_arr += dx * count;
115 | y_arr += dy * count;
116 |
117 | af::array indices = y_arr.as(s32) * grid.dims(0) + x_arr.as(s32);
118 |
119 | grid(indices) = value;
120 | }
121 |
122 | void add_lines(af::array& grid, int value,
123 | size_t start_x, size_t start_y,
124 | af::array endpoints)
125 | {
126 | // Ensure any JIT kernels have executed
127 | grid.eval();
128 | endpoints.eval();
129 |
130 | // Obtain device pointer from array object
131 | int *device_grid = grid.device();
132 | int *device_end_x = endpoints(af::span, 0).device();
133 | int *device_end_y = endpoints(af::span, 1).device();
134 |
135 | // Determine ArrayFire's CUDA stream
136 | int af_id = af::getDevice();
137 | int cuda_id = afcu::getNativeId(af_id);
138 | cudaStream_t af_cuda_stream = afcu::getStream(cuda_id);
139 |
140 | // Set arguments and run the kernel in ArrayFire's stream
141 | int block_size = 512;
142 | int grid_size = (endpoints.dims(0) + block_size - 1) / block_size;
143 | raytracing_kernel<<>>(device_grid, value,
144 | start_x, start_y,
145 | device_end_x, device_end_y,
146 | grid.dims(0), grid.dims(1),
147 | endpoints.dims(0));
148 | // Finish any pending CUDA operations
149 | cudaDeviceSynchronize();
150 |
151 | // Return control of af::array memory to ArrayFire
152 | grid.unlock();
153 | grid.eval();
154 | }
155 |
156 |
157 | } // hypergrid namespace
158 |
--------------------------------------------------------------------------------
/src/laser_to_gridmap.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 |
10 | double map_height;
11 | double map_width;
12 | double cell_size;
13 | bool DEBUG;
14 |
15 | ros::Publisher laser_gridmap_pub;
16 |
17 | // Laser frame to base_footprint tf transform
18 | std::string map_frame_id;
19 | tf::TransformListener* tf_listener;
20 |
21 | void laser_callback(const sensor_msgs::LaserScanConstPtr scan)
22 | {
23 | ros::Time t0 = ros::Time::now();
24 | // Update the laser transform
25 | tf::StampedTransform laser_footprint_transform;
26 | try
27 | {
28 | tf_listener->lookupTransform(map_frame_id, scan->header.frame_id, ros::Time(0), laser_footprint_transform);
29 | }
30 | catch(tf::TransformException &ex)
31 | {
32 | ROS_ERROR("%s", ex.what());
33 | return;
34 | }
35 | geometry_msgs::Pose origin;
36 | origin.position.x = 0;
37 | origin.position.y = - (map_height / 2);
38 | origin.orientation.w = 1;
39 | hypergrid::LaserScanConverter laser_converter(map_width, map_height, cell_size, origin, map_frame_id);
40 |
41 | hypergrid::GridMap gridmap = laser_converter.convert(scan, laser_footprint_transform);
42 | // Publish OccupancyGrid map
43 | laser_gridmap_pub.publish(gridmap.toMapMsg());
44 | if (DEBUG) std::cout << "Publish time: " << ros::Time::now() - t0 << std::endl;
45 | }
46 |
47 |
48 | int main(int argc, char **argv)
49 | {
50 | af::info();
51 |
52 | ros::init(argc, argv, "laser_to_gridmap");
53 | ros::NodeHandle public_nh, private_nh("~");
54 |
55 | private_nh.param("map_frame_id", map_frame_id, "base_footprint");
56 | private_nh.param("height", map_height, 50.0);
57 | private_nh.param("width", map_width, 50.0);
58 | private_nh.param("cell_size", cell_size, 0.2);
59 | private_nh.param("DEBUG", DEBUG, false);
60 |
61 | laser_gridmap_pub = public_nh.advertise("hypergrid/laser_to_gridmap", 2);
62 | ros::Subscriber laser_sub = public_nh.subscribe("scan", 5, laser_callback);
63 |
64 | tf_listener = new tf::TransformListener;
65 |
66 | ros::spin();
67 |
68 | return 0;
69 | }
70 |
--------------------------------------------------------------------------------
/src/pcl_to_gridmap.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 |
11 | // Map params
12 | double map_height;
13 | double map_width;
14 | double cell_size;
15 | bool DEBUG;
16 |
17 | // Parameters for floor removal algorithm
18 | bool floor_filter;
19 |
20 | // Vehicle box to ignore points inside it
21 | double vehicle_box_size;
22 |
23 | // Maximum height of obstacles. Everything higher will out of the map
24 | double max_height;
25 | double heightmap_threshold;
26 | double heightmap_cell_size;
27 |
28 | // Laser frame to base_footprint tf transform
29 | std::string map_frame_id;
30 | std::string cloud_topic;
31 | std::string output_topic;
32 | ros::Publisher cloud_map_pub;
33 |
34 | // Transform Listener
35 | tf::TransformListener* tf_listener;
36 |
37 |
38 | /* Removes all the points in the floor with a heightmap algorithm */
39 | void remove_floor(af::array& cloud)
40 | {
41 | float* x = cloud(0, af::span).host();
42 | float* y = cloud(1, af::span).host();
43 | float* z = cloud(2, af::span).host();
44 |
45 | int height_cells = map_height / heightmap_cell_size;
46 | int width_cells = map_width / heightmap_cell_size;
47 |
48 | af::array x_arr = (width_cells / 2) + (cloud(0, af::span) / heightmap_cell_size);
49 | af::array y_arr = (height_cells / 2) + (cloud(1, af::span) / heightmap_cell_size);
50 | af::array z_arr = cloud(2, af::span);
51 |
52 | float* min = new float[width_cells * height_cells];
53 | float* max = new float[width_cells * height_cells];
54 |
55 | // Resize the cloud to make it non-organized and work faster
56 | int width = cloud.dims(0) * cloud.dims(1);
57 | int height = 1;
58 |
59 | // Init maps
60 | for (int i = 0; i < width_cells; ++i)
61 | {
62 | for (int j = 0; j < height_cells; ++j)
63 | {
64 | int index = i * height_cells + j;
65 | min[index] = 9999.9;
66 | max[index] = -9999.9;
67 | }
68 | }
69 |
70 | // Build height map
71 | for (int i = 0; i < cloud.dims(1); ++i)
72 | {
73 | int x_idx = (width_cells / 2) + (x[i] / heightmap_cell_size);
74 | int y_idx = (height_cells / 2) + (y[i] / heightmap_cell_size);
75 |
76 | if (x_idx >= 0 && x_idx < width_cells && y_idx >= 0 && y_idx < height_cells)
77 | {
78 | int index = x_idx * height_cells + y_idx;
79 | min[index] = std::min(min[index], z[i]);
80 | max[index] = std::max(max[index], z[i]);
81 | }
82 | }
83 |
84 | std::vector indices;
85 | for (int i = 0; i < width; ++i)
86 | {
87 | int x_idx = (width_cells / 2) + (x[i] / heightmap_cell_size);
88 | int y_idx = (height_cells / 2) + (y[i] / heightmap_cell_size);
89 | int index = x_idx * height_cells + y_idx;
90 |
91 | bool is_obstacle = ((x_idx >= 0) && (x_idx < width_cells) && (y_idx >= 0) && (y_idx < height_cells)) && // Point is inside the grid
92 | ((z[i] < max_height)) && // Point is inside height limit
93 | ((abs(x[i]) > vehicle_box_size) || (abs(y[i]) > vehicle_box_size)) && // Point is not inside the vehicle box
94 | ((max[index] - min[index]) > heightmap_threshold); // Point is inside a cell considered obstacle by the heightmap
95 | if (is_obstacle) indices.push_back(i);
96 | }
97 |
98 | af::array indices_arr(indices.size(), indices.data());
99 | delete[] x;
100 | delete[] y;
101 | delete[] z;
102 | delete[] min;
103 | delete[] max;
104 | cloud = af::lookup(cloud, indices_arr, 1);
105 | }
106 |
107 | void cloud_callback(sensor_msgs::PointCloud2Ptr cloud_msg)
108 | {
109 | ros::Time t0 = ros::Time::now();
110 | ros::Time t_start = t0;
111 |
112 | tf::StampedTransform pcl_footprint_transform;
113 | try
114 | {
115 | tf_listener->lookupTransform(map_frame_id, cloud_msg->header.frame_id , ros::Time(0), pcl_footprint_transform);
116 | }
117 | catch(tf::TransformException &ex)
118 | {
119 | ROS_WARN("Warning: %s", ex.what());
120 | }
121 |
122 | geometry_msgs::Pose origin;
123 | origin.position.x = - (map_width / 2) + cell_size;
124 | origin.position.y = - (map_height / 2) + cell_size;
125 | origin.orientation.w = 1;
126 |
127 | hypergrid::LIDARConverter lidar_converter(map_width, map_height, cell_size,
128 | origin, map_frame_id,
129 | heightmap_threshold,
130 | heightmap_cell_size,
131 | max_height, vehicle_box_size,
132 | DEBUG);
133 |
134 | hypergrid::GridMap gridmap = lidar_converter.convert(cloud_msg, pcl_footprint_transform);
135 |
136 | // Publish OccupancyGrid map
137 | cloud_map_pub.publish(gridmap.toMapMsg());
138 | if (DEBUG) std::cout << "Publish time: " << ros::Time::now() - t0 << std::endl;
139 | if (DEBUG) std::cout << "Callback time: " << ros::Time::now() - t_start << std::endl;
140 | }
141 |
142 |
143 | int main(int argc, char **argv)
144 | {
145 | af::info();
146 |
147 | ros::init(argc, argv, "pcl_to_gridmap");
148 | ros::NodeHandle nh, priv_nh("~");
149 |
150 | priv_nh.param("map_frame_id", map_frame_id, "base_footprint");
151 | priv_nh.param("height", map_height, 50.0);
152 | priv_nh.param("width", map_width, 50.0);
153 | priv_nh.param("cell_size", cell_size, 0.2);
154 | priv_nh.param("floor_filter", floor_filter, false);
155 | priv_nh.param("heightmap_threshold", heightmap_threshold, 0.15);
156 | priv_nh.param("heightmap_cell_size", heightmap_cell_size, 0.25);
157 | priv_nh.param("max_height", max_height, 2.5);
158 | priv_nh.param("vehicle_box_size", vehicle_box_size, 2.0);
159 | priv_nh.param("DEBUG", DEBUG, true);
160 |
161 | cloud_map_pub = nh.advertise("hypergrid/pcl_to_gridmap", 2);
162 | ros::Subscriber cloud_sub = nh.subscribe("velodyne_points", 5, cloud_callback);
163 |
164 | tf_listener = new tf::TransformListener();
165 |
166 | ros::Rate r(10.0);
167 | while(ros::ok())
168 | {
169 | ros::spinOnce();
170 | r.sleep();
171 | }
172 |
173 | return 0;
174 | }
175 |
--------------------------------------------------------------------------------