[random_seed]' % argv[0])
91 | print('Example: %s exp2 1 9999' % argv[0])
92 | exit(1)
93 |
94 | # Grab input args
95 | dataset = argv[1]
96 | use_odometry = True if int(argv[2]) else False
97 | seed = int(argv[3]) if len(argv) > 3 else 0
98 |
99 | # Allocate byte array to receive map updates
100 | mapbytes = bytearray(MAP_SIZE_PIXELS * MAP_SIZE_PIXELS)
101 |
102 | # Load the data from the file
103 | timestamps, lidars, odometries = load_data('.', dataset)
104 |
105 | # Build a robot model if we want odometry
106 | robot = Rover() if use_odometry else None
107 |
108 | # Create a CoreSLAM object with laser params and optional robot object
109 | slam = RMHC_SLAM(MinesLaser(), MAP_SIZE_PIXELS, MAP_SIZE_METERS, random_seed=seed) \
110 | if seed \
111 | else Deterministic_SLAM(MinesLaser(), MAP_SIZE_PIXELS, MAP_SIZE_METERS)
112 |
113 | # Set up a SLAM display, named by dataset
114 | viz = MapVisualizer(MAP_SIZE_PIXELS, MAP_SIZE_METERS, dataset)
115 |
116 | # Pose will be modified in our threaded code
117 | pose = [0,0,0]
118 |
119 | # Launch the data-collection / update thread
120 | thread = Thread(target=threadfunc, args=(robot, slam, timestamps, lidars, odometries if use_odometry else None, mapbytes, pose))
121 | thread.daemon = True
122 | thread.start()
123 |
124 | # Loop forever,displaying current map and pose
125 | while True:
126 |
127 | # Display map and robot pose, exiting gracefully if user closes it
128 | if not viz.display(pose[0]/1000., pose[1]/1000., pose[2], mapbytes):
129 | exit(0)
130 |
131 | main()
132 |
--------------------------------------------------------------------------------
/java/edu/wlu/cs/levy/breezyslam/algorithms/CoreSLAM.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * CoreSLAM.java abstract Java class for CoreSLAM algorithm in BreezySLAM
4 | *
5 | * Copyright (C) 2014 Simon D. Levy
6 |
7 | * This code is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation, either version 3 of the
10 | * License, or (at your option) any later version.
11 | *
12 | * This code is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with this code. If not, see .
19 | */
20 |
21 |
22 | package edu.wlu.cs.levy.breezyslam.algorithms;
23 |
24 | import edu.wlu.cs.levy.breezyslam.components.Laser;
25 | import edu.wlu.cs.levy.breezyslam.components.PoseChange;
26 | import edu.wlu.cs.levy.breezyslam.components.Map;
27 | import edu.wlu.cs.levy.breezyslam.components.Scan;
28 |
29 | /**
30 | * CoreSLAM is an abstract class that uses the classes Position, Map, Scan, and Laser
31 | * to run variants of the simple CoreSLAM (tinySLAM) algorithm described in
32 | *
33 | * @inproceedings{coreslam-2010,
34 | * author = {Bruno Steux and Oussama El Hamzaoui},
35 | * title = {CoreSLAM: a SLAM Algorithm in less than 200 lines of C code},
36 | * booktitle = {11th International Conference on Control, Automation,
37 | * Robotics and Vision, ICARCV 2010, Singapore, 7-10
38 | * December 2010, Proceedings},
39 | * pages = {1975-1979},
40 | * publisher = {IEEE},
41 | * year = {2010}
42 | * }
43 | *
44 | * Implementing classes should provide the method
45 | *
46 | * void updateMapAndPointcloud(int * scan_mm, PoseChange & poseChange)
47 | *
48 | * to update the map and point-cloud (particle cloud).
49 | *
50 | */
51 | public abstract class CoreSLAM {
52 |
53 | /**
54 | * The quality of the map (0 through 255)
55 | */
56 | public int map_quality = 50;
57 |
58 | /**
59 | * The width in millimeters of each "hole" in the map (essentially, wall width)
60 | */
61 | public double hole_width_mm = 600;
62 |
63 | protected Laser laser;
64 |
65 | protected PoseChange poseChange;
66 |
67 | protected Map map;
68 |
69 | protected Scan scan_for_mapbuild;
70 | protected Scan scan_for_distance;
71 |
72 | public CoreSLAM(Laser laser, int map_size_pixels, double map_size_meters)
73 | {
74 | // Set default params
75 | this.laser = new Laser(laser);
76 |
77 | // Initialize poseChange (dxyMillimeters, dthetaDegrees, dtSeconds) for odometry
78 | this.poseChange = new PoseChange();
79 |
80 | // Initialize a scan for computing distance to map, and one for updating map
81 | this.scan_for_mapbuild = this.scan_create(3);
82 | this.scan_for_distance = this.scan_create(1);
83 |
84 | // Initialize the map
85 | this.map = new Map(map_size_pixels, map_size_meters);
86 | }
87 |
88 | private Scan scan_create(int span)
89 | {
90 | return new Scan(this.laser, span);
91 | }
92 |
93 | private void scan_update(Scan scan, int [] scan_mm)
94 | {
95 | scan.update(scan_mm, this.hole_width_mm, this.poseChange);
96 | }
97 |
98 |
99 | public void update(int [] scan_mm, PoseChange poseChange)
100 | {
101 | // Build a scan for computing distance to map, and one for updating map
102 | this.scan_update(this.scan_for_mapbuild, scan_mm);
103 | this.scan_update(this.scan_for_distance, scan_mm);
104 |
105 | // Update poseChange
106 | this.poseChange.update(poseChange.getDxyMm(), poseChange.getDthetaDegrees(), poseChange.getDtSeconds());
107 |
108 | // Implementing class updates map and pointcloud
109 | this.updateMapAndPointcloud(poseChange);
110 | }
111 |
112 | /**
113 | * Updates the scan, and calls the the implementing class's updateMapAndPointcloud method with zero poseChange
114 | * (no odometry).
115 | * @param scan_mm Lidar scan values, whose count is specified in the scan_size
116 | * attribute of the Laser object passed to the CoreSlam constructor
117 | */
118 | public void update(int [] scan_mm)
119 | {
120 | PoseChange zero_poseChange = new PoseChange();
121 |
122 | this.update(scan_mm, zero_poseChange);
123 | }
124 |
125 |
126 | protected abstract void updateMapAndPointcloud(PoseChange poseChange);
127 |
128 | public void getmap(byte [] mapbytes)
129 | {
130 | this.map.get(mapbytes);
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/matlab/WheeledRobot.m:
--------------------------------------------------------------------------------
1 | classdef WheeledRobot
2 | %WheeledRobot An abstract class supporting ododmetry for wheeled robots.
3 | % Your implementing class should provide the method:
4 | %
5 | % extractOdometry(obj, timestamp, leftWheel, rightWheel) -->
6 | % (timestampSeconds, leftWheelDegrees, rightWheelDegrees)
7 | %
8 | % Copyright (C) 2014 Simon D. Levy
9 | %
10 | % This code is free software: you can redistribute it and/or modify
11 | % it under the terms of the GNU Lesser General Public License as
12 | % published by the Free Software Foundation, either version 3 of the
13 | % License, or (at your option) any later version.
14 | %
15 | % This code is distributed in the hope that it will be useful,
16 | % but WITHOUT ANY WARRANTY without even the implied warranty of
17 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | % GNU General Public License for more details.
19 | %
20 | % You should have received a copy of the GNU Lesser General Public License
21 | % along with this code. If not, see .
22 |
23 | properties (Access = 'private')
24 |
25 | wheelRadiusMillimeters
26 | halfAxleLengthMillimeters
27 |
28 | timestampSecondsPrev
29 | leftWheelDegreesPrev
30 | rightWheelDegreesPrev
31 |
32 | end
33 |
34 | methods (Access = 'protected')
35 |
36 | function s = str(obj)
37 | % Returns a string representation of this WheeledRobot
38 | s = sprintf('', ...
39 | obj.wheelRadiusMillimeters, obj.halfAxleLengthMillimeters);
40 | end
41 |
42 | function robot = WheeledRobot(wheelRadiusMillimeters, halfAxleLengthMillimeters)
43 | % Constructs a WheeledRobot object
44 | % robot = WheeledRobot(wheelRadiusMillimeters, halfAxleLengthMillimeters)
45 | robot.wheelRadiusMillimeters = wheelRadiusMillimeters;
46 | robot.halfAxleLengthMillimeters = halfAxleLengthMillimeters;
47 |
48 | end
49 |
50 | function r = deg2rad(~, d)
51 | % Converts degrees to radians
52 | r = d * pi / 180;
53 | end
54 |
55 | end
56 |
57 | methods (Abstract)
58 |
59 | extractOdometry(obj, timestamp, leftWheel, rightWheel)
60 |
61 | end
62 |
63 | methods (Access = 'public')
64 |
65 | function [poseChange, obj] = computePoseChange(obj, timestamp, leftWheelOdometry, rightWheelOdometry)
66 | % Computes forward and angular poseChange based on odometry.
67 | %
68 | % Parameters:
69 |
70 | % timestamp time stamp, in whatever units your robot uses
71 | % leftWheelOdometry odometry for left wheel, in whatever form your robot uses
72 | % rightWheelOdometry odometry for right wheel, in whatever form your robot uses
73 | %
74 | % Returns a tuple (dxyMillimeters, dthetaDegrees, dtSeconds)
75 |
76 | % dxyMillimeters forward distance traveled, in millimeters
77 | % dthetaDegrees change in angular position, in degrees
78 | % dtSeconds elapsed time since previous odometry, in seconds
79 |
80 | dxyMillimeters = 0;
81 | dthetaDegrees = 0;
82 | dtSeconds = 0;
83 |
84 | [timestampSecondsCurr, leftWheelDegreesCurr, rightWheelDegreesCurr] = ...
85 | obj.extractOdometry(timestamp, leftWheelOdometry, rightWheelOdometry);
86 |
87 | if obj.timestampSecondsPrev
88 |
89 | leftDiffDegrees = leftWheelDegreesCurr - obj.leftWheelDegreesPrev;
90 | rightDiffDegrees = rightWheelDegreesCurr - obj.rightWheelDegreesPrev;
91 |
92 | dxyMillimeters = obj.wheelRadiusMillimeters * ...
93 | (obj.deg2rad(leftDiffDegrees) + obj.deg2rad(rightDiffDegrees));
94 |
95 | dthetaDegrees = (obj.wheelRadiusMillimeters / obj.halfAxleLengthMillimeters) * ...
96 | (rightDiffDegrees - leftDiffDegrees);
97 |
98 | dtSeconds = timestampSecondsCurr - obj.timestampSecondsPrev;
99 | end
100 |
101 | % Store current odometry for next time
102 | obj.timestampSecondsPrev = timestampSecondsCurr;
103 | obj.leftWheelDegreesPrev = leftWheelDegreesCurr;
104 | obj.rightWheelDegreesPrev = rightWheelDegreesCurr;
105 |
106 | % Return linear velocity, angular velocity, time difference
107 | poseChange = [dxyMillimeters, dthetaDegrees, dtSeconds];
108 |
109 | end
110 | end
111 | end
112 |
113 |
--------------------------------------------------------------------------------
/java/edu/wlu/cs/levy/breezyslam/components/jnibreezyslam_components.c:
--------------------------------------------------------------------------------
1 | /*
2 | * jnibreezyslam_components.c Java Native Interface code for BreezySLAM components
3 | *
4 | * Copyright (C) 2014 Simon D. Levy
5 | *
6 | * This code is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as
8 | * published by the Free Software Foundation, either version 3 of the
9 | * License, or (at your option) any later version.
10 | *
11 | * This code is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this code. If not, see .
18 | */
19 |
20 | #include "../jni_utils.h"
21 |
22 | #include "Map.h"
23 | #include "Scan.h"
24 |
25 | #include
26 | #include
27 |
28 | #define MAXSTR 100
29 |
30 | // Map methods -----------------------------------------------------------------------------------------
31 |
32 | JNIEXPORT void JNICALL Java_edu_wlu_cs_levy_breezyslam_components_Map_init (JNIEnv *env, jobject thisobject, jint size_pixels, jdouble size_meters)
33 | {
34 | map_t * map = (map_t *)malloc(sizeof(map_t));
35 | map_init(map, (int)size_pixels, (double)size_meters);
36 | ptr_to_obj(env, thisobject, map);
37 | }
38 |
39 | JNIEXPORT jstring JNICALL Java_edu_wlu_cs_levy_breezyslam_components_Map_toString (JNIEnv *env, jobject thisobject)
40 | {
41 | map_t * map = cmap_from_jmap(env, thisobject);
42 |
43 | char str[MAXSTR];
44 |
45 | map_string(*map, str);
46 |
47 | return (*env)->NewStringUTF(env, str);
48 | }
49 |
50 | JNIEXPORT void JNICALL Java_edu_wlu_cs_levy_breezyslam_components_Map_get (JNIEnv *env, jobject thisobject, jbyteArray bytes)
51 | {
52 | map_t * map = cmap_from_jmap(env, thisobject);
53 |
54 | jbyte * ptr = (*env)->GetByteArrayElements(env, bytes, NULL);
55 |
56 | map_get(map, ptr);
57 |
58 | (*env)->ReleaseByteArrayElements(env, bytes, ptr, 0);
59 | }
60 |
61 | JNIEXPORT void JNICALL Java_edu_wlu_cs_levy_breezyslam_components_Map_update (JNIEnv *env, jobject thisobject,
62 | jobject scanobject,
63 | jdouble position_x_mm,
64 | jdouble position_y_mm,
65 | jdouble position_theta_degrees,
66 | jint quality,
67 | jdouble hole_width_mm)
68 | {
69 | map_t * map = cmap_from_jmap(env, thisobject);
70 |
71 | scan_t * scan = cscan_from_jscan(env, scanobject);
72 |
73 | position_t position;
74 |
75 | position.x_mm = position_x_mm;
76 | position.y_mm = position_y_mm;
77 | position.theta_degrees = position_theta_degrees;
78 |
79 | map_update(map, scan, position, quality, hole_width_mm);
80 | }
81 |
82 |
83 | // Scan methods -----------------------------------------------------------------------------------------
84 |
85 | JNIEXPORT void JNICALL Java_edu_wlu_cs_levy_breezyslam_components_Scan_init (JNIEnv *env, jobject thisobject,
86 | jint span,
87 | jint scan_size,
88 | jdouble scan_rate_hz,
89 | jdouble detection_angle_degrees,
90 | jdouble distance_no_detection_mm,
91 | jint detection_margin,
92 | jdouble offset_mm)
93 | {
94 | scan_t * scan = (scan_t *)malloc(sizeof(scan_t));
95 |
96 | scan_init(scan,
97 | span,
98 | scan_size,
99 | scan_rate_hz,
100 | detection_angle_degrees,
101 | distance_no_detection_mm,
102 | detection_margin,
103 | offset_mm);
104 |
105 | ptr_to_obj(env, thisobject, scan);
106 | }
107 |
108 | JNIEXPORT jstring JNICALL Java_edu_wlu_cs_levy_breezyslam_components_Scan_toString (JNIEnv *env, jobject thisobject)
109 | {
110 | scan_t * scan = cscan_from_jscan(env, thisobject);
111 |
112 | char str[MAXSTR];
113 |
114 | scan_string(*scan, str);
115 |
116 | return (*env)->NewStringUTF(env, str);
117 | }
118 |
119 | JNIEXPORT void JNICALL Java_edu_wlu_cs_levy_breezyslam_components_Scan_update (JNIEnv *env, jobject thisobject,
120 | jintArray lidar_mm,
121 | jdouble hole_width_mm,
122 | jdouble velocities_dxy_mm,
123 | jdouble velocities_dtheta_degrees)
124 | {
125 | scan_t * scan = cscan_from_jscan(env, thisobject);
126 |
127 | jint * lidar_mm_c = (*env)->GetIntArrayElements(env, lidar_mm, 0);
128 |
129 | // no support for angles/interpolation yet
130 | scan_update(scan, NULL, lidar_mm_c, scan->size, hole_width_mm, velocities_dxy_mm, velocities_dtheta_degrees);
131 |
132 | (*env)->ReleaseIntArrayElements(env, lidar_mm, lidar_mm_c, 0);
133 | }
134 |
--------------------------------------------------------------------------------
/cpp/Doxyfile:
--------------------------------------------------------------------------------
1 | #---------------------------------------------------------------------------
2 | # Doxyfile: Project-related configuration options
3 | #
4 | # Adapted from
5 | #
6 | # http://www.bluequartz.net/projects/EIM_Segmentation/SoftwareDocumentation/html/exampledoxyfile.html
7 | #
8 | # downloaded 21 March 2014
9 | #
10 | # Copyright (C) Simon D. Levy 2014
11 | #
12 | # This code is free software: you can redistribute it and/or modify
13 | # it under the terms of the GNU Lesser General Public License as
14 | # published by the Free Software Foundation, either version 3 of the
15 | # License, or (at your option) any later version.
16 | #
17 | # This code is distributed in the hope that it will be useful,
18 | # but WITHOUT ANY WARRANTY without even the implied warranty of
19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | # GNU General Public License for more details.
21 | #
22 | # You should have received a copy of the GNU Lesser General Public License
23 | # along with this code. If not, see .
24 | #---------------------------------------------------------------------------
25 | DOXYFILE_ENCODING = UTF-8
26 | PROJECT_NAME = BreezySLAM
27 | PROJECT_NUMBER =
28 | OUTPUT_DIRECTORY = Documentation
29 | CREATE_SUBDIRS = YES
30 | OUTPUT_LANGUAGE = English
31 | BRIEF_MEMBER_DESC = YES
32 | REPEAT_BRIEF = YES
33 | ABBREVIATE_BRIEF = "The $name class" \
34 | "The $name widget" \
35 | "The $name file" \
36 | is \
37 | provides \
38 | specifies \
39 | contains \
40 | represents \
41 | a \
42 | an \
43 | the
44 | ALWAYS_DETAILED_SEC = NO
45 | INLINE_INHERITED_MEMB = NO
46 | FULL_PATH_NAMES = YES
47 | STRIP_FROM_PATH = Source
48 | SHORT_NAMES = NO
49 | JAVADOC_AUTOBRIEF = NO
50 | MULTILINE_CPP_IS_BRIEF = NO
51 | INHERIT_DOCS = YES
52 | SEPARATE_MEMBER_PAGES = NO
53 | TAB_SIZE = 4
54 | OPTIMIZE_OUTPUT_FOR_C = NO
55 | OPTIMIZE_OUTPUT_JAVA = NO
56 | BUILTIN_STL_SUPPORT = YES
57 | CPP_CLI_SUPPORT = NO
58 | DISTRIBUTE_GROUP_DOC = YES
59 | SUBGROUPING = YES
60 | #---------------------------------------------------------------------------
61 | # Build related configuration options
62 | #---------------------------------------------------------------------------
63 | EXTRACT_ALL = YES
64 | EXTRACT_PRIVATE = NO
65 | EXTRACT_STATIC = YES
66 | EXTRACT_LOCAL_CLASSES = YES
67 | EXTRACT_LOCAL_METHODS = NO
68 | HIDE_UNDOC_MEMBERS = NO
69 | HIDE_UNDOC_CLASSES = NO
70 | HIDE_FRIEND_COMPOUNDS = YES
71 | HIDE_IN_BODY_DOCS = NO
72 | INTERNAL_DOCS = NO
73 | CASE_SENSE_NAMES = NO
74 | HIDE_SCOPE_NAMES = NO
75 | SHOW_INCLUDE_FILES = NO
76 | INLINE_INFO = YES
77 | SORT_MEMBER_DOCS = YES
78 | SORT_BRIEF_DOCS = NO
79 | SORT_BY_SCOPE_NAME = NO
80 | GENERATE_TODOLIST = YES
81 | GENERATE_TESTLIST = YES
82 | GENERATE_BUGLIST = YES
83 | GENERATE_DEPRECATEDLIST= YES
84 | MAX_INITIALIZER_LINES = 30
85 | SHOW_USED_FILES = YES
86 | #---------------------------------------------------------------------------
87 | # configuration options related to warning and progress messages
88 | #---------------------------------------------------------------------------
89 | QUIET = NO
90 | WARNINGS = YES
91 | WARN_IF_UNDOCUMENTED = YES
92 | WARN_IF_DOC_ERROR = YES
93 | WARN_NO_PARAMDOC = NO
94 | WARN_FORMAT = "$file:$line: $text"
95 | #---------------------------------------------------------------------------
96 | # configuration options related to the input files
97 | #---------------------------------------------------------------------------
98 | INPUT = breezyslam.hpp Position.hpp Map.hpp Scan.hpp \
99 | Velocities.hpp Laser.hpp WheeledRobot.hpp algorithms.hpp
100 | INPUT_ENCODING = UTF-8
101 | FILE_PATTERNS = *.c *.cc *.cxx *.cpp *.c++ \
102 | *.h *.hh *.hxx *.hpp *.h++ *.m *.mm *.dox \
103 | RECURSIVE = YES
104 | EXCLUDE_SYMLINKS = NO
105 | EXAMPLE_PATTERNS = *
106 | EXAMPLE_RECURSIVE = NO
107 | FILTER_SOURCE_FILES = NO
108 | #---------------------------------------------------------------------------
109 | # configuration options related to the alphabetical class index
110 | #---------------------------------------------------------------------------
111 | ALPHABETICAL_INDEX = YES
112 | COLS_IN_ALPHA_INDEX = 3
113 | IGNORE_PREFIX =
114 | #---------------------------------------------------------------------------
115 | # configuration options related to the HTML output
116 | #---------------------------------------------------------------------------
117 | GENERATE_HTML = YES
118 | HTML_OUTPUT = html
119 | HTML_FILE_EXTENSION = .html
120 | HTML_HEADER =
121 | HTML_FOOTER =
122 | HTML_STYLESHEET =
123 | GENERATE_HTMLHELP = NO
124 | CHM_FILE =
125 | HHC_LOCATION =
126 | GENERATE_CHI = NO
127 | BINARY_TOC = NO
128 | TOC_EXPAND = NO
129 | DISABLE_INDEX = NO
130 | ENUM_VALUES_PER_LINE = 4
131 | GENERATE_TREEVIEW = NO
132 | TREEVIEW_WIDTH = 250
133 |
--------------------------------------------------------------------------------
/examples/log2pgm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | '''
4 | log2pgm.py : BreezySLAM Python demo. Reads logfile with odometry and scan data
5 | from Paris Mines Tech and produces a .PGM image file showing robot
6 | trajectory and final map.
7 |
8 | For details see
9 |
10 | @inproceedings{coreslam-2010,
11 | author = {Bruno Steux and Oussama El Hamzaoui},
12 | title = {CoreSLAM: a SLAM Algorithm in less than 200 lines of C code},
13 | booktitle = {11th International Conference on Control, Automation,
14 | Vehicleics and Vision, ICARCV 2010, Singapore, 7-10
15 | December 2010, Proceedings},
16 | pages = {1975-1979},
17 | publisher = {IEEE},
18 | year = {2010}
19 | }
20 |
21 | Copyright (C) 2014 Simon D. Levy
22 |
23 | This code is free software: you can redistribute it and/or modify
24 | it under the terms of the GNU Lesser General Public License as
25 | published by the Free Software Foundation, either version 3 of the
26 | License, or (at your option) any later version.
27 |
28 | This code is distributed in the hope that it will be useful,
29 | but WITHOUT ANY WARRANTY without even the implied warranty of
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 | GNU General Public License for more details.
32 |
33 | You should have received a copy of the GNU Lesser General Public License
34 | along with this code. If not, see .
35 |
36 | Change log:
37 |
38 | 20-APR-2014 - Simon D. Levy - Get params from command line
39 | 05-JUN-2014 - SDL - get random seed from command line
40 | '''
41 |
42 | # Map size, scale
43 | MAP_SIZE_PIXELS = 800
44 | MAP_SIZE_METERS = 32
45 |
46 | from breezyslam.algorithms import Deterministic_SLAM, RMHC_SLAM
47 |
48 | from mines import MinesLaser, Rover, load_data
49 | from progressbar import ProgressBar
50 | from pgm_utils import pgm_save
51 |
52 | from sys import argv, exit, stdout
53 | from time import time
54 |
55 | def main():
56 |
57 | # Bozo filter for input args
58 | if len(argv) < 3:
59 | print('Usage: %s [random_seed]' % argv[0])
60 | print('Example: %s exp2 1 9999' % argv[0])
61 | exit(1)
62 |
63 | # Grab input args
64 | dataset = argv[1]
65 | use_odometry = True if int(argv[2]) else False
66 | seed = int(argv[3]) if len(argv) > 3 else 0
67 |
68 | # Load the data from the file, ignoring timestamps
69 | _, lidars, odometries = load_data('.', dataset)
70 |
71 | # Build a robot model if we want odometry
72 | robot = Rover() if use_odometry else None
73 |
74 | # Create a CoreSLAM object with laser params and optional robot object
75 | slam = RMHC_SLAM(MinesLaser(), MAP_SIZE_PIXELS, MAP_SIZE_METERS, random_seed=seed) \
76 | if seed \
77 | else Deterministic_SLAM(MinesLaser(), MAP_SIZE_PIXELS, MAP_SIZE_METERS)
78 |
79 | # Report what we're doing
80 | nscans = len(lidars)
81 | print('Processing %d scans with%s odometry / with%s particle filter...' % \
82 | (nscans, \
83 | '' if use_odometry else 'out', '' if seed else 'out'))
84 | progbar = ProgressBar(0, nscans, 80)
85 |
86 | # Start with an empty trajectory of positions
87 | trajectory = []
88 |
89 | # Start timing
90 | start_sec = time()
91 |
92 | # Loop over scans
93 | for scanno in range(nscans):
94 |
95 | if use_odometry:
96 |
97 | # Convert odometry to pose change (dxy_mm, dtheta_degrees, dt_seconds)
98 | velocities = robot.computePoseChange(odometries[scanno])
99 |
100 | # Update SLAM with lidar and velocities
101 | slam.update(lidars[scanno], velocities)
102 |
103 | else:
104 |
105 | # Update SLAM with lidar alone
106 | slam.update(lidars[scanno])
107 |
108 | # Get new position
109 | x_mm, y_mm, theta_degrees = slam.getpos()
110 |
111 | # Add new position to trajectory
112 | trajectory.append((x_mm, y_mm))
113 |
114 | # Tame impatience
115 | progbar.updateAmount(scanno)
116 | stdout.write('\r%s' % str(progbar))
117 | stdout.flush()
118 |
119 | # Report elapsed time
120 | elapsed_sec = time() - start_sec
121 | print('\n%d scans in %f sec = %f scans / sec' % (nscans, elapsed_sec, nscans/elapsed_sec))
122 |
123 |
124 | # Create a byte array to receive the computed maps
125 | mapbytes = bytearray(MAP_SIZE_PIXELS * MAP_SIZE_PIXELS)
126 |
127 | # Get final map
128 | slam.getmap(mapbytes)
129 |
130 | # Put trajectory into map as black pixels
131 | for coords in trajectory:
132 |
133 | x_mm, y_mm = coords
134 |
135 | x_pix = mm2pix(x_mm)
136 | y_pix = mm2pix(y_mm)
137 |
138 | mapbytes[y_pix * MAP_SIZE_PIXELS + x_pix] = 0;
139 |
140 | # Save map and trajectory as PGM file
141 | pgm_save('%s.pgm' % dataset, mapbytes, (MAP_SIZE_PIXELS, MAP_SIZE_PIXELS))
142 |
143 | # Helpers ---------------------------------------------------------
144 |
145 | def mm2pix(mm):
146 |
147 | return int(mm / (MAP_SIZE_METERS * 1000. / MAP_SIZE_PIXELS))
148 |
149 |
150 | main()
151 |
--------------------------------------------------------------------------------
/java/edu/wlu/cs/levy/breezyslam/robots/WheeledRobot.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * BreezySLAM: Simple, efficient SLAM in Java
4 | *
5 | * WheeledRobot.java - Java class for wheeled robots
6 | *
7 | * Copyright (C) 2014 Simon D. Levy
8 | *
9 | * This code is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Lesser General Public License as
11 | * published by the Free Software Foundation, either version 3 of the
12 | * License, or (at your option) any later version.
13 | *
14 | * This code is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Lesser General Public License
20 | * along with this code. If not, see .
21 | */
22 |
23 |
24 | package edu.wlu.cs.levy.breezyslam.robots;
25 |
26 | import edu.wlu.cs.levy.breezyslam.components.PoseChange;
27 |
28 |
29 | /**
30 | * An abstract class for wheeled robots. Supports computation of forward and angular
31 | * poseChange based on odometry. Your subclass should should implement the
32 | * extractOdometry method.
33 | */
34 | public abstract class WheeledRobot
35 | {
36 |
37 | /**
38 | * Builds a WheeledRobot object. Parameters should be based on the specifications for
39 | * your robot.
40 | * @param wheel_radius_mm radius of each odometry wheel, in meters
41 | * @param half_axle_length_mm half the length of the axle between the odometry wheels, in meters
42 | * @return a new WheeledRobot object
43 | */
44 | protected WheeledRobot(double wheel_radius_mm, double half_axle_length_mm)
45 | {
46 | this.wheel_radius_mm = wheel_radius_mm;
47 | this.half_axle_length_mm = half_axle_length_mm;
48 |
49 | this.timestamp_seconds_prev = 0;
50 | this.left_wheel_degrees_prev = 0;
51 | this.right_wheel_degrees_prev = 0;
52 | }
53 |
54 | public String toString()
55 | {
56 |
57 | return String.format("",
58 | this.wheel_radius_mm, this.half_axle_length_mm, this.descriptorString());
59 | }
60 |
61 | /**
62 | * Computes forward and angular poseChange based on odometry.
63 | * @param timestamp time stamp, in whatever units your robot uses
64 | * @param left_wheel_odometry odometry for left wheel, in whatever units your robot uses
65 | * @param right_wheel_odometry odometry for right wheel, in whatever units your robot uses
66 | * @return poseChange object representing poseChange for these odometry values
67 | */
68 |
69 | public PoseChange computePoseChange( double timestamp, double left_wheel_odometry, double right_wheel_odometry)
70 | {
71 | WheelOdometry odometry = this.extractOdometry(timestamp, left_wheel_odometry, right_wheel_odometry);
72 |
73 | double dxy_mm = 0;
74 | double dtheta_degrees = 0;
75 | double dt_seconds = 0;
76 |
77 | if (this.timestamp_seconds_prev > 0)
78 | {
79 | double left_diff_degrees = odometry.left_wheel_degrees - this.left_wheel_degrees_prev;
80 | double right_diff_degrees = odometry.right_wheel_degrees - this.right_wheel_degrees_prev;
81 |
82 | dxy_mm = this.wheel_radius_mm * (java.lang.Math.toRadians(left_diff_degrees) + java.lang.Math.toRadians(right_diff_degrees));
83 |
84 | dtheta_degrees = this.wheel_radius_mm / this.half_axle_length_mm * (right_diff_degrees - left_diff_degrees);
85 |
86 | dt_seconds = odometry.timestamp_seconds - this.timestamp_seconds_prev;
87 | }
88 |
89 | // Store current odometry for next time
90 | this.timestamp_seconds_prev = odometry.timestamp_seconds;
91 | this.left_wheel_degrees_prev = odometry.left_wheel_degrees;
92 | this.right_wheel_degrees_prev = odometry.right_wheel_degrees;
93 |
94 | return new PoseChange(dxy_mm, dtheta_degrees, dt_seconds);
95 | }
96 |
97 | /**
98 | * Extracts usable odometry values from your robot's odometry.
99 | * @param timestamp time stamp, in whatever units your robot uses
100 | * @param left_wheel_odometry odometry for left wheel, in whatever units your robot uses
101 | * @param right_wheel_odometry odometry for right wheel, in whatever units your robot uses
102 | * @return WheelOdometry object containing timestamp in seconds, left wheel degrees, right wheel degrees
103 | */
104 | protected abstract WheelOdometry extractOdometry(double timestamp, double left_wheel_odometry, double right_wheel_odometry);
105 |
106 | protected abstract String descriptorString();
107 |
108 | protected class WheelOdometry
109 | {
110 | public WheelOdometry(double timestamp_seconds, double left_wheel_degrees, double right_wheel_degrees)
111 | {
112 | this.timestamp_seconds = timestamp_seconds;
113 | this.left_wheel_degrees = left_wheel_degrees;
114 | this.right_wheel_degrees = right_wheel_degrees;
115 | }
116 |
117 | public double timestamp_seconds;
118 | public double left_wheel_degrees;
119 | public double right_wheel_degrees;
120 |
121 | }
122 |
123 |
124 | private double wheel_radius_mm;
125 | private double half_axle_length_mm;
126 |
127 | private double timestamp_seconds_prev;
128 | private double left_wheel_degrees_prev;
129 | private double right_wheel_degrees_prev;
130 | }
131 |
--------------------------------------------------------------------------------
/examples/log2png.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | '''
4 | log2png.py : BreezySLAM Python demo. Reads logfile with odometry and scan data
5 | from Paris Mines Tech and produces a .PNG image file showing robot
6 | trajectory and final map.
7 |
8 | For details see
9 |
10 | @inproceedings{coreslam-2010,
11 | author = {Bruno Steux and Oussama El Hamzaoui},
12 | title = {CoreSLAM: a SLAM Algorithm in less than 200 lines of C code},
13 | booktitle = {11th International Conference on Control, Automation,
14 | Vehicleics and Vision, ICARCV 2010, Singapore, 7-10
15 | December 2010, Proceedings},
16 | pages = {1975-1979},
17 | publisher = {IEEE},
18 | year = {2010}
19 | }
20 |
21 | Copyright (C) 2014 Simon D. Levy
22 |
23 | This code is free software: you can redistribute it and/or modify
24 | it under the terms of the GNU Lesser General Public License as
25 | published by the Free Software Foundation, either version 3 of the
26 | License, or (at your option) any later version.
27 |
28 | This code is distributed in the hope that it will be useful,
29 | but WITHOUT ANY WARRANTY without even the implied warranty of
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 | GNU General Public License for more details.
32 |
33 | You should have received a copy of the GNU Lesser General Public License
34 | along with this code. If not, see .
35 |
36 | Change log:
37 |
38 | 20-APR-2014 - Simon D. Levy - Get params from command line
39 | 05-JUN-2014 - SDL - get random seed from command line
40 | '''
41 |
42 | # Map size, scale
43 | MAP_SIZE_PIXELS = 800
44 | MAP_SIZE_METERS = 32
45 |
46 | from breezyslam.algorithms import Deterministic_SLAM, RMHC_SLAM
47 |
48 | from mines import MinesLaser, Rover, load_data
49 | from progressbar import ProgressBar
50 |
51 | from sys import argv, exit, stdout
52 | from time import time
53 |
54 | from PIL import Image
55 |
56 | def main():
57 |
58 | # Bozo filter for input args
59 | if len(argv) < 3:
60 | print('Usage: %s [random_seed]' % argv[0])
61 | print('Example: %s exp2 1 9999' % argv[0])
62 | exit(1)
63 |
64 | # Grab input args
65 | dataset = argv[1]
66 | use_odometry = True if int(argv[2]) else False
67 | seed = int(argv[3]) if len(argv) > 3 else 0
68 |
69 | # Load the data from the file, ignoring timestamps
70 | _, lidars, odometries = load_data('.', dataset)
71 |
72 | # Build a robot model if we want odometry
73 | robot = Rover() if use_odometry else None
74 |
75 | # Create a CoreSLAM object with laser params and optional robot object
76 | slam = RMHC_SLAM(MinesLaser(), MAP_SIZE_PIXELS, MAP_SIZE_METERS, random_seed=seed) \
77 | if seed \
78 | else Deterministic_SLAM(MinesLaser(), MAP_SIZE_PIXELS, MAP_SIZE_METERS)
79 |
80 | # Report what we're doing
81 | nscans = len(lidars)
82 | print('Processing %d scans with%s odometry / with%s particle filter...' % \
83 | (nscans, \
84 | '' if use_odometry else 'out', '' if seed else 'out'))
85 | progbar = ProgressBar(0, nscans, 80)
86 |
87 | # Start with an empty trajectory of positions
88 | trajectory = []
89 |
90 | # Start timing
91 | start_sec = time()
92 |
93 | # Loop over scans
94 | for scanno in range(nscans):
95 |
96 | if use_odometry:
97 |
98 | # Convert odometry to velocities
99 | velocities = robot.computePoseChange(odometries[scanno])
100 |
101 | # Update SLAM with lidar and velocities
102 | slam.update(lidars[scanno], velocities)
103 |
104 | else:
105 |
106 | # Update SLAM with lidar alone
107 | slam.update(lidars[scanno])
108 |
109 | # Get new position
110 | x_mm, y_mm, theta_degrees = slam.getpos()
111 |
112 | # Add new position to trajectory
113 | trajectory.append((x_mm, y_mm))
114 |
115 | # Tame impatience
116 | progbar.updateAmount(scanno)
117 | stdout.write('\r%s' % str(progbar))
118 | stdout.flush()
119 |
120 | # Report elapsed time
121 | elapsed_sec = time() - start_sec
122 | print('\n%d scans in %f sec = %f scans / sec' % (nscans, elapsed_sec, nscans/elapsed_sec))
123 |
124 |
125 | # Create a byte array to receive the computed maps
126 | mapbytes = bytearray(MAP_SIZE_PIXELS * MAP_SIZE_PIXELS)
127 |
128 | # Get final map
129 | slam.getmap(mapbytes)
130 |
131 | # Put trajectory into map as black pixels
132 | for coords in trajectory:
133 |
134 | x_mm, y_mm = coords
135 |
136 | x_pix = mm2pix(x_mm)
137 | y_pix = mm2pix(y_mm)
138 |
139 | mapbytes[y_pix * MAP_SIZE_PIXELS + x_pix] = 0;
140 |
141 | # Save map and trajectory as PNG file
142 | image = Image.frombuffer('L', (MAP_SIZE_PIXELS, MAP_SIZE_PIXELS), mapbytes, 'raw', 'L', 0, 1)
143 | image.save('%s.png' % dataset)
144 |
145 |
146 | # Helpers ---------------------------------------------------------
147 |
148 | def mm2pix(mm):
149 |
150 | return int(mm / (MAP_SIZE_METERS * 1000. / MAP_SIZE_PIXELS))
151 |
152 |
153 | main()
154 |
--------------------------------------------------------------------------------
/examples/logdemo.m:
--------------------------------------------------------------------------------
1 | %
2 | % logdemo.m : BreezySLAM Matlab demo. Reads logfile with odometry and scan
3 | % data from Paris Mines Tech and displays the map and robot
4 | % position in real time.
5 | %
6 | % Usage:
7 | %
8 | % >> logdemo(dataset, [use_odometry], [random_seed])
9 | %
10 | % Examples:
11 | %
12 | % >> logdemo('exp2')
13 | %
14 | % For details see
15 | %
16 | % @inproceedings{coreslam-2010,
17 | % author = {Bruno Steux and Oussama El Hamzaoui},
18 | % title = {CoreSLAM: a SLAM Algorithm in less than 200 lines of C code},
19 | % booktitle = {11th International Conference on Control, Automation,
20 | % Robotics and Vision, ICARCV 2010, Singapore, 7-10
21 | % December 2010, Proceedings},
22 | % pages = {1975-1979},
23 | % publisher = {IEEE},
24 | % year = {2010}
25 | % }
26 | %
27 | % Copyright (C) 2014 Simon D. Levy
28 | %
29 | % This code is free software: you can redistribute it and/or modify
30 | % it under the terms of the GNU Lesser General Public License as
31 | % published by the Free Software Foundation, either version 3 of the
32 | % License, or (at your option) any later version.
33 | %
34 | % This code is distributed in the hope that it will be useful,
35 | % but WITHOUT ANY WARRANTY without even the implied warranty of
36 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 | % GNU General Public License for more details.
38 | %
39 | % You should have received a copy of the GNU Lesser General Public License
40 | % along with this code. If not, see .
41 |
42 | function logdemo(dataset, use_odometry, seed)
43 |
44 | % Params
45 |
46 | MAP_SIZE_PIXELS = 800;
47 | MAP_SIZE_METERS = 32;
48 | ROBOT_SIZE_PIXELS = 10;
49 |
50 | % Grab input args
51 |
52 | if nargin < 2
53 | use_odometry = 0;
54 | end
55 |
56 | if nargin < 3
57 | seed = 0;
58 | end
59 |
60 | % Load data from file
61 | [times, scans, odometries] = load_data(dataset);
62 |
63 | % Build a robot model if we want odometry
64 | robot = [];
65 | if use_odometry
66 | robot = MinesRover();
67 | end
68 |
69 | % Create a CoreSLAM object with laser params and optional robot object
70 | if seed
71 | slam = RMHC_SLAM(MinesLaser(), MAP_SIZE_PIXELS, MAP_SIZE_METERS, seed);
72 | else
73 | slam = Deterministic_SLAM(MinesLaser(), MAP_SIZE_PIXELS, MAP_SIZE_METERS);
74 | end
75 |
76 | % Initialize previous time for delay
77 | prevTime = 0;
78 |
79 | % Loop over scans
80 | for scanno = 1:size(scans, 1)
81 |
82 | if use_odometry
83 |
84 | % Convert odometry to velocities
85 | [velocities,robot] = robot.computePoseChange(odometries(scanno, :));
86 |
87 | % Update SLAM with lidar and velocities
88 | slam = slam.update(scans(scanno,:), velocities);
89 |
90 | else
91 |
92 | % Update SLAM with lidar alone
93 | slam = slam.update(scans(scanno,:));
94 | end
95 |
96 | % Get new position
97 | [x_mm, y_mm, theta_degrees] = slam.getpos();
98 |
99 | % Get current map
100 | map = slam.getmap();
101 |
102 | % Display map
103 | hold off
104 | image(map/4) % Keep bytes in [0,64] for colormap
105 | axis('square')
106 | colormap('gray')
107 | hold on
108 |
109 | % Generate a polyline to represent the robot
110 | [x_pix, y_pix] = robot_polyline(ROBOT_SIZE_PIXELS);
111 |
112 | % Rotate the polyline based on the robot's angular rotation
113 | theta_radians = pi * theta_degrees / 180;
114 | x_pix_r = x_pix * cos(theta_radians) - y_pix * sin(theta_radians);
115 | y_pix_r = x_pix * sin(theta_radians) + y_pix * cos(theta_radians);
116 |
117 | % Add the robot's position as offset to the polyline
118 | x_pix = x_pix_r + mm2pix(x_mm, MAP_SIZE_METERS, MAP_SIZE_PIXELS);
119 | y_pix = y_pix_r + mm2pix(y_mm, MAP_SIZE_METERS, MAP_SIZE_PIXELS);
120 |
121 | % Add robot image to map
122 | fill(x_pix, y_pix, 'r')
123 | drawnow
124 |
125 | % Delay based on current time in microseconds
126 | currTime = times(scanno);
127 | if scanno > 1
128 | pause((currTime-prevTime)/1e6)
129 | end
130 | prevTime = times(scanno);
131 |
132 |
133 | end
134 |
135 | % Function to generate a x, y points for a polyline to display the robot
136 | % Currently we just generate a triangle.
137 | function [x_pix, y_pix] = robot_polyline(robot_size)
138 | HEIGHT_RATIO = 1.25;
139 | x_pix = [-robot_size, robot_size, -robot_size];
140 | y_pix = [-robot_size/HEIGHT_RATIO, 0 , robot_size/HEIGHT_RATIO];
141 |
142 | % Function to convert millimeters to pixels -------------------------------
143 |
144 | function pix = mm2pix(mm, MAP_SIZE_METERS, MAP_SIZE_PIXELS)
145 | pix = floor(mm / (MAP_SIZE_METERS * 1000. / MAP_SIZE_PIXELS));
146 |
147 |
148 | % Function to load all from file ------------------------------------------
149 | % Each line in the file has the format:
150 | %
151 | % TIMESTAMP ... Q1 Q1 ... Distances
152 | % (usec) (mm)
153 | % 0 ... 2 3 ... 24 ...
154 | %
155 | %where Q1, Q2 are odometry values
156 |
157 | function [times, scans,odometries] = load_data(dataset)
158 |
159 | data = load([dataset '.dat']);
160 |
161 | times = data(:,1);
162 | scans = data(:,25:end-1); % avoid final ' '
163 | odometries = data(:,[1,3,4]);
164 |
165 | % Function to build a Laser data structure for the Hokuyo URG04LX used for
166 | % collecting the logfile data.
167 |
168 | function laser = MinesLaser()
169 |
170 | laser.scan_size = 682;
171 | laser.scan_rate_hz = 10;
172 | laser.detection_angle_degrees = 240;
173 | laser.distance_no_detection_mm = 4000;
174 | laser.detection_margin = 70;
175 | laser.offset_mm = 145;
176 |
--------------------------------------------------------------------------------
/matlab/CoreSLAM.m:
--------------------------------------------------------------------------------
1 | classdef CoreSLAM
2 | %CoreSLAM CoreSLAM abstract class for BreezySLAM
3 | % CoreSLAM is an abstract class that uses the classes Position,
4 | % Map, Scan, and Laser to run variants of the simple CoreSLAM
5 | % (tinySLAM) algorithm described in
6 | %
7 | % @inproceedings{coreslam-2010,
8 | % author = {Bruno Steux and Oussama El Hamzaoui},
9 | % title = {CoreSLAM: a SLAM Algorithm in less than 200 lines of C code},
10 | % booktitle = {11th International Conference on Control, Automation,
11 | % Robotics and Vision, ICARCV 2010, Singapore, 7-10
12 | % December 2010, Proceedings},
13 | % pages = {1975-1979},
14 | % publisher = {IEEE},
15 | % year = {2010}
16 | % }
17 | %
18 | %
19 | % Implementing classes should provide the method
20 | %
21 | % updateMapAndPointcloud(scan_mm, velocities)
22 | %
23 | % to update the map and point-cloud (particle cloud).
24 | %
25 | % Copyright (C) 2014 Simon D. Levy
26 | %
27 | % This code is free software: you can redistribute it and/or modify
28 | % it under the terms of the GNU Lesser General Public License as
29 | % published by the Free Software Foundation, either version 3 of the
30 | % License, or (at your option) any later version.
31 | %
32 | % This code is distributed in the hope that it will be useful,
33 | % but WITHOUT ANY WARRANTY without even the implied warranty of
34 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 | % GNU General Public License for more details.
36 | %
37 | % You should have received a copy of the GNU Lesser General Public License
38 | % along with this code. If not, see .
39 |
40 | properties (Access = 'public')
41 | map_quality = 50; % The quality of the map (0 through 255); default = 50
42 | hole_width_mm = 600; % The width in millimeters of each "hole" in the map (essentially, wall width); default = 600
43 | end
44 |
45 | properties (Access = 'protected')
46 | laser % (internal)
47 | scan_for_distance % (internal)
48 | scan_for_mapbuild % (internal)
49 | map % (internal)
50 | velocities % (internal)
51 | end
52 |
53 | methods (Abstract, Access = 'protected')
54 |
55 | updateMapAndPointcloud(slam, velocities)
56 |
57 | end
58 |
59 | methods (Access = 'private')
60 |
61 | function scan_update(slam, scanobj, scans_mm)
62 | scanobj.update(scans_mm, slam.hole_width_mm, slam.velocities)
63 | end
64 |
65 | end
66 |
67 | methods (Access = 'protected')
68 |
69 | function slam = CoreSLAM(laser, map_size_pixels, map_size_meters)
70 | % Creates a CoreSLAM object suitable for updating with new Lidar and odometry data.
71 | % CoreSLAM(laser, map_size_pixels, map_size_meters)
72 | % laser is a Laser object representing the specifications of your Lidar unit
73 | % map_size_pixels is the size of the square map in pixels
74 | % map_size_meters is the size of the square map in meters
75 |
76 | % Store laser for later
77 | slam.laser = laser;
78 |
79 | % Initialize velocities (dxyMillimeters, dthetaDegrees, dtSeconds) for odometry
80 | slam.velocities = [0, 0, 0];
81 |
82 | % Initialize a scan for computing distance to map, and one for updating map
83 | slam.scan_for_distance = Scan(laser, 1);
84 | slam.scan_for_mapbuild = Scan(laser, 3);
85 |
86 | % Initialize the map
87 | slam.map = Map(map_size_pixels, map_size_meters);
88 |
89 | end
90 | end
91 |
92 | methods (Access = 'public')
93 |
94 | function slam = update(slam, scans_mm, velocities)
95 | % Updates the scan and odometry.
96 | % Calls the the implementing class's updateMapAndPointcloud()
97 | % method with the specified velocities.
98 | %
99 | % slam = update(slam, scans_mm, [velocities])
100 | %
101 | % scan_mm is a list of Lidar scan values, whose count is specified in the scan_size
102 | % velocities is an optional list of velocities [dxy_mm, dtheta_degrees, dt_seconds] for odometry
103 |
104 | % Build a scan for computing distance to map, and one for updating map
105 | slam.scan_update(slam.scan_for_mapbuild, scans_mm)
106 | slam.scan_update(slam.scan_for_distance, scans_mm)
107 |
108 | % Default to zero velocities
109 | if nargin < 3
110 | velocities = [0, 0, 0];
111 | end
112 |
113 | % Update velocities
114 | velocity_factor = 0;
115 | if velocities(3) > 0
116 | velocity_factor = 1 / velocities(3);
117 | end
118 | new_dxy_mm = velocities(1) * velocity_factor;
119 | new_dtheta_degrees = velocities(2) * velocity_factor;
120 | slam.velocities = [new_dxy_mm, new_dtheta_degrees, 0];
121 |
122 | % Implementing class updates map and pointcloud
123 | slam = slam.updateMapAndPointcloud(velocities);
124 |
125 | end
126 |
127 | function map = getmap(slam)
128 | % Returns the current map.
129 | % Map is returned as an occupancy grid (matrix of pixels).
130 | map = slam.map.get();
131 | end
132 |
133 | end
134 |
135 | end
136 |
137 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | GNU LESSER 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 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------