Skip to content

Commit

Permalink
First version of autonomous map making strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Theophil committed Sep 30, 2015
1 parent 43a9c0e commit 7775714
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 37 deletions.
6 changes: 6 additions & 0 deletions robotcontrol2.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
9EB81AB51BB69F0300CF417F /* libopencv_core.3.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EB81AB41BB69F0300CF417F /* libopencv_core.3.0.0.dylib */; };
9ED482951BB962F8001A3968 /* libopencv_imgproc.3.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ED482941BB962F8001A3968 /* libopencv_imgproc.3.0.0.dylib */; };
9ED9A9811BB094A700843215 /* robot_controller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9ED9A9801BB094A700843215 /* robot_controller.cpp */; settings = {ASSET_TAGS = (); }; };
9EE74C871BBB21D100274281 /* edge_following_strategy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9EE74C851BBB21D100274281 /* edge_following_strategy.cpp */; settings = {ASSET_TAGS = (); }; };
9EF738C21BB4849700E06378 /* occupancy_grid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9EF738C11BB4849700E06378 /* occupancy_grid.cpp */; settings = {ASSET_TAGS = (); }; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -50,6 +51,8 @@
9ED482941BB962F8001A3968 /* libopencv_imgproc.3.0.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libopencv_imgproc.3.0.0.dylib; path = ../../../../usr/local/Cellar/opencv3/3.0.0/lib/libopencv_imgproc.3.0.0.dylib; sourceTree = "<group>"; };
9ED9A97F1BAF477F00843215 /* robot_controller_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = robot_controller_c.h; sourceTree = "<group>"; };
9ED9A9801BB094A700843215 /* robot_controller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = robot_controller.cpp; sourceTree = "<group>"; };
9EE74C851BBB21D100274281 /* edge_following_strategy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = edge_following_strategy.cpp; sourceTree = "<group>"; };
9EE74C861BBB21D100274281 /* edge_following_strategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = edge_following_strategy.h; sourceTree = "<group>"; };
9EF738BC1BB471C400E06378 /* geometry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = geometry.h; sourceTree = "<group>"; };
9EF738BD1BB472CD00E06378 /* nonmoveable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nonmoveable.h; sourceTree = "<group>"; };
9EF738BF1BB47A1900E06378 /* math.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = math.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -104,6 +107,8 @@
9ED9A9801BB094A700843215 /* robot_controller.cpp */,
9EF738C01BB4824700E06378 /* occupancy_grid.h */,
9EF738C11BB4849700E06378 /* occupancy_grid.cpp */,
9EE74C861BBB21D100274281 /* edge_following_strategy.h */,
9EE74C851BBB21D100274281 /* edge_following_strategy.cpp */,
9EF738BF1BB47A1900E06378 /* math.h */,
9EF738BD1BB472CD00E06378 /* nonmoveable.h */,
9EF738BC1BB471C400E06378 /* geometry.h */,
Expand Down Expand Up @@ -248,6 +253,7 @@
9E39FBC21A20D163002D6835 /* QuartzView.swift in Sources */,
9E39FBA51A20CB82002D6835 /* RobotViewController.swift in Sources */,
9ED9A9811BB094A700843215 /* robot_controller.cpp in Sources */,
9EE74C871BBB21D100274281 /* edge_following_strategy.cpp in Sources */,
9EF738C21BB4849700E06378 /* occupancy_grid.cpp in Sources */,
9E39FBA31A20CB82002D6835 /* AppDelegate.swift in Sources */,
9E1529951A28E49800FE55D3 /* BLE.swift in Sources */,
Expand Down
24 changes: 16 additions & 8 deletions robotcontrol2/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -682,13 +682,10 @@
<customView translatesAutoresizingMaskIntoConstraints="NO" id="HTx-LB-1Eb" customClass="QuartzView" customModule="robotcontrol2" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="324" height="207"/>
</customView>
<matrix verticalHuggingPriority="750" allowsEmptySelection="NO" autorecalculatesCellSize="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AI7-bg-1Dn">
<rect key="frame" x="332" y="147" width="148" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Bec-81-Y2L"/>
</constraints>
<matrix verticalHuggingPriority="750" misplaced="YES" allowsEmptySelection="NO" autorecalculatesCellSize="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AI7-bg-1Dn">
<rect key="frame" x="332" y="97" width="148" height="90"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
<size key="cellSize" width="101" height="18"/>
<size key="cellSize" width="148" height="21"/>
<size key="intercellSpacing" width="4" height="2"/>
<buttonCell key="prototype" type="radio" title="Radio" imagePosition="left" alignment="left" inset="2" id="FwA-bQ-lN0">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
Expand All @@ -704,8 +701,19 @@
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<buttonCell type="radio" title="Edge Map" imagePosition="left" alignment="left" tag="2" inset="2" id="XHF-9y-ETR">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<buttonCell type="radio" title="Features" imagePosition="left" alignment="left" tag="3" inset="2" id="1YW-ux-SoX">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</column>
</cells>
<connections>
<action selector="onMapSelection:" target="XfG-lQ-9wD" id="eIV-5q-uCa"/>
</connections>
</matrix>
</subviews>
<constraints>
Expand All @@ -725,11 +733,11 @@
<scrollView horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kN3-Ou-Ld7">
<rect key="frame" x="0.0" y="0.0" width="500" height="216"/>
<clipView key="contentView" id="ClZ-6h-1D2">
<rect key="frame" x="1" y="1" width="223" height="133"/>
<rect key="frame" x="1" y="1" width="498" height="214"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView editable="NO" importsGraphics="NO" richText="NO" findStyle="panel" verticallyResizable="YES" id="qav-DC-KA4">
<rect key="frame" x="0.0" y="0.0" width="223" height="214"/>
<rect key="frame" x="0.0" y="0.0" width="498" height="214"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="498" height="214"/>
Expand Down
14 changes: 9 additions & 5 deletions robotcontrol2/RobotViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,17 +109,17 @@ class RobotViewController: NSViewController {

func draw() {
let btnSelected = radiobtnShowMap.selectedCell() as! NSButtonCell
let bShowErodedMap = btnSelected.tag == 1
var bitmap = robot_get_map(m_robotcontroller, bShowErodedMap)
let type = bitmap_type(UInt32(btnSelected.tag))

var bitmap = robot_get_map(m_robotcontroller, type)
if let bitmaprep = NSBitmapImageRep(bitmapDataPlanes: &bitmap.m_pbImage,
pixelsWide: bitmap.m_nWidth,
pixelsHigh: bitmap.m_nHeight,
bitsPerSample: 8,
samplesPerPixel: 1,
samplesPerPixel: bitmap.m_cChannels,
hasAlpha: false,
isPlanar: false,
colorSpaceName: NSDeviceWhiteColorSpace,
colorSpaceName: (bitmap.m_cChannels==3 ? NSDeviceRGBColorSpace : NSDeviceWhiteColorSpace),
bytesPerRow: bitmap.m_cbBytesPerRow,
bitsPerPixel: 0) {

Expand Down Expand Up @@ -151,6 +151,10 @@ class RobotViewController: NSViewController {
// textview.scrollRangeToVisible(NSMakeRange(textview.string!.lengthOfBytesUsingEncoding(NSUTF8StringEncoding), 0))
}

@IBAction func onMapSelection(sender: AnyObject) {
viewRender.needsDisplay = true
}

var m_robotcontroller : COpaquePointer = nil
var m_apairptf = [(CGPoint, CGFloat)]()
var m_bezierpath = NSBezierPath()
Expand Down
37 changes: 37 additions & 0 deletions robotcontrol2/edge_following_strategy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// edge_following_strategy.cpp
// robotcontrol2
//
// Created by Sebastian Theophil on 29.09.15.
// Copyright © 2015 Sebastian Theophil. All rights reserved.
//

#include "edge_following_strategy.h"
#include <opencv2/imgproc.hpp>

namespace rbt {
void CEdgeFollowingStrategy::update(point<double> const& ptf, double fYaw, COccupancyGrid const& occgrid) {
// Threshold first, converting image to black & white. Decision to drive to a position is essentially binary.
// Either we can drive someplace or we can't.
cv::threshold(occgrid.ErodedMap(), m_matnMapEdges, /* pixels >= */ 255*0.4, /* are set to */ 255, cv::THRESH_BINARY);

// Recognize edges in eroded map.
// Threshold factors determined empirically to work well with greyscale image.
// They don't matter with thresholded binary image
cv::Canny(m_matnMapEdges, m_matnMapEdges, 100, 300);

// Turn edges into lines. The robot must follow these lines to scan the walls.
std::vector<cv::Vec4i> vecline;
cv::HoughLinesP(m_matnMapEdges,
vecline,
1, // resolution of r in px
CV_PI/180, // resolution of rho in rad
15); // min number of votes for a line, 15-20 seems to work ok

// Draw recognized features for debugging
cvtColor(occgrid.GreyscaleMap(), m_matrgbMapFeatures, CV_GRAY2RGB);
boost::for_each(vecline, [&](cv::Vec4i const& line) {
cv::line(m_matrgbMapFeatures, cv::Point(line[0], line[1]), cv::Point(line[2], line[3]), cv::Scalar(0,0,255), /*thickness*/ 1);
});
}
}
29 changes: 29 additions & 0 deletions robotcontrol2/edge_following_strategy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// edge_following_strategy.hpp
// robotcontrol2
//
// Created by Sebastian Theophil on 29.09.15.
// Copyright © 2015 Sebastian Theophil. All rights reserved.
//

#ifndef edge_following_strategy_hpp
#define edge_following_strategy_hpp

#include "occupancy_grid.h"

namespace rbt {
struct CEdgeFollowingStrategy {
CEdgeFollowingStrategy() {}
void update(point<double> const& ptf, double fYaw, COccupancyGrid const& occgrid);

cv::Mat const& EdgeMap() constreturn m_matnMapEdges; }
cv::Mat const& FeatureRGBMap() constreturn m_matrgbMapFeatures; }

private:
cv::Mat m_matnMapEdges;
#ifndef NDEBUG
cv::Mat m_matrgbMapFeatures;
#endif
};
}
#endif /* edge_following_strategy_hpp */
17 changes: 4 additions & 13 deletions robotcontrol2/occupancy_grid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ namespace rbt {

template<class Func>
void for_each_pixel(Func foreach) const {
// TODO: Approximate arc with lines, use cv::LineIterator instead
auto szFrom = rbt::size<int>::fromAngleAndDistance(m_fAngleFrom, m_fRadius);
auto szTo = rbt::size<int>::fromAngleAndDistance(m_fAngleTo, m_fRadius);

assert(angularDistance(m_fAngleFrom, m_fAngleTo)<M_PI/2);
assert(szFrom.compare(szTo) != 0);
// This can happen because szFrom and szTo are already cast to int coordinates:
// assert(szFrom.compare(szTo) != 0);

if(szFrom.compare(szTo) < 0) { // ptFrom should be left of ptTo
std::swap(szFrom, szTo);
Expand Down Expand Up @@ -105,6 +107,7 @@ namespace rbt {
// Rotate the scaled rectangle.
// TODO: For numerical precision, it may be better to rotate the rect
// in world coordinates and then scale.
// TODO: Use cv::LineIterator instead
rbt::point<int> apt[] = {
m_ptnCenter - rbt::size<int>((m_szf/2).rotated(m_fAngle)),
m_ptnCenter + rbt::size<int>((rbt::size<double>(m_szf.x, -m_szf.y)/2).rotated(m_fAngle)),
Expand Down Expand Up @@ -212,18 +215,6 @@ namespace rbt {
cv::erode(m_matnMapGreyscale, m_matnMapEroded, s_matnKernel);
}

struct SBitmap COccupancyGrid::bitmap(bool bEroded) const {
auto const& matnMap = bEroded ? m_matnMapEroded : m_matnMapGreyscale;
SBitmap bitmap;
bitmap.m_pbImage = matnMap.data;
bitmap.m_cbBytesPerRow = m_szn.x;

bitmap.m_nWidth = m_szn.x;
bitmap.m_nHeight = m_szn.y;
bitmap.m_nScale = m_nScale;
return bitmap;
}

point<int> COccupancyGrid::toGridCoordinates(point<double> const& pt) const {
return point<int>(pt/m_nScale) + m_szn/2;
}
Expand Down
11 changes: 6 additions & 5 deletions robotcontrol2/occupancy_grid.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ namespace rbt {

point<int> toGridCoordinates(point<double> const& pt) const;
point<int> toWorldCoordinates(point<int> const& pt) const;

struct SBitmap bitmap(bool bEroded) const;

private:
rbt::size<int> m_szn;
int m_nScale; // cm per pixel
cv::Mat const& GreyscaleMap() const { return m_matnMapGreyscale; }
cv::Mat const& ErodedMap() const { return m_matnMapEroded; }

rbt::size<int> const m_szn;
int const m_nScale; // cm per pixel

private:
cv::Mat m_matfMapLogOdds;
cv::Mat m_matnMapGreyscale;
cv::Mat m_matnMapEroded;
Expand Down
29 changes: 24 additions & 5 deletions robotcontrol2/robot_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
#include "geometry.h"
#include "nonmoveable.h"
#include "occupancy_grid.h"
#include "edge_following_strategy.h"

#include <vector>

namespace rbt {
struct CRobotController : rbt::nonmoveable {
CRobotController()
: m_occgrid(rbt::size<int>(400, 400), /*nScale*/5) {} // = Map of 20m x 20m map
: m_occgrid(rbt::size<int>(400, 400), /*nScale*/5) // = Map of 20m x 20m map
{}

void receivedSensorData(SSensorData const& data) {
// TODO: Fuse odometry and IMU sensors?
auto const fYaw = yawToRadians(data.m_nYaw);
auto const fYaw = yawToRadians(data.m_nYaw); // TODO: Fuse odometry and IMU sensors?

auto const ptfPrev = m_vecpairptfPose.empty() ? rbt::point<double>::zero() : m_vecpairptfPose.back().first;
rbt::point<double> ptf;
Expand All @@ -27,9 +28,11 @@ namespace rbt {

m_vecpairptfPose.emplace_back(std::make_pair(ptf, fYaw));
m_occgrid.update(ptf, fYaw, data.m_nAngle, data.m_nDistance + sonarOffset(data.m_nAngle)); // TODO: Add sonarOffset to position instead?
m_edgefollow.update(ptf, fYaw, m_occgrid);
}

rbt::COccupancyGrid m_occgrid;
rbt::CEdgeFollowingStrategy m_edgefollow;
std::vector<std::pair<rbt::point<double>, double>> m_vecpairptfPose;
};
}
Expand All @@ -46,7 +49,23 @@ struct SPose robot_received_sensor_data(struct CRobotController* probot, struct
return { pairptfPose.first.x, pairptfPose.first.y, pairptfPose.second };
}

struct SBitmap robot_get_map(struct CRobotController* probot, bool bEroded) {
struct SBitmap robot_get_map(struct CRobotController* probot, bitmap_type bm) {
auto const& robotcontroller = *reinterpret_cast<rbt::CRobotController*>(probot);
return robotcontroller.m_occgrid.bitmap(bEroded);

SBitmap bitmap;
bitmap.m_pbImage = [&]() {
switch(bm) {
case bitmap_type::greyscale: return robotcontroller.m_occgrid.GreyscaleMap().data;
case bitmap_type::eroded: return robotcontroller.m_occgrid.ErodedMap().data;
case bitmap_type::edges: return robotcontroller.m_edgefollow.EdgeMap().data;
case bitmap_type::features: return robotcontroller.m_edgefollow.FeatureRGBMap().data;
}
}();

bitmap.m_cChannels = (bm==bitmap_type::features ? 3 : 1);
bitmap.m_cbBytesPerRow = robotcontroller.m_occgrid.m_szn.x * bitmap.m_cChannels * sizeof(std::uint8_t);
bitmap.m_nWidth = robotcontroller.m_occgrid.m_szn.x;
bitmap.m_nHeight = robotcontroller.m_occgrid.m_szn.y;
bitmap.m_nScale = robotcontroller.m_occgrid.m_nScale;
return bitmap;
}
8 changes: 7 additions & 1 deletion robotcontrol2/robot_controller_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@ struct SPose robot_received_sensor_data(struct CRobotController* probot, struct
// or the map with erosion filter applied (bEroded = true)
struct SBitmap {
unsigned char* m_pbImage;
size_t m_cChannels; // No of 8-bit channels, 1 (Greyscale) or 3 (RGB)
size_t m_cbBytesPerRow;
size_t m_nWidth;
size_t m_nHeight;
size_t m_nScale; // cm per pixel
};
struct SBitmap robot_get_map(struct CRobotController* probot, bool bEroded);

enum bitmap_type {
greyscale, eroded, edges, features
};

struct SBitmap robot_get_map(struct CRobotController* probot, enum bitmap_type bm);

#ifdef __cplusplus
}
Expand Down

0 comments on commit 7775714

Please sign in to comment.