├── HumbleDockerfile
├── LICENSE
├── Makefile
├── README.md
├── resources
├── Successrateenv.png
├── frame.jpg
├── frame.png
└── motivation.png
└── ros_ws
├── Demo.sh
├── data
├── Env1.png
├── Env1.yaml
├── Env2.png
├── Env2.yaml
├── Env3.png
├── Env3.yaml
├── cmcl_realA.config
└── cmcl_realB.config
└── src
└── cmcl
├── cmcl_msgs
├── CMakeLists.txt
├── msg
│ ├── Cluster.msg
│ ├── Coreset.msg
│ ├── DET.msg
│ ├── DistributionExchange.msg
│ ├── KMeansCluster.msg
│ ├── ParticleFilter.msg
│ ├── Prediction.msg
│ ├── ProrokClusterAbstraction.msg
│ └── RobotDetection.msg
└── package.xml
└── cmcl_ros
├── CMakeLists.txt
├── include
└── RosUtils.h
├── launch
└── cmcl_real.launch
├── ncore
├── CMakeLists.txt
├── data
│ └── config
│ │ ├── Env2.png
│ │ ├── Env2.yaml
│ │ └── cmcl.config
├── include
│ ├── BeamEnd.h
│ ├── Cluster.h
│ ├── ClusterAbstraction.h
│ ├── DensityEstimationTree.h
│ ├── DistributionData.h
│ ├── DistributionExchange.h
│ ├── FSR.h
│ ├── GMap.h
│ ├── GoodPointsCompression.h
│ ├── KMeansClustering.h
│ ├── Lidar2D.h
│ ├── LidarData.h
│ ├── MCL.h
│ ├── Particle.h
│ ├── ParticleFilter.h
│ ├── ProrokClustering.h
│ ├── Resampling.h
│ ├── SetStatistics.h
│ ├── StandardThinning.h
│ └── Utils.h
├── src
│ ├── BeamEnd.cpp
│ ├── CMakeLists.txt
│ ├── Cluster.cpp
│ ├── ClusterAbstraction.cpp
│ ├── DensityEstimationTree.cpp
│ ├── DistributionExchange.cpp
│ ├── FSR.cpp
│ ├── GMap.cpp
│ ├── GoodPointsCompression.cpp
│ ├── KMeansClustering.cpp
│ ├── Lidar2D.cpp
│ ├── MCL.cpp
│ ├── Particle.cpp
│ ├── ParticleFilter.cpp
│ ├── ProrokClustering.cpp
│ ├── Resampling.cpp
│ ├── SetStatistics.cpp
│ ├── StandardThinning.cpp
│ ├── Utils.cpp
│ └── dist_compress.py
└── tst
│ ├── BenchmarkClustering.cpp
│ ├── CMakeLists.txt
│ ├── Clustering.pdf
│ ├── Clustering4.pdf
│ ├── ClusteringNotSym.pdf
│ ├── Clusteringfail.pdf
│ ├── Clusteringsuccess.pdf
│ ├── DumpClustering.cpp
│ ├── TestUtils.cpp
│ ├── TestUtils.h
│ ├── UnitTests.cpp
│ └── particle_test.py
├── package.xml
├── rviz
└── cmcl_real.rviz
└── src
├── Depth4DetectionNode.cpp
├── DetectionNoiseNode.cpp
├── EvalNode.cpp
├── LidarScan2PointCloudNode.cpp
├── MCLNode.cpp
├── MapLoaderNode.cpp
├── OprtitrackPublisherNode.cpp
├── RelativePosedNode.cpp
├── RosUtils.cpp
└── UVDetection2WorldNode.cpp
/HumbleDockerfile:
--------------------------------------------------------------------------------
1 | FROM ros:humble
2 | ENV DEBIAN_FRONTEND noninteractive
3 | ENV NVIDIA_VISIBLE_DEVICES all
4 | ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute
5 |
6 | RUN apt-get update && apt-get install -y \
7 | locales \
8 | python3-pip \
9 | ros-humble-xacro \
10 | ros-humble-launch-xml \
11 | ros-humble-cv-bridge \
12 | ros-humble-launch-testing-ament-cmake \
13 | ros-humble-robot-state-publisher \
14 | ros-humble-joint-state-publisher \
15 | ros-humble-joint-state-publisher-gui \
16 | ros-humble-joy \
17 | ros-humble-joy-teleop \
18 | ros-humble-tf-transformations \
19 | ros-humble-pcl-conversions \
20 | ros-humble-pcl-msgs \
21 | ros-humble-pcl-ros \
22 | libopus-dev \
23 | nano \
24 | && rm -rf /var/lib/apt/lists/*
25 |
26 | RUN locale-gen en_US.UTF-8
27 |
28 | SHELL ["/bin/bash", "-c"]
29 |
30 | RUN python3 -m pip install -U numpy numpy-quaternion pyyaml
31 | RUN apt-get update && \
32 | apt-get install -y nlohmann-json3-dev libgtest-dev libeigen3-dev libarmadillo-dev libensmallen-dev libcereal-dev libstb-dev g++ cmake && rm -rf /var/lib/apt/lists/*
33 | RUN mkdir -p /tmp && cd /tmp && git clone https://github.com/mlpack/mlpack.git && cd /tmp/mlpack && cmake -S . -B build && cmake --build build --target install && rm -rf /tmp
34 |
35 | RUN mkdir /tmp
36 | RUN chmod 1777 /tmp
37 | RUN apt-get update && apt-get install -y \
38 | ros-humble-rviz2 \
39 | ros-humble-navigation2 \
40 | ros-humble-nav2-bringup \
41 | ros-humble-slam-toolbox \
42 | ros-humble-rqt \
43 | ros-humble-rqt-image-view \
44 | ros-humble-rqt-tf-tree \
45 | ros-humble-joy \
46 | ros-humble-joy-teleop \
47 | ros-humble-rosbag2-storage-mcap \
48 | && rm -rf /var/lib/apt/lists/*
49 |
50 |
51 |
52 | RUN python3 -m pip install goodpoints pybind11 pandas
53 |
54 | COPY ros_ws ros_ws
55 |
56 | RUN cd /usr/include/ && sudo ln -sf eigen3/Eigen Eigen
57 |
58 | RUN cd /ros_ws/src/cmcl/cmcl_ros/ncore && cmake -S . -B build && cmake --build build
59 |
60 | RUN cd /ros_ws && source /ros_entrypoint.sh && colcon build --packages-up-to robomaster_ros
61 |
62 | RUN cd /ros_ws && source /ros_entrypoint.sh && \
63 | colcon build --packages-select cmcl_msgs cmcl_ros --cmake-clean-cache && rm -r build log
64 |
65 |
66 | WORKDIR /ros_ws
67 |
68 |
69 | #RUN chmod 1777 /tmp
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 IDSIA Robotics Group
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | build:
2 | ifdef foxy
3 | docker build -f Dockerfile -t mclfoxy .
4 | endif
5 | ifdef humble
6 | docker build -f HumbleDockerfile -t mclhumble .
7 | endif
8 |
9 | run:
10 | ifdef foxy
11 | docker run --rm -it --init --gpus=all --network host --pid host --ipc host -e "DISPLAY" --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
12 | -v $(CURDIR)/ros_ws:/ros_ws mclfoxy
13 | endif
14 | ifdef humble
15 | docker run --rm -it --init --gpus=all --privileged --network host --pid host --ipc host -e "DISPLAY" --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
16 | -v $(CURDIR)/ros_ws:/ros_ws mclhumble
17 | endif
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Resource-Aware Collaborative Monte Carlo Localization with Distribution Compression
2 | This repository contains the implementation of the following [publication](https://arxiv.org/abs/2404.02010):
3 | ```bibtex
4 | @misc{zimmerman2024arxiv,
5 | title={{Resource-Aware Collaborative Monte Carlo Localization with Distribution Compression}},
6 | author={Nicky Zimmerman and Alessandro Giusti and Jérôme Guzzi},
7 | year={2024},
8 | eprint={2404.02010},
9 | archivePrefix={arXiv},
10 | primaryClass={cs.RO}
11 | }
12 | ```
13 | Under review for IROS 2024. Our live demo:
14 |
15 | [](https://www.youtube.com/watch?v=dgssNAHPvvM)
16 |
17 |
18 |
19 | ## Abstract
20 | Global localization is essential in enabling robot autonomy, and collaborative localization is key for multi-robot systems.
21 | In this paper, we address the task of collaborative global localization under computational and communication constraints. We propose a method which reduces the amount of information exchanged and the computational cost. We also analyze, implement and open-source seminal approaches, which we believe to be a valuable contribution to the community.
22 | We exploit techniques for distribution compression in near-linear time, with error guarantees.
23 | We evaluate our approach and the implemented baselines on multiple challenging scenarios, simulated and real-world. Our approach can run online on an onboard computer. We release an open-source C++/ROS2 implementation of our approach, as well as the baselines.
24 |
25 |
26 |
27 |
28 | ## Results
29 | We conducted a thorough evaluation of the different approaches to cooperative localization. We present our experiments to show the capabilities of our method, Compress++ MCL.
30 | The results support the claims that our proposed approach (i) improves collaborative localization, (ii) decreases the required band-width, (iii) reduces the computational load, (iv) runs online
31 | on an onboard computer.
32 |
33 |
34 |
35 |
36 |
37 | ## Installation
38 | We provide Docker installations for ROS 2 Humble. Make sure you installed Docker Engine and NVidia container so you can run Dokcer with GPU support.
39 | Download the external resources in the host machine into the `/ros_ws/src` directory
40 | ```bash
41 | git clone git@github.com:jeguzzi/robomaster_ros.git
42 | ```
43 | The package is necessarily for running the demo as the rosbag includes RoboMaster specific detection messages. However, they are not strictly necessary for any of the approaches, and the dependency can be removed with a bit of work on the ROS wrapper. In the root directory, run
44 | ```bash
45 | sudo make humble=1
46 | ```
47 | To build the Docker. To enable RVIZ visualization from the Docker run in the host machine
48 | ```bash
49 | xhost +local:docker
50 | ```
51 | To run the Docker
52 | ```bash
53 | sudo make run humble=1
54 | ```
55 | The core code is C++ with no ROS dependency. To build the ncore library in the docker, run
56 | ```bash
57 | cd src/cmcl/cmcl_ros/ncore && mkdir build && cd build && cmake .. -DBUILD_TESTING=1 && make -j12
58 | ./bin/UnitTests
59 | ```
60 | Run the unit tests to verify the installation is successful. Then to build the ROS 2 wrapper
61 | ```bash
62 | cd /ros_ws && . /opt/ros/humble/setup.bash && colcon build && . install/setup.bash
63 | ```
64 |
65 | ## Running the Algo
66 | You can download the rosbag from [here](https://drive.switch.ch/index.php/s/Of0l9iPzjmQ8CXc). place it in the `/ros_ws/rosbags` directory and you can use the Demo.sh script to run it.
67 | Remember to enable RVIZ in your docker.
68 |
69 | ### MCLNode
70 | The main node which is a ROS 2 wrapper to the C++ implementation of the different approaches.
71 | Requires as input a minimum of 2 topics, Odometry and PointCloud2, for the single robot range-based MCL. To enable collaborative localization, RobotDetection messages are needed.
72 | These messages are agnostic to detection algorithm and if you wish to use your own detection pipeline, just write a ROS node that publishes these messages.
73 | The topic names are configurable through the launch file. This runs the correct and predict steps asynchronously, so correct is executed whenever we have odometry and predict is executed when an observation arrives.
74 | MCLNodE publishes PoseWithCovarianceStamped messages with the pose prediction. To see the predictions in RVIZ, run
75 | ```bash
76 | ros2 launch cmcl_ros cmcl_real.launch
77 | ```
78 |
79 | ### LidarScan2PointCloudNode
80 | This nodes converts the LaserScan messages from our YDLIDAR Tmini Pro 2D LiDAR to a point cloud in base_link frame.
81 |
82 | ### DetectionNoiseNode
83 | This node is used to add noise to "perfect" detections generated by our simulation, to make the scenarios more realistic.
84 |
85 | ### UVDetection2WorldNode
86 | This node takes as input the RoboMaster Detection messages, which are 2D bounding boxes in image coordinates, and provides a 3D position of the detected robot in the base_link frame.
87 | The distance to the detected robot is computed using the known dimensions of the RoboMaster and the 2D bounding boxes.
88 |
89 | ### EvalNode
90 | This node was used to log the localization predictions for the evluation.
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/resources/Successrateenv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idsia-robotics/Collaborative-Monte-Carlo-Localization/918d41678b1eaca9ebbaf0ab47427f127ac0f1c3/resources/Successrateenv.png
--------------------------------------------------------------------------------
/resources/frame.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idsia-robotics/Collaborative-Monte-Carlo-Localization/918d41678b1eaca9ebbaf0ab47427f127ac0f1c3/resources/frame.jpg
--------------------------------------------------------------------------------
/resources/frame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idsia-robotics/Collaborative-Monte-Carlo-Localization/918d41678b1eaca9ebbaf0ab47427f127ac0f1c3/resources/frame.png
--------------------------------------------------------------------------------
/resources/motivation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idsia-robotics/Collaborative-Monte-Carlo-Localization/918d41678b1eaca9ebbaf0ab47427f127ac0f1c3/resources/motivation.png
--------------------------------------------------------------------------------
/ros_ws/Demo.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 |
4 | #find . -name "*.csv" -type f -delete
5 |
6 |
7 | declare -a DIST
8 | DIST[0]="-1"
9 | DIST[1]="1"
10 | DIST[2]="3"
11 | DIST[3]="2"
12 | DIST[4]="4"
13 | DIST[5]="0"
14 | DIST[6]="0"
15 |
16 | declare -a DETECT
17 | DETECT[0]="false"
18 | DETECT[1]="true"
19 | DETECT[2]="true"
20 | DETECT[3]="true"
21 | DETECT[4]="true"
22 | DETECT[5]="true"
23 | DETECT[6]="true"
24 |
25 | declare -a ALGO
26 | ALGO[0]="MCL"
27 | ALGO[1]="FOX_CMCL"
28 | ALGO[2]="PROROK_CMCL"
29 | ALGO[3]="KMEANS_CMCL"
30 | ALGO[4]="GOODPOINTS_CMCL"
31 | ALGO[5]="THIN_CMCL"
32 | ALGO[6]="NAIVE_CMCL"
33 |
34 | declare -a MAP
35 | MAP[0]="Env1"
36 | MAP[1]="Env2"
37 | MAP[2]="Env3"
38 |
39 |
40 | particleNum=10000
41 | path1="/ros_ws/dump/"
42 | rosbagDir="/ros_ws/rosbags/"
43 | seq="demo"
44 | m=2
45 | mapName=${MAP[ $m ]}
46 |
47 | source /ros_ws/install/setup.bash
48 |
49 | a=4
50 | run=0
51 | detect=${DETECT[ $a ]}
52 | dist=${DIST[ $a ]}
53 | algo=${ALGO[ $a ]}
54 | csv="$path1/$algo/$mapName/S$s/"
55 | echo $csv
56 |
57 |
58 | ros2 launch cmcl_ros cmcl_real.launch mapName:="$mapName" detection:="$detect" distType:="$dist" csvPath:="$csv" run:="$run" &
59 | sleep 5
60 | ros2 lifecycle set /map_server activate
61 | rosbagPath="$rosbagDir/$seq/"
62 | echo $rosbagPath
63 | ros2 bag play $rosbagPath
64 |
65 | kill $(pgrep -f rviz2)
66 | kill $(pgrep -f DetectionNoiseNode)
67 | kill $(pgrep -f MCLNode)
68 | kill $(pgrep -f LidarScan2PointCloudNode)
69 | kill $(pgrep -f EvalNode)
70 | kill $(pgrep -f map_server)
71 | kill $(pgrep -f UVDetection2WorldNode)
72 | kill $(pgrep -f RelativePosedNode)
73 | kill $(pgrep -f cmcl.launch)
74 | kill $(pgrep -f OprtitrackPublisherNode)
75 | pkill -9 ros2
76 | ros2 daemon stop
77 |
78 |
--------------------------------------------------------------------------------
/ros_ws/data/Env1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idsia-robotics/Collaborative-Monte-Carlo-Localization/918d41678b1eaca9ebbaf0ab47427f127ac0f1c3/ros_ws/data/Env1.png
--------------------------------------------------------------------------------
/ros_ws/data/Env1.yaml:
--------------------------------------------------------------------------------
1 | image: Env1.png
2 | resolution: 0.05
3 | origin: [-16.0, -16.0, 0]
4 | negate: 0
5 | occupied_thresh: 0.65
6 | free_thresh: 0.25
7 | mode: trinary
8 |
--------------------------------------------------------------------------------
/ros_ws/data/Env2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idsia-robotics/Collaborative-Monte-Carlo-Localization/918d41678b1eaca9ebbaf0ab47427f127ac0f1c3/ros_ws/data/Env2.png
--------------------------------------------------------------------------------
/ros_ws/data/Env2.yaml:
--------------------------------------------------------------------------------
1 | image: Env2.png
2 | resolution: 0.05
3 | origin: [-16, -16, 0]
4 | negate: 0
5 | occupied_thresh: 0.65
6 | free_thresh: 0.25
7 | mode: trinary
8 |
--------------------------------------------------------------------------------
/ros_ws/data/Env3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idsia-robotics/Collaborative-Monte-Carlo-Localization/918d41678b1eaca9ebbaf0ab47427f127ac0f1c3/ros_ws/data/Env3.png
--------------------------------------------------------------------------------
/ros_ws/data/Env3.yaml:
--------------------------------------------------------------------------------
1 | image: Env3.png
2 | resolution: 0.05
3 | origin: [-10.0, -10.0, 0]
4 | negate: 0
5 | occupied_thresh: 0.65
6 | free_thresh: 0.25
7 | mode: trinary
8 |
--------------------------------------------------------------------------------
/ros_ws/data/cmcl_realA.config:
--------------------------------------------------------------------------------
1 | {
2 | "mapPath": "Env3.yaml",
3 | "numParticles": 2000,
4 | "sensorModel": {
5 | "likelihoodSigma": 0.15,
6 | "maxDist": 20.0,
7 | "type": "BeamEnd",
8 | "weightingScheme": 1
9 | },
10 | "detectionModel": {
11 | "kmeans":
12 | {
13 | "clusters": 8,
14 | "iterations" : 5
15 | },
16 | "det":
17 | {
18 | "minSize": 500,
19 | "maxSize": 1000
20 | },
21 | "prorok":
22 | {
23 | "clusters": 8
24 | },
25 | "thinning":
26 | {
27 | "clusters": 64
28 | },
29 | "detectionNoise":
30 | {
31 | "x": 0.1,
32 | "y": 0.1
33 | },
34 | "penalty" : 0.000000001,
35 | "alpha" : 0.06,
36 | "clusters": 10000,
37 | "type" : 3
38 | },
39 | "tracking":
40 | {
41 | "mode" : false,
42 | "x" : [8.61341, 8.61341],
43 | "y" : [-3.3749, -3.3749],
44 | "yaw" : [0.03733, 0.03733] ,
45 | "cov_x" : [0.5, 0.5],
46 | "cov_y" : [0.5, 0.5],
47 | "cov_yaw" : [0.5, 0.5]
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ros_ws/data/cmcl_realB.config:
--------------------------------------------------------------------------------
1 | {
2 | "mapPath": "Env3.yaml",
3 | "numParticles": 2000,
4 | "sensorModel": {
5 | "likelihoodSigma": 0.3,
6 | "maxDist": 20.0,
7 | "type": "BeamEnd",
8 | "weightingScheme": 1
9 | },
10 | "detectionModel": {
11 | "kmeans":
12 | {
13 | "clusters": 8,
14 | "iterations" : 5
15 | },
16 | "det":
17 | {
18 | "minSize": 500,
19 | "maxSize": 1000
20 | },
21 | "prorok":
22 | {
23 | "clusters": 8
24 | },
25 | "thinning":
26 | {
27 | "clusters": 64
28 | },
29 | "detectionNoise":
30 | {
31 | "x": 0.1,
32 | "y": 0.1
33 | },
34 | "penalty" : 0.000000001,
35 | "alpha" : 0.06,
36 | "clusters": 10000,
37 | "type" : 3
38 | },
39 | "tracking":
40 | {
41 | "mode" : false,
42 | "x" : [8.61341, 8.61341],
43 | "y" : [-3.3749, -3.3749],
44 | "yaw" : [0.03733, 0.03733] ,
45 | "cov_x" : [0.5, 0.5],
46 | "cov_y" : [0.5, 0.5],
47 | "cov_yaw" : [0.5, 0.5]
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 | project(cmcl_msgs)
3 |
4 | # Default to C99
5 | if(NOT CMAKE_C_STANDARD)
6 | set(CMAKE_C_STANDARD 99)
7 | endif()
8 |
9 | # Default to C++14
10 | if(NOT CMAKE_CXX_STANDARD)
11 | set(CMAKE_CXX_STANDARD 14)
12 | endif()
13 |
14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
15 | add_compile_options(-Wall -Wextra -Wpedantic)
16 | endif()
17 |
18 | # find dependencies
19 | find_package(ament_cmake REQUIRED)
20 | # uncomment the following section in order to fill in
21 | # further dependencies manually.
22 | # find_package( REQUIRED)
23 |
24 | find_package(std_msgs REQUIRED)
25 | find_package(geometry_msgs REQUIRED)
26 | find_package(rosidl_default_generators REQUIRED)
27 |
28 | rosidl_generate_interfaces(${PROJECT_NAME}
29 | "msg/ProrokClusterAbstraction.msg"
30 | "msg/KMeansCluster.msg"
31 | "msg/DET.msg"
32 | "msg/Coreset.msg"
33 | "msg/ParticleFilter.msg"
34 | "msg/Cluster.msg"
35 | "msg/Prediction.msg"
36 | "msg/DistributionExchange.msg"
37 | "msg/RobotDetection.msg"
38 | DEPENDENCIES geometry_msgs std_msgs # Add packages that above messages depend on, in this case geometry_msgs for Sphere.msg
39 | )
40 |
41 | if(BUILD_TESTING)
42 | find_package(ament_lint_auto REQUIRED)
43 | # the following line skips the linter which checks for copyrights
44 | # uncomment the line when a copyright and license is not present in all source files
45 | #set(ament_cmake_copyright_FOUND TRUE)
46 | # the following line skips cpplint (only works in a git repo)
47 | # uncomment the line when this package is not in a git repo
48 | #set(ament_cmake_cpplint_FOUND TRUE)
49 | ament_lint_auto_find_test_dependencies()
50 | endif()
51 |
52 | ament_package()
53 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/Cluster.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | float32[] centroid
3 | float32[] mu
4 | float32[] variance
5 | float32 weight
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/Coreset.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | geometry_msgs/Pose[] particles
3 | float32[] weights
4 | float32[] variance
5 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/DET.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | uint8[] tree
3 | float32[] variance
4 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/DistributionExchange.msg:
--------------------------------------------------------------------------------
1 |
2 | std_msgs/Header header
3 | uint8 type
4 | int32 observer_id
5 | int32 detected_id
6 | cmcl_msgs/ParticleFilter filter
7 | cmcl_msgs/Coreset coreset
8 | cmcl_msgs/DET det
9 | cmcl_msgs/Cluster[] clusters
10 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/KMeansCluster.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | float32[] mean
3 | float32[] variance
4 | float32 weight
5 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/ParticleFilter.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | geometry_msgs/Pose[] particles
3 | float32[] weights
4 | float32[] variance
5 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/Prediction.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | uint8 type
3 | geometry_msgs/PoseWithCovarianceStamped pose
4 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/ProrokClusterAbstraction.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | float32[] centroid
3 | float32[] mu
4 | float32[] variance
5 | float32 weight
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/msg/RobotDetection.msg:
--------------------------------------------------------------------------------
1 | std_msgs/Header header
2 | int32 observer_id
3 | int32 detected_id
4 | geometry_msgs/Pose pose
5 | uint8 type
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_msgs/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | cmcl_msgs
5 | 0.0.0
6 | TODO: Package description
7 | nickybones
8 | TODO: License declaration
9 |
10 | ament_cmake
11 |
12 | ament_lint_auto
13 | ament_lint_common
14 | geometry_msgs
15 | std_msgs
16 |
17 | rosidl_default_generators
18 |
19 | rosidl_default_runtime
20 |
21 | rosidl_interface_packages
22 |
23 |
24 | ament_cmake
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 | project(cmcl_ros)
3 |
4 | SET(OpenCV_MIN_VERSION "4.2.0")
5 |
6 |
7 | #colcon build --allow-overriding cv_bridge image_geometry
8 |
9 | # Default to C++14
10 | if(NOT CMAKE_CXX_STANDARD)
11 | set(CMAKE_CXX_STANDARD 14)
12 | endif()
13 |
14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
15 | #add_compile_options(-Wall -Wextra -Wpedantic)
16 | endif()
17 |
18 |
19 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/)
20 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/lib/)
21 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)
22 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ncore/include/)
23 |
24 |
25 | set(RESULTS_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/results)
26 | file(MAKE_DIRECTORY ${RESULTS_OUTPUT_DIRECTORY})
27 |
28 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${RESULTS_OUTPUT_DIRECTORY}/lib)
29 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${RESULTS_OUTPUT_DIRECTORY}/lib)
30 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${RESULTS_OUTPUT_DIRECTORY}/bin)
31 | link_directories(${CMAKE_CURRENT_SOURCE_DIR}/ncore/build/lib)
32 |
33 |
34 |
35 |
36 | # find dependencies
37 | find_package(ament_cmake REQUIRED)
38 | find_package(rclcpp REQUIRED)
39 | find_package(sensor_msgs REQUIRED)
40 | find_package(std_msgs REQUIRED)
41 | find_package(nav_msgs REQUIRED)
42 | find_package(geometry_msgs REQUIRED)
43 | find_package(message_filters REQUIRED)
44 | find_package(tf2 REQUIRED)
45 | find_package(tf2_ros REQUIRED)
46 | find_package(tf2_msgs REQUIRED)
47 | find_package(Eigen3 REQUIRED)
48 | find_package(OpenCV ${OpenCV_MIN_VERSION} REQUIRED)
49 | find_package(pcl_conversions REQUIRED)
50 | find_package(nav2_map_server REQUIRED)
51 | find_package(pcl_ros REQUIRED)
52 | find_package(cmcl_msgs REQUIRED)
53 | find_package(robomaster_msgs REQUIRED)
54 | find_package(cv_bridge REQUIRED)
55 | find_package(Boost REQUIRED COMPONENTS system)
56 | find_package(nlohmann_json 3.2.0 REQUIRED)
57 | find_package(OpenMP)
58 | if (OPENMP_FOUND)
59 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
60 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
61 | set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
62 | endif()
63 |
64 | set(pybind11_DIR /usr/local/lib/python3.10/dist-packages/)
65 | set(PYTHON_INCLUDE_DIR "/usr/include/python3.10")
66 | find_package (Python COMPONENTS Interpreter Development)
67 | if(Python_FOUND)
68 | message(STATUS "Found Python version ${Python_VERSION}")
69 | include_directories(${PYTHON_INCLUDE_DIR})
70 | endif(Python_FOUND)
71 | find_package(pybind11 REQUIRED)
72 |
73 | find_package(Armadillo REQUIRED)
74 | if (ARMADILLO_FOUND)
75 | include_directories(${ARMADILLO_INCLUDE_DIRS})
76 | endif()
77 |
78 |
79 | find_package(LAPACK REQUIRED)
80 | include_directories(${LAPACK_INCLUDE_DIRS})
81 |
82 | if(BUILD_TESTING)
83 | find_package(ament_lint_auto REQUIRED)
84 | # the following line skips the linter which checks for copyrights
85 | # uncomment the line when a copyright and license is not present in all source files
86 | #set(ament_cmake_copyright_FOUND TRUE)
87 | # the following line skips cpplint (only works in a git repo)
88 | # uncomment the line when this package is not in a git repo
89 | #set(ament_cmake_cpplint_FOUND TRUE)
90 | ament_lint_auto_find_test_dependencies()
91 | endif()
92 |
93 | #add_subdirectory("src")
94 | add_library(NCORE STATIC IMPORTED)
95 | set_target_properties(NCORE PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/ncore/build/lib/libNCORE.a)
96 |
97 | add_executable(MCLNode src/MCLNode.cpp src/RosUtils.cpp)
98 | add_executable(LidarScan2PointCloudNode src/LidarScan2PointCloudNode.cpp src/RosUtils.cpp)
99 | add_executable(EvalNode src/EvalNode.cpp src/RosUtils.cpp)
100 | add_executable(Depth4DetectionNode src/Depth4DetectionNode.cpp src/RosUtils.cpp)
101 | add_executable(UVDetection2WorldNode src/UVDetection2WorldNode.cpp src/RosUtils.cpp)
102 | add_executable(DetectionNoiseNode src/DetectionNoiseNode.cpp src/RosUtils.cpp)
103 | add_executable(RelativePosedNode src/RelativePosedNode.cpp src/RosUtils.cpp)
104 | add_executable(OprtitrackPublisherNode src/OprtitrackPublisherNode.cpp src/RosUtils.cpp)
105 | add_executable(MapLoaderNode src/MapLoaderNode.cpp src/RosUtils.cpp)
106 |
107 |
108 |
109 | target_link_libraries(MCLNode NCORE ${Boost_SYSTEM_LIBRARY} ${ARMADILLO_LIBRARIES} ${LAPACK_LIBRARIES} pybind11::embed)
110 | target_link_libraries(LidarScan2PointCloudNode NCORE ${Boost_SYSTEM_LIBRARY} pybind11::embed)
111 | target_link_libraries(EvalNode NCORE ${Boost_SYSTEM_LIBRARY} pybind11::embed)
112 | target_link_libraries(Depth4DetectionNode NCORE ${Boost_SYSTEM_LIBRARY} pybind11::embed)
113 | target_link_libraries(UVDetection2WorldNode NCORE ${Boost_SYSTEM_LIBRARY} pybind11::embed)
114 | target_link_libraries(DetectionNoiseNode NCORE ${Boost_SYSTEM_LIBRARY} pybind11::embed)
115 | target_link_libraries(RelativePosedNode NCORE ${Boost_SYSTEM_LIBRARY} pybind11::embed)
116 | target_link_libraries(OprtitrackPublisherNode NCORE ${Boost_SYSTEM_LIBRARY} pybind11::embed)
117 | target_link_libraries(MapLoaderNode NCORE ${Boost_SYSTEM_LIBRARY})
118 |
119 |
120 | ament_target_dependencies(MCLNode rclcpp std_msgs sensor_msgs nav_msgs cmcl_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros pcl_conversions nlohmann_json OpenCV)
121 |
122 | ament_target_dependencies(LidarScan2PointCloudNode rclcpp std_msgs sensor_msgs nav_msgs cmcl_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros pcl_conversions nlohmann_json OpenCV)
123 |
124 |
125 | ament_target_dependencies(EvalNode rclcpp std_msgs sensor_msgs nav_msgs cmcl_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros pcl_conversions nlohmann_json OpenCV)
126 |
127 | ament_target_dependencies(Depth4DetectionNode rclcpp std_msgs sensor_msgs nav_msgs cmcl_msgs robomaster_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros pcl_conversions nlohmann_json OpenCV)
128 |
129 | ament_target_dependencies(UVDetection2WorldNode rclcpp std_msgs sensor_msgs nav_msgs cmcl_msgs robomaster_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros cv_bridge pcl_conversions nlohmann_json OpenCV)
130 |
131 | ament_target_dependencies(DetectionNoiseNode rclcpp std_msgs sensor_msgs nav_msgs cmcl_msgs robomaster_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros cv_bridge pcl_conversions nlohmann_json OpenCV)
132 |
133 | ament_target_dependencies(RelativePosedNode rclcpp std_msgs sensor_msgs nav_msgs cmcl_msgs robomaster_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros cv_bridge pcl_conversions nlohmann_json OpenCV)
134 |
135 |
136 | ament_target_dependencies(OprtitrackPublisherNode rclcpp std_msgs sensor_msgs nav_msgs cmcl_msgs robomaster_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros cv_bridge pcl_conversions nlohmann_json OpenCV)
137 |
138 | ament_target_dependencies(MapLoaderNode rclcpp std_msgs sensor_msgs nav2_map_server nav_msgs cmcl_msgs robomaster_msgs geometry_msgs message_filters tf2 tf2_ros tf2_msgs pcl_ros cv_bridge pcl_conversions nlohmann_json OpenCV)
139 |
140 |
141 | install(TARGETS
142 | MCLNode
143 | LidarScan2PointCloudNode
144 | EvalNode
145 | Depth4DetectionNode
146 | UVDetection2WorldNode
147 | DetectionNoiseNode
148 | RelativePosedNode
149 | OprtitrackPublisherNode
150 | MapLoaderNode
151 | DESTINATION lib/${PROJECT_NAME}
152 | )
153 |
154 |
155 | install(DIRECTORY
156 | #python_cmcl
157 | DESTINATION lib/${PROJECT_NAME}
158 | )
159 |
160 | install(DIRECTORY
161 | launch
162 | DESTINATION share/${PROJECT_NAME}
163 | )
164 |
165 | install(DIRECTORY
166 | #config
167 | DESTINATION share/${PROJECT_NAME}
168 | )
169 |
170 | install(DIRECTORY
171 | rviz
172 | DESTINATION share/${PROJECT_NAME}
173 | )
174 |
175 | ament_package()
176 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/include/RosUtils.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2021- University of Bonn #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: RosUtils.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef ROSUTILS_H
14 | #define ROSUTILS_H
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | //#include
22 | //#include
23 | #include
24 | #include
25 | #include
26 |
27 |
28 | // Eigen::Vector3f OdomMsg2Pose2D(const nav_msgs::msg::Odometry::ConstSharedPtr odom);
29 |
30 | // Eigen::Vector3f PoseMsg2Pose2D(const geometry_msgs::msg::PoseStamped::ConstSharedPtr& poseMsg);
31 |
32 | // std::vector OdomMsg2Pose3D(const nav_msgs::msg::Odometry::ConstSharedPtr odom);
33 |
34 | // std::vector PoseMsg2Pose3D(const geometry_msgs::msg::PoseStamped::ConstSharedPtr& odom);
35 |
36 | // geometry_msgs::msg::PoseStamped Pose2D2PoseMsg(Eigen::Vector3f pose2d);
37 |
38 |
39 | // //pcl::PointCloud Vec2PointCloud(const std::vector& points3d, Eigen::Vector3f rgb);
40 |
41 |
42 | // geometry_msgs::msg::PoseWithCovarianceStamped Pred2PoseWithCov(Eigen::Vector3d pred, Eigen::Matrix3d cov);
43 |
44 |
45 | Eigen::Vector3f OdomMsg2Pose2D(const nav_msgs::msg::Odometry::ConstSharedPtr& odom);
46 |
47 | Eigen::Vector3f PoseMsg2Pose2D(const geometry_msgs::msg::PoseStamped::ConstSharedPtr& poseMsg);
48 |
49 | std::vector OdomMsg2Pose3D(const nav_msgs::msg::Odometry::ConstSharedPtr& odom);
50 |
51 | std::vector PoseMsg2Pose3D(const geometry_msgs::msg::PoseStamped::ConstSharedPtr& odom);
52 |
53 | geometry_msgs::msg::PoseStamped Pose2D2PoseMsg(Eigen::Vector3f pose2d);
54 |
55 |
56 | pcl::PointCloud Vec2PointCloud(const std::vector& points3d, Eigen::Vector3f rgb);
57 |
58 | pcl::PointCloud Vec2PointCloud(const std::vector& points3d);
59 |
60 | pcl::PointCloud Vec2RGBPointCloud(const std::vector& points3d, std::vector rgb);
61 |
62 |
63 | pcl::PointCloud ManyVec2PointCloud(const std::vector>& points3d, std::vector rgb);
64 |
65 |
66 | geometry_msgs::msg::PoseWithCovarianceStamped Pred2PoseWithCov(Eigen::Vector3d pred, Eigen::Matrix3d cov);
67 |
68 | //sensor_msgs::msg::Image CVMat2ImgMsg(const cv::Mat& img, std_msgs::Header header, const std::string& type);
69 |
70 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/launch/cmcl_real.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16.0)
2 | project(ncore)
3 | SET(OpenCV_MIN_VERSION "4.2.0")
4 |
5 | set(CMAKE_CXX_FLAGS "-std=c++11 -O3 -fopenmp -Wall ${CMAKE_CXX_FLAGS}")
6 | set(CMAKE_CXX_STANDARD 14)
7 |
8 | find_package(OpenMP)
9 | if (OPENMP_FOUND)
10 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
11 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
12 | set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
13 | endif()
14 |
15 |
16 |
17 | find_package(Eigen3 REQUIRED)
18 | if(Eigen3_FOUND)
19 | message(STATUS "Found OpenCV version ${Eigen3}")
20 | message(STATUS "OpenCV directories: ${Eigen3_INCLUDE_DIRS}")
21 | include_directories(${Eigen3_INCLUDE_DIRS})
22 | else()
23 | message(FATAL_ERROR "Eigen3 not found, please read the README.md")
24 | endif(Eigen3_FOUND)
25 | set(pybind11_DIR /usr/local/lib/python3.10/dist-packages/)
26 | set(PYTHON_INCLUDE_DIR "/usr/include/python3.10")
27 | find_package (Python COMPONENTS Interpreter Development)
28 | if(Python_FOUND)
29 | message(STATUS "Found Python version ${Python_VERSION}")
30 | include_directories(${PYTHON_INCLUDE_DIR})
31 | endif(Python_FOUND)
32 | find_package(pybind11 REQUIRED)
33 |
34 |
35 | find_package(OpenCV ${OpenCV_MIN_VERSION} REQUIRED)
36 | if(OpenCV_FOUND)
37 | message(STATUS "Found OpenCV version ${OpenCV_VERSION}")
38 | message(STATUS "OpenCV directories: ${OpenCV_INCLUDE_DIRS}")
39 | include_directories(${OpenCV_INCLUDE_DIRS})
40 | else()
41 | message(FATAL_ERROR "OpenCV not found, please read the README.md")
42 | endif(OpenCV_FOUND)
43 |
44 |
45 | find_package(Boost COMPONENTS serialization system filesystem)
46 | if(Boost_FOUND)
47 | message(STATUS "Found Boost version ${Boost_VERSION}")
48 | message(STATUS "Boost directories: ${Boost_INCLUDE_DIRS}")
49 | include_directories(${Boost_INCLUDE_DIRS})
50 | else()
51 | message(FATAL_ERROR "Boost not found, please read the README.md")
52 | endif(Boost_FOUND)
53 |
54 | find_package(nlohmann_json 3.2.0 REQUIRED)
55 | if(nlohmann_json_FOUND)
56 | message(STATUS "Found nlohmann_json")
57 | else()
58 | message(FATAL_ERROR "nlohmann_json not found, please read the README.md")
59 | endif(nlohmann_json_FOUND)
60 |
61 | find_package(Armadillo REQUIRED)
62 | include_directories(${ARMADILLO_INCLUDE_DIRS})
63 | find_package(LAPACK REQUIRED)
64 | include_directories(${LAPACK_INCLUDE_DIRS})
65 |
66 | if(BUILD_TESTING)
67 | enable_testing()
68 | find_package(GTest REQUIRED)
69 | if(GTEST_FOUND)
70 | message(STATUS "GTest directories: ${GTEST_INCLUDE_DIRS}")
71 | include_directories(${GTEST_INCLUDE_DIRS})
72 | else()
73 | message(FATAL_ERROR "GTEST_FOUND not found, please read the README.md")
74 | endif(GTEST_FOUND)
75 | endif()
76 |
77 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/)
78 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/lib/)
79 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/)
80 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../nlohmann_json/include/)
81 |
82 | set(RESULTS_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build)
83 | file(MAKE_DIRECTORY ${RESULTS_OUTPUT_DIRECTORY})
84 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${RESULTS_OUTPUT_DIRECTORY}/lib)
85 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${RESULTS_OUTPUT_DIRECTORY}/lib)
86 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${RESULTS_OUTPUT_DIRECTORY}/bin)
87 |
88 | add_subdirectory("src")
89 | if(BUILD_TESTING)
90 | add_subdirectory("tst")
91 | endif()
92 |
93 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/data/config/Env2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idsia-robotics/Collaborative-Monte-Carlo-Localization/918d41678b1eaca9ebbaf0ab47427f127ac0f1c3/ros_ws/src/cmcl/cmcl_ros/ncore/data/config/Env2.png
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/data/config/Env2.yaml:
--------------------------------------------------------------------------------
1 | image: Env2.png
2 | resolution: 0.05
3 | origin: [-16, -16, 0]
4 | negate: 0
5 | occupied_thresh: 0.65
6 | free_thresh: 0.25
7 | mode: trinary
8 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/data/config/cmcl.config:
--------------------------------------------------------------------------------
1 | {
2 | "mapPath": "Env2.yaml",
3 | "numParticles": 10000,
4 | "sensorModel": {
5 | "likelihoodSigma": 0.5,
6 | "maxDist": 20.0,
7 | "type": "BeamEnd",
8 | "weightingScheme": 1
9 | },
10 | "detectionModel": {
11 | "kmeans":
12 | {
13 | "clusters": 8,
14 | "iterations" : 5
15 | },
16 | "det":
17 | {
18 | "minSize": 500,
19 | "maxSize": 1000
20 | },
21 | "prorok":
22 | {
23 | "clusters": 8
24 | },
25 | "thinning":
26 | {
27 | "clusters": 64
28 | },
29 | "detectionNoise":
30 | {
31 | "x": 0.1,
32 | "y": 0.1
33 | },
34 | "penalty" : 0.000000001,
35 | "alpha" : 0.06,
36 | "clusters": 10000,
37 | "type" : 3
38 | },
39 | "tracking":
40 | {
41 | "mode" : false,
42 | "x" : [8.61341, 8.61341],
43 | "y" : [-3.3749, -3.3749],
44 | "yaw" : [0.03733, 0.03733] ,
45 | "cov_x" : [0.5, 0.5],
46 | "cov_y" : [0.5, 0.5],
47 | "cov_yaw" : [0.5, 0.5]
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/BeamEnd.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: BeamEnd.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef BEAMEND_H
14 | #define BEAMEND_H
15 |
16 | #include
17 | #include
18 | #include "GMap.h"
19 | #include
20 | #include
21 | #include "LidarData.h"
22 | #include "Particle.h"
23 | #include "GMap.h"
24 |
25 | class BeamEnd
26 | {
27 | public:
28 |
29 | enum class Weighting
30 | {
31 | NAIVE = 0,
32 | GEOMETRIC = 1
33 | };
34 |
35 |
36 | //! A constructor
37 | /*!
38 | \param Gmap is a ptr to a GMAP object, which holds the gmapping map
39 | \param sigma is a float that determine how forgiving the model is (small sigma will give a very peaked likelihood)
40 | \param maxDist is a float specifying up to what distance from the sensor a reading is valid
41 | \param Weighting is an int specifying which weighting scheme to use
42 | */
43 |
44 | BeamEnd(const std::shared_ptr& GMap, float sigma = 8, float maxDist = 15, Weighting weighting = Weighting::GEOMETRIC);
45 |
46 | //! Computes weights for all particles based on how well the observation matches the map
47 | /*!
48 | \param particles is a vector of Particle elements
49 | \param SensorData is an abstract container for sensor data. This function expects LidarData type
50 | */
51 |
52 | void ComputeWeights(std::vector& particles, std::shared_ptr data);
53 |
54 | //! Returns truth if a particle is in an occupied grid cell, false otherwise. Notice that for particles in unknown areas the return is false.
55 | /*!
56 | \param Particle is a particle with pose and weight
57 | */
58 |
59 |
60 | //void plotParticles(std::vector& particles, std::string title, bool show=true);
61 |
62 | const cv::Mat& DebugMap()
63 | {
64 | return o_debugMap;
65 | }
66 |
67 |
68 | private:
69 |
70 |
71 | float getLikelihood(float distance);
72 |
73 | void plotScan(Eigen::Vector3f laser, std::vector& zMap);
74 |
75 | std::vector scan2Map(const Particle& particle, const std::vector& scan);
76 |
77 | double naive(const Particle& particle, const std::vector& scan, std::vector scanMask);
78 |
79 | double geometric(const Particle& particle, const std::vector& scan, std::vector scanMask);
80 |
81 |
82 | std::shared_ptr o_gmap;
83 | cv::Mat o_debugMap;
84 | float o_maxDist = 15;
85 | float o_sigma = 8;
86 | float o_resolution = 0.05;
87 |
88 | cv::Mat o_edt;
89 | Weighting o_weighting;
90 | float o_coeff = 1;
91 |
92 | };
93 |
94 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/Cluster.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: Cluster.h #
9 | # ##############################################################################
10 | **/
11 |
12 | #ifndef CLUSTER_H
13 | #define CLUSTER_H
14 |
15 | #include
16 | #include
17 | #include
18 |
19 | class Cluster
20 | {
21 | public:
22 |
23 | Cluster(){}
24 |
25 | void ComputeMean();
26 |
27 | void ComputeVariance();
28 |
29 | void ComputeError();
30 |
31 | void ComputeWeight();
32 |
33 |
34 | std::vector points;
35 | std::vector weights;
36 | float totalWeight = 0;
37 | Eigen::Vector3f mean;
38 | Eigen::Vector3f variance;
39 | float error;
40 |
41 |
42 | };
43 |
44 |
45 |
46 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/ClusterAbstraction.h:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | # ##############################################################################
4 | # Copyright (c) 2023- University of Lugano #
5 | # All rights reserved. #
6 | # #
7 | # Author: Nicky Zimmerman #
8 | # #
9 | # File: ClusterAbstraction.h #
10 | # ##############################################################################
11 | **/
12 |
13 |
14 | #ifndef CLUSTERABSTRACTION_H
15 | #define CLUSTERABSTRACTION_H
16 |
17 | #include
18 | #include
19 | #include
20 | #include "Cluster.h"
21 | #include "Utils.h"
22 |
23 |
24 |
25 | class ClusterAbstraction
26 | {
27 | public:
28 |
29 | ClusterAbstraction();
30 |
31 | ClusterAbstraction(Cluster& cluster, Eigen::Vector3f trans);
32 |
33 |
34 | static Eigen::Vector2f computePolarDifference(Eigen::Vector3f pm, Eigen::Vector3f pn);
35 |
36 | static std::vector shiftPoints(std::vector& points, const Eigen::Vector3f& trans);
37 |
38 | static Eigen::Vector3f shiftPoint(Eigen::Vector3f& point, const Eigen::Vector2f& trans);
39 |
40 | void computePolarVariance(std::vector& polarPoints, std::vector& weights);
41 |
42 |
43 |
44 |
45 |
46 |
47 | Eigen::Vector3f centroid;
48 | float weight;
49 | Eigen::Vector2f mu;
50 | Eigen::Matrix2f covariance;
51 | };
52 |
53 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/DensityEstimationTree.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: DensityEstimationTree.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef DENSITYESTIMATIONTREE_H
14 | #define DENSITYESTIMATIONTREE_H
15 |
16 | #include
17 | #include
18 | #include "DistributionData.h"
19 | #include
20 | #include "Resampling.h"
21 |
22 | class DensityEstimationTree
23 | {
24 | public:
25 |
26 | DensityEstimationTree(int minLeafSize, int maxLeafSize);
27 |
28 | std::shared_ptr Compress(const std::vector& particles, Eigen::Vector3f trans);
29 |
30 | std::shared_ptr> TrainDET(const std::vector& particles);
31 |
32 | double QueryDET(std::shared_ptr> tree, Particle particle);
33 |
34 | void Fuse(std::vector& particles, std::shared_ptr& distData);
35 |
36 |
37 | private:
38 |
39 |
40 | float o_penalty = 0.000000001;
41 | int o_minLeafSize = 0;
42 | int o_maxLeafSize = 0;
43 | std::shared_ptr o_resampler;
44 |
45 |
46 | };
47 |
48 |
49 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/DistributionData.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: DistributionData.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef DISTRIBUTIONDATA_H
14 | #define DISTRIBUTIONDATA_H
15 |
16 | #include
17 | #include
18 | #include "Particle.h"
19 | #include "ClusterAbstraction.h"
20 |
21 |
22 | enum class DISTRIBUTION
23 | {
24 | PARTICLES = 0,
25 | DET = 1,
26 | KMEANS = 2,
27 | PROROK = 3,
28 | GOODPOINTS = 4
29 | };
30 |
31 | class DistributionData
32 | {
33 |
34 | public:
35 |
36 | DistributionData(DISTRIBUTION distType, std::vector observerParticles, Eigen::Vector2f variance = Eigen::Vector2f(1.0, 1.0))
37 | {
38 | o_distType = distType;
39 | o_particles = observerParticles;
40 | o_variance = variance;
41 | }
42 |
43 | DistributionData(DISTRIBUTION distType, std::vector det, Eigen::Vector2f variance = Eigen::Vector2f(1.0, 1.0))
44 | {
45 | o_distType = distType;
46 | o_det = det;
47 | o_variance = variance;
48 | }
49 |
50 | DistributionData(DISTRIBUTION distType, std::vector kmeans)
51 | {
52 | o_distType = distType;
53 | o_kmeans = kmeans;
54 | o_variance = Eigen::Vector2f(0.0, 0.0);
55 | }
56 |
57 | DistributionData(DISTRIBUTION distType, std::vector prorok)
58 | {
59 | o_distType = distType;
60 | o_prorok = prorok;
61 | o_variance = Eigen::Vector2f(0.0, 0.0);
62 | }
63 |
64 | std::vector& Particles()
65 | {
66 | return o_particles;
67 | }
68 |
69 | std::vector& DET()
70 | {
71 | return o_det;
72 | }
73 |
74 | std::vector& KMeans()
75 | {
76 | return o_kmeans;
77 | }
78 |
79 | std::vector& Prorok()
80 | {
81 | return o_prorok;
82 | }
83 |
84 | DISTRIBUTION Type()
85 | {
86 | return o_distType;
87 | }
88 |
89 | Eigen::Vector2f Variance()
90 | {
91 | return o_variance;
92 | }
93 |
94 |
95 |
96 | private:
97 |
98 | DISTRIBUTION o_distType;
99 | std::vector o_particles;
100 | std::vector o_det;
101 | std::vector o_prorok;
102 | std::vector o_kmeans;
103 | Eigen::Vector2f o_variance;
104 |
105 | };
106 |
107 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/DistributionExchange.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: DistributionExchange.h #
9 | # ##############################################################################
10 | **/
11 |
12 | #ifndef DISTRIBUTIONEXCHANGE_H
13 | #define DISTRIBUTIONEXCHANGE_H
14 |
15 | #include
16 | #include "Particle.h"
17 | #include "DistributionData.h"
18 |
19 | #include "GoodPointsCompression.h"
20 | #include "ProrokClustering.h"
21 | #include "DensityEstimationTree.h"
22 | #include "KMeansClustering.h"
23 | #include "StandardThinning.h"
24 |
25 |
26 | class DistributionExchange
27 | {
28 | public:
29 |
30 | DistributionExchange(const std::string& jsonConfigPath);
31 |
32 | DistributionExchange(int k = 5, Eigen::Vector2f detectionNoise = Eigen::Vector2f(0.15, 0.15), float penalty = 0.000000001);
33 |
34 | void FuseDistribution(std::vector& particles, std::shared_ptr& distData);
35 |
36 | std::shared_ptr CreateDistribution(const std::vector& observerParticles, DISTRIBUTION distType, Eigen::Vector3f trans = Eigen::Vector3f());
37 |
38 |
39 |
40 |
41 | private:
42 |
43 | Eigen::Vector2f o_detectionNoise;
44 | float o_penalty = 0.000000001;
45 | int o_k = 5;
46 |
47 | std::shared_ptr o_goodPoints;
48 | std::shared_ptr o_prorok;
49 | std::shared_ptr o_det;
50 | std::shared_ptr o_kmeans;
51 | std::shared_ptr o_thin;
52 | //std::shared_ptr o_naive;
53 |
54 | };
55 |
56 |
57 |
58 |
59 |
60 | #endif
61 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/FSR.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: FSR.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef FSR_H
14 | #define FSR_H
15 |
16 | #include
17 | #include
18 |
19 | class FSR
20 | {
21 | public:
22 |
23 | Eigen::Vector3f SampleMotion(const Eigen::Vector3f& p1, const std::vector& command, const std::vector& weights, const Eigen::Vector3f& noise);
24 |
25 | Eigen::Vector3f Forward(Eigen::Vector3f p1, Eigen::Vector3f u);
26 |
27 | Eigen::Vector3f Backward(Eigen::Vector3f p1, Eigen::Vector3f p2);
28 |
29 |
30 | };
31 |
32 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/GMap.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023 University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: GMap.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef GMAP
14 | #define GMAP
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | class GMap
23 | {
24 | public:
25 |
26 | //! A constructor for handling the output of Gmapping, which include a metadata yaml and a .pgm map
27 | /*!
28 | \param origin is the 2D pose of the bottom right corner of the map (found in the yaml)
29 | \param resolution is the map resolution - distance in meters corresponding to 1 pixel (found in the yaml)
30 | \param gridMap is occupancy map built according to the scans
31 | */
32 | GMap(cv::Mat& gridMap, Eigen::Vector3f origin, float resolution);
33 |
34 |
35 | //! A constructor for handling the output of Gmapping, which include a metadata yaml and a .pgm map
36 | /*!
37 | \param yamlPath is the path to the metadata yaml file produced by gmapping
38 | */
39 | GMap(const std::string& mapFolder, const std::string& yamlName = "YouBotMap.yaml");
40 |
41 |
42 | //! A getter top left corner of the actual occupied area, as the map usually has wide empty margins
43 | /*!
44 | \return Eigen::Vector2f = (u, v) pixel coordinates for the gridmap
45 | */
46 | Eigen::Vector2f TopLeft()
47 | {
48 | return o_topLeft;
49 | }
50 |
51 |
52 | //! A getter bottom right corner of the actual occupied area, as the map usually has wide empty margins
53 | /*!
54 | \return Eigen::Vector2f = (u, v) pixel coordinates for the gridmap
55 | */
56 | Eigen::Vector2f BottomRight()
57 | {
58 | return o_bottomRight;
59 | }
60 |
61 |
62 | //! Converts (x, y) from the map frame to the pixels coordinates
63 | /*!
64 | \param (x, y) position in map frame
65 | \return (u, v) pixel coordinates for the gridmap
66 | */
67 | Eigen::Vector2f World2Map(Eigen::Vector2f xy) const;
68 |
69 |
70 | //! Converts (u, v) pixel coordinates to map frame (x, y)
71 | /*!
72 | \param (u, v) pixel coordinates for the gridmap
73 | \return (x, y) position in map frame
74 | */
75 | Eigen::Vector2f Map2World(Eigen::Vector2f uv) const;
76 |
77 |
78 | bool IsInMap(Eigen::Vector2f mp) const;
79 |
80 |
81 | bool IsValid(Eigen::Vector3f pose) const;
82 |
83 | bool IsValid2D(Eigen::Vector2f mp) const;
84 |
85 |
86 | const cv::Mat& Map() const
87 | {
88 | return o_gridmap;
89 | }
90 |
91 | float Resolution() const
92 | {
93 | return o_resolution;
94 | }
95 |
96 | Eigen::Vector3f Origin() const
97 | {
98 | return o_origin;
99 | }
100 |
101 |
102 | private:
103 |
104 | //std::shared_ptr o_gridmap;
105 | cv::Mat o_gridmap;
106 | float o_resolution = 0;
107 | int o_maxy = 0;
108 | Eigen::Vector3f o_origin;
109 | Eigen::Vector2f o_bottomRight;
110 | Eigen::Vector2f o_topLeft;
111 |
112 | void getBorders();
113 |
114 | };
115 |
116 | #endif //GMap
117 |
118 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/GoodPointsCompression.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: GoodPointsCompression.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef GOODPOINTSCOMPRESSION_H
14 | #define GOODPOINTSCOMPRESSION_H
15 |
16 | #include
17 | #include
18 | #include "Particle.h"
19 | #include "DistributionData.h"
20 | #include "Resampling.h"
21 |
22 | class GoodPointsCompression
23 | {
24 |
25 | public:
26 | GoodPointsCompression(const std::string& modulePath, Eigen::Vector2f detectionNoise = Eigen::Vector2f(0.15, 0.15));
27 |
28 |
29 | std::shared_ptr Compress(const std::vector& particles, Eigen::Vector3f trans);
30 |
31 | Eigen::MatrixXi Compress(Eigen::MatrixXd& data);
32 |
33 |
34 | void Fuse(std::vector& particles, std::shared_ptr& distData);
35 |
36 | void ReciprocalSampling(std::vector& particles, std::shared_ptr& distData);
37 |
38 |
39 |
40 | private:
41 |
42 | pybind11::object comp_kt;
43 | pybind11::object dc;
44 | float o_penalty = 0.000000001; //0.0000000000000001;
45 | Eigen::Vector2f o_detectionNoise;
46 | std::shared_ptr o_resampler;
47 | };
48 |
49 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/KMeansClustering.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: KMeansClustering.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef KMEANSCLUSTERING_H
14 | #define KMEANSCLUSTERING_H
15 |
16 | #include
17 | #include
18 | #include "DistributionData.h"
19 | #include "Resampling.h"
20 |
21 | class KMeansClustering
22 | {
23 | public:
24 |
25 | KMeansClustering(int k, int epochs, Eigen::Vector2f detectionNoise);
26 |
27 | std::shared_ptr Compress(const std::vector& particles, Eigen::Vector3f trans);
28 |
29 | void Fuse(std::vector& particles, std::shared_ptr& distData);
30 |
31 | void AssignClusters(std::vector& points, std::vector& weights, std::vector& clusters);
32 |
33 | void RecomputeCentroids(std::vector& clusters);
34 |
35 | void ReciprocalSampling(std::vector& particles, std::shared_ptr& distData);
36 |
37 |
38 | private:
39 |
40 | float o_penalty = 0.000000001;
41 | int o_k = 0;
42 | int o_epochs = 0;
43 | Eigen::Vector2f o_detectionNoise;
44 | std::shared_ptr o_resampler;
45 | };
46 |
47 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/Lidar2D.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: Lidar2D.h #
9 | # ##############################################################################
10 | **/
11 |
12 | #ifndef LIDAR2D_H
13 | #define LIDAR2D_H
14 |
15 | #include
16 | #include
17 | #include
18 |
19 |
20 | class Lidar2D
21 | {
22 | public:
23 |
24 | Lidar2D(std::string name_, Eigen::Vector3f origin, int numBeams, float maxAngle, float minAngle);
25 |
26 | Lidar2D(std::string name_, std::string yamlFolder);
27 |
28 | Lidar2D(std::string jsonPath);
29 |
30 | //const std::vector& Heading() const
31 | std::vector Heading()
32 | {
33 | return o_heading;
34 | }
35 |
36 | std::string Name()
37 | {
38 | return o_name;
39 | }
40 |
41 | Eigen::Matrix3f Trans()
42 | {
43 | return o_trans;
44 | }
45 |
46 |
47 |
48 | std::vector Center(const std::vector& ranges);
49 |
50 |
51 |
52 | private:
53 |
54 | std::vector o_heading;
55 | std::string o_name;
56 | Eigen::Matrix3f o_trans;
57 |
58 | };
59 |
60 |
61 |
62 |
63 |
64 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/LidarData.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: LidarData.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef LIDARDATA_H
14 | #define LIDARDATA_H
15 |
16 | #include
17 | #include
18 |
19 | class LidarData
20 | {
21 |
22 | public:
23 |
24 | LidarData(const std::vector& scan, const std::vector& mask)
25 | {
26 | o_scan = scan;
27 | o_mask = mask;
28 | }
29 |
30 | //virtual ~LidarData(){};
31 |
32 | std::vector& Scan()
33 | {
34 | return o_scan;
35 | }
36 |
37 | std::vector& Mask()
38 | {
39 | return o_mask;
40 | }
41 |
42 | private:
43 |
44 | std::vector o_scan;
45 | std::vector o_mask;
46 |
47 | };
48 |
49 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/MCL.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: MCL.h #
9 | # ##############################################################################
10 | **/
11 |
12 | #ifndef MCL_H
13 | #define MCL_H
14 |
15 | #include "FSR.h"
16 | #include "BeamEnd.h"
17 | #include "Resampling.h"
18 | #include "SetStatistics.h"
19 | #include "GMap.h"
20 | #include
21 | #include "LidarData.h"
22 | #include "ParticleFilter.h"
23 | #include "DistributionExchange.h"
24 |
25 | class MCL
26 | {
27 | public:
28 |
29 |
30 | //! A constructor
31 | /*!
32 | \param fm is a ptr to a GMap object
33 | \param mm is a ptr to a MotionModel object, which is an abstract class. FSR is the implementation
34 | \param sm is a ptr to a BeamEnd object, which is an abstract class. BeamEnd is the implementation
35 | \param rs is a ptr to a Resampling object, which is an abstract class. LowVarianceResampling is the implementation
36 | \param n_particles is an int, and it defines how many particles the particle filter will use
37 | */
38 | MCL(std::shared_ptr gmap, std::shared_ptr mm, std::shared_ptr sm,
39 | std::shared_ptr rs, int n_particles);
40 |
41 |
42 | //! A constructor
43 | /*!
44 | \param fm is a ptr to a GMap object
45 | */
46 | MCL(const std::string& jsonConfigPath);
47 |
48 |
49 | //! A constructor
50 | /*!
51 | * \param fm is a ptr to a GMap object
52 | \param mm is a ptr to a MotionModel object, which is an abstract class. FSR is the implementation
53 | \param sm is a ptr to a BeamEnd object, which is an abstract class. BeamEnd is the implementation
54 | \param rs is a ptr to a Resampling object, which is an abstract class. LowVarianceResampling is the implementation
55 | \param n_particles is an int, and it defines how many particles the particle filter will use
56 | \param initGuess is a vector of initial guess for the location of the robots
57 | \param covariances is a vector of covariances (uncertainties) corresponding to the initial guesses
58 | \param injectionRatio is an float, and it determines which portions of the particles are replaced when relocalizing
59 | */
60 | MCL(std::shared_ptr gmap, std::shared_ptr mm, std::shared_ptr sm,
61 | std::shared_ptr rs, int n_particles, std::vector initGuess,
62 | std::vector covariances);
63 |
64 |
65 | //! A getter for the mean and covariance of the particles
66 | /*!
67 | \return an object SetStatistics, that has fields for mean and covariance
68 | */
69 | SetStatistics Stats()
70 | {
71 | return o_stats;
72 | }
73 |
74 |
75 | //! A getter particles representing the pose hypotheses
76 | /*!
77 | \return A vector of points, where each is Eigen::Vector3f = (x, y, theta)
78 | */
79 | std::vector Particles()
80 | {
81 | return o_particles;
82 | }
83 |
84 |
85 | //! Advanced all particles according to the control and noise, using the chosen MotionModel's forward function
86 | /*!
87 | \param control is a 3d control command. In the FSR model it's (forward, sideways, rotation)
88 | \param odomWeights is the corresponding weight to each odometry source
89 | \param noise is the corresponding noise to each control component
90 | */
91 | void Predict(const std::vector& control, const std::vector& odomWeights, const Eigen::Vector3f& noise);
92 |
93 | //! Considers the beamend likelihood of observation for all hypotheses, and then performs resampling
94 | /*!
95 | \param scan is a vector of homogeneous points (x, y, 1), in the sensor's frame. So the sensor location is (0, 0, 0)
96 | Notice that for the LaserScan messages you need to first transform the ranges to homo points, and then center them
97 | */
98 | void Correct(std::shared_ptr data);
99 |
100 |
101 | void FuseDistribution(std::shared_ptr& distData);
102 |
103 |
104 | std::shared_ptr CreateDistribution(DISTRIBUTION distType, const Eigen::Vector3f& relTrans);
105 |
106 |
107 |
108 | //! Initializes filter with new particles upon localization failure
109 | void Recover();
110 |
111 | Eigen::Vector3f Backward(Eigen::Vector3f p1, Eigen::Vector3f p2)
112 | {
113 | return o_motionModel->Backward(p1, p2);
114 | }
115 |
116 | //! A setter for the injection ration for particle, in case of text spotting. The ratio represents the fraction of particles that will be removed, and the same number
117 | // of particles will be injected at the location of detected text. The removed particles are always the ones with the lowest weights.
118 |
119 |
120 | const cv::Mat& DebugMap()
121 | {
122 | return o_beamEndModel->DebugMap();
123 | }
124 |
125 |
126 | std::shared_ptr Map()
127 | {
128 | return o_gmap;
129 | }
130 |
131 | private:
132 |
133 | void dumpParticles();
134 | int traceInMap(Eigen::Vector3f p1, Eigen::Vector3f p2);
135 | void detectionReweight(Eigen::Vector3f trans);
136 | //std::vector computeDetectedParticles(const Eigen::Vector3f& relTrans);
137 |
138 | std::shared_ptr o_particleFilter;
139 | unsigned int o_frame = 0;
140 | std::shared_ptr o_motionModel;
141 | std::shared_ptr o_beamEndModel;
142 | std::shared_ptr o_resampler;
143 | std::shared_ptr o_distExcange;
144 | std::shared_ptr o_gmap;
145 | int o_numParticles = 0;
146 | std::vector o_particles;
147 | SetStatistics o_stats;
148 | Eigen::Vector2f o_detectionNoise;
149 | };
150 |
151 | #endif
152 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/Particle.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: Particle.h #
9 | # ##############################################################################
10 | **/
11 |
12 | #ifndef PARTICLE_H
13 | #define PARTICLE_H
14 |
15 |
16 | #include
17 | #include
18 |
19 |
20 | class Particle
21 | {
22 | public:
23 |
24 | Particle(Eigen::Vector3f p = Eigen::Vector3f(0, 0, 0), double w = 0);
25 |
26 | Eigen::Vector3f pose;
27 | double weight;
28 |
29 | };
30 |
31 |
32 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/ParticleFilter.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: ParticleFilter.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef PARTICLEFILTER_H
14 | #define PARTICLEFILTER_H
15 |
16 | #include "Particle.h"
17 | #include "GMap.h"
18 | #include "SetStatistics.h"
19 |
20 | class ParticleFilter
21 | {
22 | public:
23 |
24 | //multi-map
25 | ParticleFilter(std::shared_ptr GMap);
26 |
27 |
28 |
29 | void InitUniform(std::vector& particles, int n_particles);
30 | void InitGaussian(std::vector& particles, int n_particles, const std::vector& initGuess, const std::vector& covariances);
31 |
32 | SetStatistics ComputeStatistics(const std::vector& particles);
33 |
34 | void NormalizeWeights(std::vector& particles);
35 |
36 |
37 | std::vector& Particles()
38 | {
39 | return o_particles;
40 | }
41 |
42 | void SetParticle(int id, Particle p)
43 | {
44 | o_particles[id] = p;
45 | }
46 |
47 |
48 | SetStatistics Statistics()
49 | {
50 | return o_stats;
51 | }
52 |
53 |
54 |
55 | private:
56 |
57 |
58 |
59 |
60 | std::shared_ptr o_gmap;
61 | std::vector o_particles;
62 | SetStatistics o_stats;
63 | };
64 |
65 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/ProrokClustering.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: ProrokClustering.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef PROROKCLUSTERING_H
14 | #define PROROKCLUSTERING_H
15 |
16 | #include
17 | #include
18 | #include "Cluster.h"
19 | #include "DistributionData.h"
20 | #include "Resampling.h"
21 |
22 |
23 |
24 | class ProrokClustering
25 | {
26 | public:
27 |
28 | ProrokClustering(int k, Eigen::Vector2f detectionNoise = Eigen::Vector2f(0.15, 0.15));
29 |
30 | std::shared_ptr Compress(const std::vector& particles, Eigen::Vector3f trans);
31 |
32 | void Fuse(std::vector& particles, std::shared_ptr& distData);
33 |
34 |
35 | std::vector ComputeClusters(const std::vector& particles);
36 |
37 | void findHighestVarianceCluster(std::vector& clusters, int& index, int& dim);
38 |
39 | void splitClusters(std::vector& clusters, int& index, int& dim);
40 |
41 | void ReciprocalSampling(std::vector& particles, std::shared_ptr& distData);
42 |
43 | //std::vector ProrokClustering(std::vector& points, std::vector& weights, int k);
44 |
45 |
46 | private:
47 |
48 |
49 | float o_penalty = 0.000000001;
50 | int o_k = 0;
51 | Eigen::Vector2f o_detectionNoise;
52 | std::shared_ptr o_resampler;
53 | };
54 |
55 |
56 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/Resampling.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: LowVarianceResampling.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef RESAMPLING_H
14 | #define RESAMPLING_H
15 |
16 |
17 | #include
18 | #include
19 | #include "Particle.h"
20 |
21 | class Resampling
22 | {
23 | public:
24 |
25 | void Resample(std::vector& particles);
26 |
27 | void SetTH(float th)
28 | {
29 | o_th = th;
30 | }
31 |
32 |
33 | private:
34 |
35 | float o_th = 0.5;
36 |
37 | };
38 |
39 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/SetStatistics.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: SetStatistics.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef SETSTATISTICS_H
14 | #define SETSTATISTICS_H
15 |
16 | #include
17 | #include
18 | #include "Particle.h"
19 |
20 | class SetStatistics
21 | {
22 | public:
23 |
24 | SetStatistics(Eigen::Vector3d m = Eigen::Vector3d::Zero(), Eigen::Matrix3d c = Eigen::Matrix3d::Zero())
25 | {
26 | mean = m;
27 | cov = c;
28 | }
29 |
30 | Eigen::Vector3d Mean()
31 | {
32 | return mean;
33 | }
34 |
35 | Eigen::Matrix3d Cov()
36 | {
37 | return cov;
38 | }
39 |
40 |
41 | static SetStatistics ComputeParticleSetStatistics(const std::vector& particles);
42 |
43 | private:
44 |
45 | Eigen::Vector3d mean;
46 | Eigen::Matrix3d cov;
47 |
48 | };
49 |
50 |
51 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/StandardThinning.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: StandardThinning.h #
9 | # ##############################################################################
10 | **/
11 |
12 |
13 | #ifndef STANDARDTHINNING_H
14 | #define STANDARDTHINNING_H
15 |
16 |
17 | #include "DistributionData.h"
18 | #include "Resampling.h"
19 |
20 | class StandardThinning
21 | {
22 | public:
23 | StandardThinning(int subSize, Eigen::Vector2f detectionNoise = Eigen::Vector2f(0.15, 0.15));
24 |
25 | std::shared_ptr Compress(const std::vector& particles, Eigen::Vector3f trans);
26 |
27 | void Fuse(std::vector& particles, std::shared_ptr& distData);
28 |
29 | void ReciprocalSampling(std::vector& particles, std::shared_ptr& distData);
30 |
31 |
32 |
33 | private:
34 | float o_penalty = 0.000000001;
35 | Eigen::Vector2f o_detectionNoise;
36 | int o_n = 0;
37 | std::shared_ptr o_resampler;
38 |
39 |
40 | };
41 |
42 |
43 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/include/Utils.h:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2021- University of Bonn #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: Utils.h #
9 | # ##############################################################################
10 | **/
11 |
12 | #ifndef UTILS_H
13 | #define UTILS_H
14 |
15 |
16 | #include
17 | #include
18 | #include
19 | #include "Particle.h"
20 |
21 | std::vector computeDetectedParticles(const std::vector& particles, const Eigen::Vector3f& relTrans);
22 |
23 |
24 | Eigen::Matrix3f Vec2Trans(Eigen::Vector3f v);
25 |
26 | float CosineSimilarity(float yaw1, float yaw2);
27 |
28 | float Wrap2Pi(float angle);
29 |
30 | float GetYaw(float qz, float qw);
31 |
32 | std::vector Ranges2Points(const std::vector& ranges, const std::vector& angles);
33 |
34 | std::vector Downsample(const std::vector& ranges, int N);
35 |
36 | std::vector Downsample(const std::vector& ranges, int N);
37 |
38 | std::vector StringToVec(std::string seq);
39 |
40 | std::vector File2Lines(std::string filePath);
41 |
42 | float SampleGuassian(float sigma);
43 |
44 | #endif
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/src/BeamEnd.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: BeamEnd.cpp #
9 | # ##############################################################################
10 | **/
11 |
12 | #include "BeamEnd.h"
13 | #include "Utils.h"
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | BeamEnd::BeamEnd(const std::shared_ptr& GMap, float sigma, float maxDist, Weighting weighting )
21 | {
22 | o_gmap = GMap;
23 | o_maxDist = maxDist;
24 | o_sigma = sigma; //value of 8 for map resolution 0.05, 40 for 0.01
25 | o_weighting = weighting;
26 | o_coeff = 1.0 / sqrt(2 * M_PI * o_sigma);
27 | o_resolution = o_gmap->Resolution();
28 |
29 | cv::Mat edt;
30 | cv::threshold(o_gmap->Map(), o_edt, 127, 255, 0);
31 | cv::imwrite("TH.png", o_edt);
32 | o_edt = 255 - o_edt;
33 | cv::distanceTransform(o_edt, o_edt, cv::DIST_L2, cv::DIST_MASK_3);
34 | //cv::threshold(o_edt, o_edt, o_maxDist, o_maxDist, 2); //Threshold Truncated
35 |
36 | o_debugMap = cv::Mat::zeros(o_edt.size(), CV_32SC1);
37 | cv::imwrite("edt.png", o_edt);
38 |
39 | }
40 |
41 | void BeamEnd::ComputeWeights(std::vector& particles, std::shared_ptr data)
42 | {
43 | const std::vector& scan = data->Scan();
44 | const std::vector& scanMask = data->Mask();
45 |
46 | double acc_w = 0;
47 |
48 | // for(int m = 0; m < o_debugMaps.size(); ++m)
49 | // {
50 | // o_debugMaps[m] = cv::Mat::zeros(o_edts[0][0].size(), CV_32SC1);
51 | // }
52 |
53 | #pragma omp parallel for
54 | for(long unsigned int i = 0; i < particles.size(); ++i)
55 | {
56 | //auto t1 = std::chrono::high_resolution_clock::now();
57 | double w = 0;
58 | switch(o_weighting)
59 | {
60 | case Weighting::NAIVE :
61 | w = naive(particles[i], scan, scanMask);
62 | break;
63 | case Weighting::GEOMETRIC :
64 | w = geometric(particles[i], scan, scanMask);
65 | break;
66 |
67 | }
68 | particles[i].weight *= w;
69 | acc_w += w;
70 |
71 | //auto t2 = std::chrono::high_resolution_clock::now();
72 | //auto ns = std::chrono::duration_cast(t2 - t1);
73 | //std::cout << "BeamEnd::Timing of compute : " << ns.count() << std::endl;
74 | }
75 |
76 | //std::cout << acc_w/particles.size() << std::endl;
77 | }
78 |
79 |
80 |
81 | double BeamEnd::naive(const Particle& particle, const std::vector& scan, std::vector scanMask)
82 | {
83 | std::vector mapPoints = scan2Map(particle, scan);
84 | //plotScan(particle.pose, mapPoints);
85 |
86 | Eigen::Vector2f br = o_gmap->BottomRight();
87 |
88 | double weight = 1.0;
89 | int nonValid = 0;
90 |
91 | for(long unsigned int i = 0; i < mapPoints.size(); ++i)
92 | {
93 | Eigen::Vector2f mp = mapPoints[i];
94 |
95 | if(scanMask[i] > 0.0)
96 | {
97 | if ((mp(0) < 0) || (mp(1) < 0) || (mp(0) > br(0)) || (mp(1) > br(1)))
98 | {
99 | ++nonValid;
100 | }
101 | else
102 | {
103 | float dist = o_edt.at(mp(1) ,mp(0));
104 | double w = getLikelihood(dist);
105 | weight *= w;
106 | }
107 | }
108 | }
109 | //std::cout << nonValid << std::endl;
110 |
111 | float penalty = pow(getLikelihood(o_maxDist), nonValid);
112 | weight *= penalty;
113 |
114 | return weight;
115 | }
116 |
117 | static int plot = 0;
118 |
119 | double BeamEnd::geometric(const Particle& particle, const std::vector& scan, std::vector scanMask)
120 | {
121 | std::vector mapPoints = scan2Map(particle, scan);
122 | //plotScan(particle.pose, mapPoints);
123 | //plot++;
124 |
125 | double weight = 1.0;
126 | float geoW = 1.0 / scan.size();
127 | int debug_id = 0;
128 |
129 | Eigen::Vector2f br = o_gmap->BottomRight();
130 | int nonValid = 0;
131 | int valid = 0;
132 | double tot_dist = 0;
133 |
134 | for(long unsigned int i = 0; i < mapPoints.size(); ++i)
135 | {
136 | Eigen::Vector2f mp = mapPoints[i];
137 |
138 | if(scanMask[i] > 0.0)
139 | {
140 | if ((mp(0) < 0) || (mp(1) < 0) || (mp(0) > br(0)) || (mp(1) > br(1)))
141 | {
142 | ++nonValid;
143 | }
144 | else
145 | {
146 |
147 | float dist = o_edt.at(mp(1) ,mp(0)) * o_resolution;
148 | if (dist > o_maxDist) dist = o_maxDist;
149 |
150 | tot_dist += pow(dist / o_sigma, 2.0);
151 | ++valid;
152 |
153 | }
154 | }
155 | }
156 |
157 | geoW = 1.0 /(valid + nonValid);
158 | tot_dist += nonValid * pow(o_maxDist / o_sigma, 2.0);
159 | weight = o_coeff * exp(-0.5 * tot_dist * geoW);
160 |
161 |
162 | //Eigen::Vector2f pp = o_gmaps[floorID][0]->World2Map(Eigen::Vector2f(particle.pose(0), particle.pose(1)));
163 | //o_debugMaps[debug_id].at(pp(1), pp(0)) += 1.0;
164 |
165 | return weight;
166 | }
167 |
168 |
169 | float BeamEnd::getLikelihood(float distance)
170 | {
171 | float l = o_coeff * exp(-0.5 * pow(distance / o_sigma, 2));
172 | return l;
173 | }
174 |
175 |
176 | /*
177 | void BeamEnd::plotParticles(std::vector& particles, std::string title, bool show)
178 | {
179 | cv::Mat img;
180 | cv::cvtColor(Gmap->Map(), img, cv::COLOR_GRAY2BGR);
181 |
182 | cv::namedWindow("Particles", cv::WINDOW_NORMAL);
183 |
184 | for(long unsigned int i = 0; i < particles.size(); ++i)
185 | {
186 | Eigen::Vector3f p = particles[i].pose;
187 | Eigen::Vector2f uv = Gmap->World2Map(Eigen::Vector2f(p(0), p(1)));
188 |
189 | cv::circle(img, cv::Point(uv(0), uv(1)), 5, cv::Scalar(0, 0, 255), -1);
190 | }
191 | if(show)
192 | {
193 | cv::imshow("Particles", img);
194 | cv::waitKey(0);
195 | }
196 | cv::imwrite("/home/nickybones/Code/YouBotMCL/nmcl/" + title + ".png", img);
197 |
198 | cv::destroyAllWindows();
199 | }*/
200 |
201 |
202 | void BeamEnd::plotScan(Eigen::Vector3f laser, std::vector& zMap)
203 | {
204 | cv::Mat img;
205 | cv::cvtColor(o_gmap->Map(), img, cv::COLOR_GRAY2BGR);
206 |
207 | //cv::namedWindow("Scan", cv::WINDOW_NORMAL);
208 | Eigen::Vector2f p = o_gmap->World2Map(Eigen::Vector2f(laser(0), laser(1)));
209 |
210 | cv::circle(img, cv::Point(p(0), p(1)), 5, cv::Scalar(255, 0, 0), -1);
211 |
212 | for(long unsigned int i = 0; i < zMap.size(); ++i)
213 | {
214 | Eigen::Vector2f p = zMap[i];
215 | cv::circle(img, cv::Point(p(0), p(1)), 1, cv::Scalar(0, 0, 255), -1);
216 | }
217 |
218 | //cv::Rect myROI(475, 475, 400, 600);
219 | // Crop the full image to that image contained by the rectangle myROI
220 | // Note that this doesn't copy the data
221 | //cv::Mat img_(img, myROI);
222 |
223 | cv::imwrite("scan" + std::to_string(plot) + ".png", img);
224 | //cv::imshow("Scan", img_);
225 | //cv::waitKey(0);
226 |
227 | //cv::destroyAllWindows();
228 | }
229 |
230 | //#include
231 |
232 | std::vector BeamEnd::scan2Map(const Particle& particle, const std::vector& scan)
233 | {
234 | Eigen::Vector3f pose = particle.pose;
235 | Eigen::Matrix3f trans = Vec2Trans(pose);
236 | std::vector mapPoints(scan.size());
237 |
238 | // std::fstream fout;
239 | // fout.open("scan" + std::to_string(plot) + ".csv", std::ios::out | std::ios::app);
240 | // std::fstream fout2;
241 | // fout2.open("scanTr" + std::to_string(plot) + ".csv", std::ios::out | std::ios::app);
242 | // std::fstream fout3;
243 | // fout3.open("scanMp" + std::to_string(plot) + ".csv", std::ios::out | std::ios::app);
244 |
245 | for(long unsigned int i = 0; i < scan.size(); ++i)
246 | {
247 |
248 | Eigen::Vector3f ts = trans * scan[i];
249 | Eigen::Vector2f mp = o_gmap->World2Map(Eigen::Vector2f(ts(0), ts(1)));
250 | mapPoints[i] = mp;
251 |
252 | //fout << scan[i](0) << ", " << scan[i](1) << ", " << scan[i](2) << std::endl;
253 | //fout2 << ts(0) << ", " << ts(1) << std::endl;
254 | //fout3 << mp(0) << ", " << mp(1) << std::endl;
255 | }
256 | //fout.close();
257 | //fout2.close();
258 | //fout3.close();
259 |
260 |
261 |
262 | return mapPoints;
263 | }
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | add_library(NCORE MCL.cpp DistributionExchange.cpp BeamEnd.cpp Resampling.cpp SetStatistics.cpp ParticleFilter.cpp Particle.cpp Lidar2D.cpp GMap.cpp FSR.cpp KMeansClustering.cpp Cluster.cpp ProrokClustering.cpp GoodPointsCompression.cpp StandardThinning.cpp DensityEstimationTree.cpp ClusterAbstraction.cpp Utils.cpp)
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/src/Cluster.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | # ##############################################################################
3 | # Copyright (c) 2023- University of Lugano #
4 | # All rights reserved. #
5 | # #
6 | # Author: Nicky Zimmerman #
7 | # #
8 | # File: Cluster.cpp #
9 | # ##############################################################################
10 | **/
11 |
12 | #include "Cluster.h"
13 | #include "Utils.h"
14 |
15 | #include
16 |
17 | void Cluster::ComputeMean()
18 | {
19 | int pointNum = points.size();
20 | mean = Eigen::Vector3f(0,0,0);
21 |
22 | double dx = 0;
23 | double dy = 0;
24 | double w = 0;
25 |
26 | for (int i = 0; i < pointNum; ++i)
27 | {
28 | mean(0) += points[i](0) * weights[i];
29 | mean(1) += points[i](1) * weights[i];
30 | dx += cos(points[i](2)) * weights[i]; // theta
31 | dy += sin(points[i](2)) * weights[i]; // theta
32 | w += weights[i];
33 | }
34 |
35 | mean /= w;
36 | mean(2) = Wrap2Pi(atan2(dy, dx));
37 |
38 | //std::cout << "dx dy:" << dx << ", " << dy << ", " << mean(2) << std::endl;
39 | //std::cout << "mean:" << mean(0) << ", " << mean(1) << ", " << mean(2) << ", " << w << std::endl;
40 | }
41 |
42 | void Cluster::ComputeError()
43 | {
44 | int n = points.size();
45 | float error = 0;
46 |
47 | for (int i = 0; i < n; ++i)
48 | {
49 | Eigen::Vector2f diff = points[i].head(2) - mean.head(2);
50 | float dist = diff.norm();
51 | error += dist;
52 | }
53 |
54 | error /= n;
55 | }
56 |
57 | void Cluster::ComputeWeight()
58 | {
59 | int n = points.size();
60 | totalWeight = 0;
61 | for (int i = 0; i < n; ++i)
62 | {
63 | totalWeight += weights[i];
64 | }
65 | }
66 |
67 | void Cluster::ComputeVariance()
68 | {
69 | int pointNum = points.size();
70 | variance = Eigen::Vector3f(0, 0, 0);
71 | ComputeMean();
72 |
73 | double w = 0;
74 |
75 | for (int i = 0; i < pointNum; ++i)
76 | {
77 | Eigen::Vector3f p = points[i];
78 | Eigen::Vector3f diff = p - mean;
79 | w += weights[i];
80 |
81 | variance(0) += diff(0) * diff(0) * weights[i];
82 | variance(1) += diff(1) * diff(1) * weights[i];
83 | // ignoring angular variance here
84 | }
85 |
86 | variance /= w;
87 | }
--------------------------------------------------------------------------------
/ros_ws/src/cmcl/cmcl_ros/ncore/src/ClusterAbstraction.cpp:
--------------------------------------------------------------------------------
1 |
2 |
3 | /**
4 | # ##############################################################################
5 | # Copyright (c) 2023- University of Lugano #
6 | # All rights reserved. #
7 | # #
8 | # Author: Nicky Zimmerman #
9 | # #
10 | # File: ClusterAbstraction.cpp #
11 | # ##############################################################################
12 | **/
13 |
14 | #include "ClusterAbstraction.h"
15 | #include
16 | #include
17 | #include
18 |
19 | std::vector ClusterAbstraction::shiftPoints(std::vector& points, const Eigen::Vector3f& trans)
20 | {
21 | size_t numPoints = points.size();
22 |
23 | float r = trans.head(2).norm();
24 | float theta = atan2(trans(1), trans(0));
25 |
26 | std::vector shiftedPoints(numPoints);
27 |
28 | #pragma omp parallel for
29 | for(long unsigned int i = 0; i < numPoints; ++i)
30 | {
31 | Eigen::Vector3f p;
32 | p(0) = points[i](0) + r * cos(points[i](2) + theta);
33 | p(1) = points[i](1) + r * sin(points[i](2) + theta);
34 | shiftedPoints[i] = p;
35 | }
36 |
37 | return shiftedPoints;
38 | }
39 |
40 | Eigen::Vector3f ClusterAbstraction::shiftPoint(Eigen::Vector3f& point, const Eigen::Vector2f& trans)
41 | {
42 | float r = trans(0);
43 | float theta = trans(1);
44 |
45 | Eigen::Vector3f p;
46 | p(0) = point(0) + r * cos(point(2) + theta);
47 | p(1) = point(1) + r * sin(point(2) + theta);
48 | p(2) = point(2);
49 |
50 |
51 | return p;
52 | }
53 |
54 |
55 | Eigen::Vector2f ClusterAbstraction::computePolarDifference(Eigen::Vector3f pm, Eigen::Vector3f pn)
56 | {
57 | Eigen::Vector2f diff(0, 0);
58 |
59 | diff(0) = (pm.head(2) - pn.head(2)).norm();
60 | diff(1) = Wrap2Pi(atan2(pn(1) - pm(1), pn(0) - pm(0)) - (pm(2))); //Do I need to add M_PI here?
61 |
62 | return diff;
63 | }
64 |
65 |
66 | void ClusterAbstraction::computePolarVariance(std::vector& polarPoints, std::vector