From 639f99691b6246c40e44d4b11d47e6a2175321d8 Mon Sep 17 00:00:00 2001 From: Jon Trulson Date: Thu, 15 Oct 2015 11:03:40 -0700 Subject: [PATCH] urm37: Initial implementation This driver was tested with the DFRobot URM37 Ultrasonic Ranger, V4. Both UART and analog access modes are supported. Signed-off-by: Jon Trulson Signed-off-by: Abhishek Malik --- examples/c++/CMakeLists.txt | 5 + examples/c++/urm37-uart.cxx | 66 +++++++ examples/c++/urm37.cxx | 65 ++++++ examples/javascript/urm37-uart.js | 52 +++++ examples/javascript/urm37.js | 52 +++++ examples/python/urm37-uart.py | 50 +++++ examples/python/urm37.py | 50 +++++ src/urm37/CMakeLists.txt | 5 + src/urm37/javaupm_urm37.i | 10 + src/urm37/jsupm_urm37.i | 10 + src/urm37/pyupm_urm37.i | 11 ++ src/urm37/urm37.cxx | 318 ++++++++++++++++++++++++++++++ src/urm37/urm37.h | 204 +++++++++++++++++++ 13 files changed, 898 insertions(+) create mode 100644 examples/c++/urm37-uart.cxx create mode 100644 examples/c++/urm37.cxx create mode 100644 examples/javascript/urm37-uart.js create mode 100644 examples/javascript/urm37.js create mode 100644 examples/python/urm37-uart.py create mode 100644 examples/python/urm37.py create mode 100644 src/urm37/CMakeLists.txt create mode 100644 src/urm37/javaupm_urm37.i create mode 100644 src/urm37/jsupm_urm37.i create mode 100644 src/urm37/pyupm_urm37.i create mode 100644 src/urm37/urm37.cxx create mode 100644 src/urm37/urm37.h diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index eb377d82..522a8964 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -148,6 +148,8 @@ add_executable (grovegprs-example grovegprs.cxx) add_executable (lm35-example lm35.cxx) add_executable (micsv89-example micsv89.cxx) add_executable (xbee-example xbee.cxx) +add_executable (urm37-example urm37.cxx) +add_executable (urm37-uart-example urm37-uart.cxx) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/grove) @@ -261,6 +263,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/grovegprs) include_directories (${PROJECT_SOURCE_DIR}/src/lm35) include_directories (${PROJECT_SOURCE_DIR}/src/micsv89) include_directories (${PROJECT_SOURCE_DIR}/src/xbee) +include_directories (${PROJECT_SOURCE_DIR}/src/urm37) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) @@ -410,3 +413,5 @@ target_link_libraries (grovegprs-example grovegprs ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (lm35-example lm35 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (micsv89-example micsv89 ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (xbee-example xbee ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (urm37-example urm37 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (urm37-uart-example urm37 ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/c++/urm37-uart.cxx b/examples/c++/urm37-uart.cxx new file mode 100644 index 00000000..7a94a1ff --- /dev/null +++ b/examples/c++/urm37-uart.cxx @@ -0,0 +1,66 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "urm37.h" + +using namespace std; + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main() +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + + // Instantiate a URM37 sensor on UART 0, with the reset pin on D2 + upm::URM37 *sensor = new upm::URM37(0, 2); + + // Every half a second, sample the URM37 and output the measured + // distance in cm, and temperature in degrees C + + while (shouldRun) + { + cout << "Detected distance (cm): " << sensor->getDistance() << endl; + cout << "Temperature (C): " << sensor->getTemperature() << endl; + + usleep(500000); + } + +//! [Interesting] + + cout << "Exiting" << endl; + + delete sensor; + return 0; +} diff --git a/examples/c++/urm37.cxx b/examples/c++/urm37.cxx new file mode 100644 index 00000000..820b2a18 --- /dev/null +++ b/examples/c++/urm37.cxx @@ -0,0 +1,65 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "urm37.h" + +using namespace std; + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main() +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + + // Instantiate a URM37 sensor on analog pin A0, reset pin on D2, + // trigger pin on D3 with an analog reference voltage of 5.0 + upm::URM37 *sensor = new upm::URM37(0, 2, 3, 5.0); + + // Every half a second, sample the URM37 and output the measured + // distance in cm. + + while (shouldRun) + { + cout << "Detected distance (cm): " << sensor->getDistance() << endl; + usleep(500000); + } + +//! [Interesting] + + cout << "Exiting" << endl; + + delete sensor; + return 0; +} diff --git a/examples/javascript/urm37-uart.js b/examples/javascript/urm37-uart.js new file mode 100644 index 00000000..ee81cc5f --- /dev/null +++ b/examples/javascript/urm37-uart.js @@ -0,0 +1,52 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ + +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +var sensorObj = require('jsupm_urm37'); + +// Instantiate a URM37 sensor on UART 0, with the reset pin on D2 +var sensor = new sensorObj.URM37(0, 2); + +// Every half a second, sample the URM37 and output the measured +// distance in cm, and temperature in degrees C + +setInterval(function() +{ + console.log("Detected distance (cm): " + sensor.getDistance()); + console.log("Temperature (C): " + sensor.getTemperature()); +}, 500); + +// exit on ^C +process.on('SIGINT', function() +{ + sensor = null; + sensorObj.cleanUp(); + sensorObj = null; + console.log("Exiting."); + process.exit(0); +}); + diff --git a/examples/javascript/urm37.js b/examples/javascript/urm37.js new file mode 100644 index 00000000..17b1c162 --- /dev/null +++ b/examples/javascript/urm37.js @@ -0,0 +1,52 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ + +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +var sensorObj = require('jsupm_urm37'); + +// Instantiate a URM37 sensor on analog pin A0, reset pin on D2, +// trigger pin on D3 with an analog reference voltage of 5.0 +var sensor = new sensorObj.URM37(0, 2, 3, 5.0); + +// Every half a second, sample the URM37 and output the measured +// distance in cm. + +setInterval(function() +{ + console.log("Detected distance (cm): " + sensor.getDistance()); +}, 500); + +// exit on ^C +process.on('SIGINT', function() +{ + sensor = null; + sensorObj.cleanUp(); + sensorObj = null; + console.log("Exiting."); + process.exit(0); +}); + diff --git a/examples/python/urm37-uart.py b/examples/python/urm37-uart.py new file mode 100644 index 00000000..8e6ee80d --- /dev/null +++ b/examples/python/urm37-uart.py @@ -0,0 +1,50 @@ +#!/usr/bin/python +# Author: Jon Trulson +# Copyright (c) 2015 Intel Corporation. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import time, sys, signal, atexit +import pyupm_urm37 as sensorObj + +# Instantiate a URM37 sensor on UART 0, with the reset pin on D2 +sensor = sensorObj.URM37(0, 2) + +## Exit handlers ## +# This function stops python from printing a stacktrace when you hit control-C +def SIGINTHandler(signum, frame): + raise SystemExit + +# This function lets you run code on exit +def exitHandler(): + print "Exiting" + sys.exit(0) + +# Register exit handlers +atexit.register(exitHandler) +signal.signal(signal.SIGINT, SIGINTHandler) + +# Every half a second, sample the URM37 and output the measured +# distance in cm, and temperature in degrees C + +while (1): + print "Detected distance (cm):", sensor.getDistance() + print "Temperature (C):", sensor.getTemperature() + time.sleep(.5) diff --git a/examples/python/urm37.py b/examples/python/urm37.py new file mode 100644 index 00000000..fa977aa9 --- /dev/null +++ b/examples/python/urm37.py @@ -0,0 +1,50 @@ +#!/usr/bin/python +# Author: Jon Trulson +# Copyright (c) 2015 Intel Corporation. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import time, sys, signal, atexit +import pyupm_urm37 as sensorObj + +# Instantiate a URM37 sensor on analog pin A0, reset pin on D2, +# trigger pin on D3 with an analog reference voltage of 5.0 +sensor = sensorObj.URM37(0, 2, 3, 5.0) + +## Exit handlers ## +# This function stops python from printing a stacktrace when you hit control-C +def SIGINTHandler(signum, frame): + raise SystemExit + +# This function lets you run code on exit +def exitHandler(): + print "Exiting" + sys.exit(0) + +# Register exit handlers +atexit.register(exitHandler) +signal.signal(signal.SIGINT, SIGINTHandler) + +# Every half a second, sample the URM37 and output the measured +# distance in cm. + +while (1): + print "Detected distance (cm):", sensor.getDistance() + time.sleep(.5) diff --git a/src/urm37/CMakeLists.txt b/src/urm37/CMakeLists.txt new file mode 100644 index 00000000..91a490e6 --- /dev/null +++ b/src/urm37/CMakeLists.txt @@ -0,0 +1,5 @@ +set (libname "urm37") +set (libdescription "upm DFRobot URM37 Ultrasonic ranger") +set (module_src ${libname}.cxx) +set (module_h ${libname}.h) +upm_module_init() diff --git a/src/urm37/javaupm_urm37.i b/src/urm37/javaupm_urm37.i new file mode 100644 index 00000000..f355ce40 --- /dev/null +++ b/src/urm37/javaupm_urm37.i @@ -0,0 +1,10 @@ +%module javaupm_urm37 +%include "../upm.i" +%include "std_string.i" + +%{ + #include "urm37.h" +%} + +%include "urm37.h" + diff --git a/src/urm37/jsupm_urm37.i b/src/urm37/jsupm_urm37.i new file mode 100644 index 00000000..bc029464 --- /dev/null +++ b/src/urm37/jsupm_urm37.i @@ -0,0 +1,10 @@ +%module jsupm_urm37 +%include "../upm.i" +%include "std_string.i" + +%{ + #include "urm37.h" +%} + +%include "urm37.h" + diff --git a/src/urm37/pyupm_urm37.i b/src/urm37/pyupm_urm37.i new file mode 100644 index 00000000..ec27ff12 --- /dev/null +++ b/src/urm37/pyupm_urm37.i @@ -0,0 +1,11 @@ +%module pyupm_urm37 +%include "../upm.i" +%include "std_string.i" + +%feature("autodoc", "3"); + +%{ + #include "urm37.h" +%} +%include "urm37.h" + diff --git a/src/urm37/urm37.cxx b/src/urm37/urm37.cxx new file mode 100644 index 00000000..85305d31 --- /dev/null +++ b/src/urm37/urm37.cxx @@ -0,0 +1,318 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "urm37.h" + +using namespace upm; +using namespace std; + +static const int waitTimeout = 1000; +static const int maxRetries = 10; + +URM37::URM37(int aPin, int resetPin, int triggerPin, float aref) : + m_uart(0), m_aio(new mraa::Aio(aPin)), m_gpioReset(resetPin), + m_gpioTrigger(new mraa::Gpio(triggerPin)) +{ + m_analogMode = true; + + m_aRes = (1 << m_aio->getBit()); + m_aref = aref; + + m_gpioTrigger->dir(mraa::DIR_OUT); + + // setup trigger for mmapped access, not a big deal if this fails + m_gpioTrigger->useMmap(true); + + // trigger high + m_gpioTrigger->write(1); + + init(); +} + +URM37::URM37(int uart, int resetPin) : + m_uart(new mraa::Uart(uart)), m_aio(0), m_gpioReset(resetPin), + m_gpioTrigger(0) +{ + m_analogMode = false; + + m_aRes = 0; + m_aref = 0; + + // 9600 baud is the only support baud rate... + if (m_uart->setBaudRate(9600)) + { + throw std::runtime_error(string(__FUNCTION__) + + ": setBaudRate(9600) failed"); + return; + } + + init(); +} + +URM37::~URM37() +{ + if (m_uart) + delete m_uart; + if (m_aio) + delete m_aio; + if(m_gpioTrigger) + delete m_gpioTrigger; +} + +void URM37::init() +{ + m_gpioReset.dir(mraa::DIR_OUT); + + // reset the device + reset(); +} + +void URM37::reset() +{ + // toggle reset + m_gpioReset.write(0); + usleep(100); + m_gpioReset.write(1); + // wait for reset to complete + sleep(3); +} + +bool URM37::dataAvailable(unsigned int millis) +{ + return m_uart->dataAvailable(millis); +} + +std::string URM37::readDataStr(int len) +{ + return m_uart->readStr(len); +} + +int URM37::writeDataStr(std::string data) +{ + m_uart->flush(); + return m_uart->writeStr(data); +} + +float URM37::getDistance(int degrees) +{ + // analog mode + if (m_analogMode) + { + m_gpioTrigger->write(0); + int val = m_aio->read(); + m_gpioTrigger->write(1); + + float mVolts = (float(val) * (m_aref / m_aRes)) * 1000.0; + + // 6.8mV per CM + return (mVolts / 6.8); + } + + // UART mode + // query distance cmd sequence + uint8_t deg = (uint8_t)(degrees / 6); + if (deg > 46) + throw std::out_of_range(string(__FUNCTION__) + + ": degrees out of range, must be 0-270"); + + string cmd; + uint8_t cksum = 0x22 + deg + 0x00; + cmd.push_back(0x22); + cmd.push_back(deg); + cmd.push_back(0x00); + cmd.push_back(cksum); + + string resp = sendCommand(cmd); + + if (resp.empty()) + { + throw std::runtime_error(string(__FUNCTION__) + + ": sendCommand() failed"); + return 0.0; + } + + uint8_t h = (uint8_t)resp[1]; + uint8_t l = (uint8_t)resp[2]; + + float distance = float((h << 8) | l); + + return (distance); +} + +float URM37::getTemperature() +{ + if (m_analogMode) + { + throw std::runtime_error(string(__FUNCTION__) + + ": Temperature measurement not available in analog mode"); + + return 0.0; + } + + // query temperature cmd sequence + string cmd; + cmd.push_back(0x11); + cmd.push_back(0x00); + cmd.push_back(0x00); + cmd.push_back(0x11); + + string resp = sendCommand(cmd); + + if (resp.empty()) + { + throw std::runtime_error(string(__FUNCTION__) + + ": sendCommand() failed"); + return 0.0; + } + + uint8_t h = (uint8_t)resp[1]; + uint8_t l = (uint8_t)resp[2]; + + float temp; + temp = float((h & 0x0f) * 256 + l) / 10.0; + if (h & 0xf0) + temp *= -1; + + return (temp); +} + +uint8_t URM37::readEEPROM(uint8_t addr) +{ + if (m_analogMode) + { + throw std::runtime_error(string(__FUNCTION__) + + ": readEEPROM() is not possible in analog mode"); + + return 0; + } + + if (addr > 0x04) + throw std::out_of_range(string(__FUNCTION__) + + ": addr must be between 0x00-0x04"); + + string cmd; + uint8_t cksum = 0x33 + addr + 0x00; + cmd.push_back(0x33); + cmd.push_back(addr); + cmd.push_back(0x00); + cmd.push_back(cksum); + + string resp = sendCommand(cmd); + + if (resp.empty()) + { + throw std::runtime_error(string(__FUNCTION__) + + ": sendCommand() failed"); + return 0; + } + + return resp[2]; +} + +void URM37::writeEEPROM(uint8_t addr, uint8_t value) +{ + if (m_analogMode) + { + throw std::runtime_error(string(__FUNCTION__) + + ": writeEEPROM() is not possible in analog mode"); + + return; + } + + if (addr > 0x04) + throw std::out_of_range(string(__FUNCTION__) + + ": addr must be between 0x00-0x04"); + + string cmd; + uint8_t cksum = 0x44 + addr + value; + cmd.push_back(0x44); + cmd.push_back(addr); + cmd.push_back(value); + cmd.push_back(cksum); + + string resp = sendCommand(cmd); + + if (resp.empty()) + { + throw std::runtime_error(string(__FUNCTION__) + + ": sendCommand() failed"); + return; + } + + return; +} + +string URM37::sendCommand(string cmd) +{ + if (m_analogMode) + { + throw std::runtime_error(string(__FUNCTION__) + + ": can only be executed in UART mode"); + + return ""; + } + + int tries = 0; + string resp; + + while (tries++ < maxRetries) + { + writeDataStr(cmd); + if (!dataAvailable(waitTimeout)) + { + cerr << __FUNCTION__ << ": Timed out waiting for response" << endl; + continue; + } + + resp = readDataStr(8); + + // verify size + if (resp.size() != 4) + { + cerr << __FUNCTION__ << ": Invalid returned packet size" << endl; + continue; + } + else + { + // we have data, verify cksum, return the response if it's + // good, retry otherwise + uint8_t cksum = (uint8_t)(resp[0] + resp[1] + resp[2]); + + if ((uint8_t)resp[3] != cksum) + { + cerr << __FUNCTION__ << ": cksum failure" << endl; + continue; + } + + // else, we are good to go + return resp; + } + } + + // :( + return ""; +} + diff --git a/src/urm37/urm37.h b/src/urm37/urm37.h new file mode 100644 index 00000000..43a26883 --- /dev/null +++ b/src/urm37/urm37.h @@ -0,0 +1,204 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2015 Intel Corporation. + * + * Thanks to Adafruit for supplying a google translated version of the + * Chinese datasheet and some clues in their code. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define URM37_DEFAULT_UART 0 + +namespace upm { + /** + * @brief DFRobot URM37 Ultrasonic Ranger + * @defgroup urm37 libupm-urm37 + * @ingroup dfrobot uart gpio ainput sound + */ + + /** + * @library urm37 + * @sensor urm37 + * @comname DFRobot URM37 Ultrasonic Ranger + * @type sound + * @man dfrobot + * @con uart ainput gpio + * @web http://www.dfrobot.com/index.php?route=product/product&product_id=53 + * + * @brief API for the DFRobot URM37 Ultrasonic Ranger + * + * The driver was tested with the DFRobot URM37 Ultrasonic Ranger, + * V4. It has a range of between 5 and 500 centimeters (cm). It + * supports both analog distance measurement, and UART based + * temperature and distance measurements. This driver does not + * support PWM measurement mode. + * + * For UART operation, the only supported baud rate is 9600. In + * addition, you must ensure that the UART TX/RX pins are + * configured for TTL operation (the factory default) rather than + * RS232 operation, or permanent damage to your URM37 and/or MCU + * will result. On power up, the LED indicator will blink one + * long pulse, followed by one short pulse to indicate TTL + * operation. See the DFRobot wiki for more information: + * + * (https://www.dfrobot.com/wiki/index.php?title=URM37_V4.0_Ultrasonic_Sensor_%28SKU:SEN0001%29) + * + * An example using analog mode + * @snippet urm37.cxx Interesting + * An example using UART mode + * @snippet urm37-uart.cxx Interesting + */ + + class URM37 { + public: + + /** + * URM37 object constructor (Analog mode) + * + * @param aPin Analog pin to use + * @param resetPin GPIO pin to use for reset + * @param triggerPin GPIO pin to use for triggering a distance measurement + * @param aref The analog reference voltage, default 5.0 + */ + URM37(int aPin, int resetPin, int triggerPin, float aref=5.0); + + /** + * URM37 object constructor (UART mode) + * + * @param uart Default UART to use (0 or 1). + * @param resetPin GPIO pin to use for reset + */ + URM37(int uart, int resetPin); + + /** + * URM37 object destructor + */ + ~URM37(); + + /** + * Reset the device. This will take approximately 3 seconds to + * complete. + * + */ + void reset(); + + /** + * Get the distance measurement. A return value of 65535.0 + * in UART mode indicates an invalid measurement. + * + * @param degrees in UART mode, this specifies the degrees to turn + * an attached PWM servo connected to the MOTO output on the + * URM37. Default is 0. Valid values are 0-270. This option is + * ignored in analog mode. + * @return The measured distance in cm + */ + float getDistance(int degrees=0); + + /** + * Get the temperature measurement. This is only valid in UART mode. + * + * @return The measured temperature in degrees C + */ + float getTemperature(); + + /** + * In UART mode only, read a value from the EEPROM and return it. + * + * @param addr The address in the EEPROM to read. Valid values + * are between 0x00-0x04. + * @return The EEPROM value at addr + */ + uint8_t readEEPROM(uint8_t addr); + + /** + * In UART mode only, write a value into an address on the EEPROM. + * + * @param addr The address in the EEPROM to write. Valid values + * are between 0x00-0x04. + * @param value The value to write + * @return The EEPROM value at addr + */ + void writeEEPROM(uint8_t addr, uint8_t value); + + protected: + mraa::Uart *m_uart; + mraa::Aio *m_aio; + mraa::Gpio *m_gpioTrigger; + mraa::Gpio m_gpioReset; + + // initialize reset gpio and call reset + void init(); + + // send a serial command and return a 4 byte response (UART mode only) + std::string sendCommand(std::string cmd); + + private: + /** + * Checks to see if there is data aavailable for reading + * + * @param millis Number of milliseconds to wait; 0 means no waiting + * @return true if there is data available for reading + */ + bool dataAvailable(unsigned int millis); + + /** + * Reads any available data and returns it in a std::string. Note: + * the call blocks until data is available for reading. Use + * dataAvailable() to determine whether there is data available + * beforehand, to avoid blocking. + * + * @param len Maximum length of the data to be returned + * @return Number of bytes read + */ + std::string readDataStr(int len); + + /** + * Writes the std:string data to the device. If you are writing a + * command, be sure to terminate it with a carriage return (\r) + * + * @param data Buffer to write to the device + * @return Number of bytes written + */ + int writeDataStr(std::string data); + + // analog or UART mode + bool m_analogMode; + + // analog reference and resolution + float m_aref; + int m_aRes; + }; +} + +