<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
{font-family:Helvetica;
panose-1:2 11 5 4 2 2 2 2 2 4;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
{font-family:"Segoe UI Emoji";
panose-1:2 11 5 2 4 2 4 2 2 3;}
@font-face
{font-family:Consolas;
panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
code
{mso-style-priority:99;
font-family:"Courier New";}
pre
{mso-style-priority:99;
mso-style-link:"HTML Preformatted Char";
margin:0in;
margin-bottom:.0001pt;
font-size:10.0pt;
font-family:"Courier New";}
p.gmail-m-1259438599545823872msolistparagraph, li.gmail-m-1259438599545823872msolistparagraph, div.gmail-m-1259438599545823872msolistparagraph
{mso-style-name:gmail-m_-1259438599545823872msolistparagraph;
mso-margin-top-alt:auto;
margin-right:0in;
mso-margin-bottom-alt:auto;
margin-left:0in;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
span.HTMLPreformattedChar
{mso-style-name:"HTML Preformatted Char";
mso-style-priority:99;
mso-style-link:"HTML Preformatted";
font-family:"Courier New";}
.MsoChpDefault
{mso-style-type:export-only;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
/* List Definitions */
@list l0
{mso-list-id:516117929;
mso-list-template-ids:-1;}
@list l0:level1
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level2
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:1.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level3
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:1.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level4
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:2.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level5
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:2.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level6
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:3.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level7
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:3.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level8
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:4.0in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l0:level9
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:4.5in;
mso-level-number-position:left;
text-indent:-.25in;}
@list l1
{mso-list-id:2106261844;
mso-list-template-ids:-1;}
@list l1:level2
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:1.0in;
mso-level-number-position:left;
text-indent:-.25in;}
ol
{margin-bottom:0in;}
ul
{margin-bottom:0in;}
--></style></head><body lang=EN-US link=blue vlink="#954F72" style='word-wrap:break-word'><div class=WordSection1><p class=MsoNormal>Cyrill Stachniss has a number of 5-minute video “lectures” on different topics, including one on occupancy grid maps. <a href="https://youtu.be/8ckhPViqneg">https://youtu.be/8ckhPViqneg</a></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>With a bit of searching, I’m sure you’ll find enough bits and pieces of python code that illustrate how to do generate a grid map, given the robot’s pose and the laser scan as inputs.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>If your odometry is very good, this will probably produce decent results. Big if…..</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>In practice, odometry will be less than perfect, and that’s why many of the “name-brand” mapping solutions (gmapping, hector mapping, google cartographer, etc.) employ localization, i.e. they are doing SLAM. This essentially allows them to deal with odometry drift (and some will even work w/ out any wheel odometry). </p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>My point is this: putting something together for scratch or semi-from-scratch that illustrates the principle of occupancy grid mapping is probably not that hard, and surely satisfying, but making it work well is probably more effort than figuring out how to use / integrate an existing solution.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>“existing solution” doesn’t need to imply ROS – most of the algorithms that are available in “ROS format”, also exist as standalone implementations somewhere……</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Chris.</p><p class=MsoNormal><o:p> </o:p></p><div style='mso-element:para-border-div;border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in'><p class=MsoNormal style='border:none;padding:0in'><b>From: </b><a href="mailto:tnkumar@gmail.com">Thalanayar Muthukumar</a><br><b>Sent: </b>Sunday, November 21, 2021 2:17 PM<br><b>To: </b><a href="mailto:netterchris@gmail.com">Chris N</a><br><b>Cc: </b><a href="mailto:dprglist@lists.dprg.org">DPRG</a><br><b>Subject: </b>Re: [Dprglist] Need help with getting a map of the house usingRPLidarwith RPi</p></div><p class=MsoNormal><o:p> </o:p></p><div><p class=MsoNormal>Thanks Chris for sharing your experiences.<br><a href="https://www.youtube.com/watch?v=qT5PWlmwydc">https://www.youtube.com/watch?v=qT5PWlmwydc</a> (~30 secs) - RPLidar mounted on my robot <br>It is ready to move around the house<br><br><span style='font-size:12.0pt'>"you need to take the robot’s actual current pose (x, y, theta) into account" - need to figure out how to do this</span></p></div><p class=MsoNormal><o:p> </o:p></p><div><div><p class=MsoNormal>On Sun, Nov 21, 2021 at 12:52 PM Chris N <<a href="mailto:netterchris@gmail.com">netterchris@gmail.com</a>> wrote:</p></div><blockquote style='border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in'><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>Kumar,</span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>What you are looking for is called an “occupancy grid map”. There are other types of maps, but the occupancy grid map is conceptually the easiest one to understand and work with I believe.</span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>Conceptually, its straight forward how it is created. This type of map is really no different from an image – every pixel corresponds to, for example, one square inch of space, and the pixel values correspond to definitely empty (black), definitely something there (white), unsure (grey). </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>In a way, it is just an extension of the real-time display code that you have running. The key differences between real-time display of lidar data and using this data to build a map are:</span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><ol start=1 type=a><li class=gmail-m-1259438599545823872msolistparagraph style='mso-list:l0 level1 lfo1'><span style='font-size:12.0pt'>For map making, you need to take the robot’s actual current pose (x, y, theta) into account. (For real-time display, you essentially pretend your robot is always at x,y=0,0 and orientation= 0 degrees)</span></li><li class=gmail-m-1259438599545823872msolistparagraph style='mso-list:l0 level1 lfo1'><span style='font-size:12.0pt'>For map making, you remember the point that is drawn into the map, instead of starting with a clean canvas every cycle</span></li><li class=gmail-m-1259438599545823872msolistparagraph style='mso-list:l0 level1 lfo1'><span style='font-size:12.0pt'>For map making, the size of your map needs to be larger than the range of your Lidar, otherwise it won’t be of much use. </span></li></ol><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>You have 3 options:</span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><ol start=1 type=1><li class=gmail-m-1259438599545823872msolistparagraph style='margin-bottom:12.0pt;mso-list:l1 level1 lfo2'><span style='font-size:12.0pt'>Create the algorithm more or less completely from scratch or adapt some sample code that seems to be easy enough to work with. I’m sure such sample code for python and C++ is out there…. Quick google search found this python code for example: </span><a href="https://gist.github.com/superjax/33151f018407244cb61402e094099c1d" target="_blank">An occupancy grid mapping example · GitHub</a>. It says “# This is an implementation of Occupancy Grid Mapping as Presented in Chapter 9 of "Probabilistic Robotics" By Sebastian Thrun et al. In particular, this is an implementation of Table 9.1 and 9.2”</li><li class=gmail-m-1259438599545823872msolistparagraph style='margin-bottom:12.0pt;mso-list:l1 level1 lfo2'><span style='font-size:12.0pt'>Find a library that contains the necessary building blocks. Maybe all you need is a ready to use grid map data structure along with an API for putting things into that grid map. Or maybe the library also provides functions that take care of all the processing of the laser scan data. Etc, etc. Then figure out how to use this library. MRPT comes to mind but there are probably others. </span><a href="https://www.mrpt.org/" target="_blank">MRPT – Empowering C++ development in robotics</a>. <a href="https://openslam-org.github.io/" target="_blank">OpenSLAM.org (openslam-org.github.io)</a> is also a possible resource.</li><li class=gmail-m-1259438599545823872msolistparagraph style='mso-list:l1 level1 lfo2'><span style='font-size:12.0pt'>Use ROS and pick one of the mapping algorithms that are available, such as</span></li></ol><ol start=3 type=1><ol start=1 type=a><li class=gmail-m-1259438599545823872msolistparagraph style='mso-list:l1 level2 lfo2'><span style='font-size:12.0pt'>Gmapping</span></li><li class=gmail-m-1259438599545823872msolistparagraph style='mso-list:l1 level2 lfo2'><span style='font-size:12.0pt'>Google cartographer</span></li><li class=gmail-m-1259438599545823872msolistparagraph style='mso-list:l1 level2 lfo2'><span style='font-size:12.0pt'>etc</span></li></ol></ol><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>I have gone down road # 1 and road # 2 some 5+ years ago, but I did not reach my destination </span><span style='font-size:12.0pt;font-family:"Segoe UI Emoji",sans-serif'>☹</span><span style='font-size:12.0pt'> I probably didn’t try hard enough…..</span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>I have also started going down road #3 on more than one occasion, but find my self often going in circles and not getting anywhere </span><span style='font-size:12.0pt;font-family:"Segoe UI Emoji",sans-serif'>☹</span><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>I find that no matter which road you take, it requires a substantial time commitment to fully master the underlying technologies. I find that unless I’m at it every day, I start to forget things I’ve learned….</span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'>Chris.</span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt'> </span></p><div style='border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in'><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><b>From: </b><a href="mailto:dprglist@lists.dprg.org" target="_blank">Thalanayar Muthukumar via DPRGlist</a><br><b>Sent: </b>Sunday, November 21, 2021 12:36 PM<br><b>To: </b><a href="mailto:dprglist@lists.dprg.org" target="_blank">DPRG</a><br><b>Subject: </b>[Dprglist] Need help with getting a map of the house using RPLidarwith RPi</p></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> </p><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><a href="https://learn.adafruit.com/slamtec-rplidar-on-pi/cpython-on-raspberry-pi" target="_blank" title="https://learn.adafruit.com/slamtec-rplidar-on-pi/cpython-on-raspberry-pi"><span style='font-size:12.0pt;font-family:"Helvetica",sans-serif;border:none windowtext 1.0pt;padding:0in'>https://learn.adafruit.com/slamtec-rplidar-on-pi/cpython-on-raspberry-pi</span></a><span style='font-size:12.0pt;font-family:"Helvetica",sans-serif;color:#DCDDDE'> -<span style='background:white'> </span></span><span style='font-size:12.0pt;font-family:"Helvetica",sans-serif;color:black;background:white'>The relevant code is below </span></p><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'>def process_data(data):</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> global max_distance</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> lcd.fill((0,0,0))</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> for angle in range(360):</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> distance = data[angle]</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> if distance > 0: # ignore initially ungathered data points</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> max_distance = max([min([5000, distance]), max_distance])</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> radians = angle * pi / 180.0</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> x = distance * cos(radians)</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> y = distance * sin(radians)</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> point = (160 + int(x / max_distance * 119), 120 + int(y / max_distance * 119))</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> lcd.set_at(point, pygame.Color(255, 255, 255))</span></code></pre><pre style='vertical-align:baseline'><code><span style='font-family:Consolas;color:black;background:white'> pygame.display.update()</span></code></pre></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'><span style='font-size:12.0pt;font-family:"Helvetica",sans-serif;color:black;background:white'>This code is used to update the TFT display and is working for me. Instantaneously, the RPLidar's surroundings are displayed on the TFT display. I would like to adapt this to move the RPLidar through the rooms of the house to create a map. @Chris - Any suggestions or pointers? I do not have ROS installed. Regards. - Kumar </span></p></div></div></blockquote></div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;margin-left:4.8pt'> </p><p class=MsoNormal><o:p> </o:p></p></div></body></html>