Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Parallax Ping))) Sensor Code


  • Please log in to reply
8 replies to this topic

#1 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 25 December 2010 - 06:26 AM

Hello there!
I made some c sharp drivers for the Ping))) Sensor from parallax (http://www.parallax....92/Default.aspx). These are pretty nice I think. I took a look at this: http://forums.netdui...ch__1#entry4555

I then decided to use the TristatePort class (previously used in my charlieplexing code). I also got started with the math behind it from someone else's code.. if you are the one who wrote some code on the speed of sound conversion let me know and I'll post a link to your thread. Sorry I forgot who it was :unsure:

What I basicly did was a lot of optimization (other programmer friends of mine hate this, i love it) and cleaning up, also nice commented code makes for happy you and me! Also added a few new features like the Units enum and the math is optimized as well.

I'll make a video soon. Let me know if you have any questions or issues. Little note, the port that connects to the Ping))) does not need to be a PWM!

Enjoy :)

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System.Threading;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace Parallax.Sensors.Ping
{
    public enum DistanceUnits
    {
        mm,
        cm,
        dm,
        m,
        feet,
        inch,
        yard
    }

    public class Ping
    {
        TristatePort _port;
        DistanceUnits _unit = DistanceUnits.mm;

        double _soundSpeed = 343, _convertion = (10000 / 343) * 2; // default values
 
        public Ping(Cpu.Pin pin)
        {
            _port = new TristatePort(pin, false, false, ResistorModes.Disabled);
        }

        /// <summary>
        /// Automaticly adjust the convertion factor depending on air temperature.
        /// </summary>
        /// <param name="degC">The temperature in degrees celsius</param>
        public void AdjustSoundSpeed(double degC)
        {
            /* Speed of Sound (at 20 degrees celsius): 343 m/s
             * or
             * _soundSpeed = 331.4 + 0.6 * degC
             * 
             * There are 10,000,000 ticks per second.
             * 10,000,000 / _soundSpeed * 1000 can be simplyfied into:
             * 10,000 / _soundSpeed
             * times it by 2 because of round trip
             * then you get about 58.309 ticks per mm
             * 
             * then multiply if other unit is needed
             * 
             */
            _soundSpeed = 331.4 + 0.6 * degC;
            _convertion = (10000 / _soundSpeed) * 2;
        }

        /// <summary>
        /// Return the Ping))) sensor's reading in millimeters.
        /// </summary>
        /// <param name="usedefault">Set true to return value in the unit specified by the "Unit" property.
        /// Set false to return value in mm.</param>
        public double GetDistance()
        {
            bool low = true, high = true;
            long t1, t2;

            // Set it to an putput
            _port.Active = true;

            //Send a quick HIGH pulse
            _port.Write(true);
            _port.Write(false);

            // Set it as an input
            _port.Active = false;  

            while (low) 
                low = !_port.Read(); 
            t1 = System.DateTime.Now.Ticks;

            while (high) 
                high = _port.Read(); 
            t2 = System.DateTime.Now.Ticks;

            return Convert(((t2 - t1) / _convertion), _unit);
        }

        /// <summary>
        /// Convert the millimeters into other units.
        /// </summary>
        /// <param name="millimeters">The Ping))) sensor's mm reading.</param>
        /// <param name="outputUnit">The desired output unit.</param>
        public double Convert(double millimeters, DistanceUnits outputUnit)
        {
            double result = millimeters;

            switch (outputUnit)
            {
                case DistanceUnits.cm:
                    result = millimeters * 0.1F;
                    break;
                case DistanceUnits.dm:
                    result = millimeters * 0.01F;
                    break;
                case DistanceUnits.m:
                    result = millimeters * 0.001F;
                    break;
                case DistanceUnits.inch:
                    result = millimeters * 0.0393700787;
                    break;
                case DistanceUnits.feet:
                    result = millimeters * 0.0032808399;
                    break;
                case DistanceUnits.yard:
                    result = millimeters * 0.0010936133;
                    break;
            }

            return result;
        }

        public DistanceUnits Unit
        {
            get { return _unit; }
            set { _unit = value; }
        }
    }
}


#2 Anteater Ohmie

Anteater Ohmie

    New Member

  • Members
  • Pip
  • 1 posts

Posted 01 January 2011 - 03:31 AM

Hello Omar, I'm new to C# and netduino, and really trying to figure this out. :) Where would you plug in the optimized code you have above? within the other code which you reference to? Thanks. I'm also trying to output the data to a file, not sure how to go about that. :blink: Thanks if you can provide any help.

#3 Omar (OZ)

Omar (OZ)

    Advanced Member

  • Members
  • PipPipPip
  • 564 posts

Posted 01 January 2011 - 04:14 AM

Hello Omar,
I'm new to C# and netduino, and really trying to figure this out. :)

Where would you plug in the optimized code you have above? within the other code which you reference to? Thanks. I'm also trying to output the data to a file, not sure how to go about that. :blink: Thanks if you can provide any help.

"Where would you plug in the optimized code you have above?" - Just make a new class and paste all that code in the new class file. It is a whole class, it works by it self, no need to put it in another code.

"I'm also trying to output the data to a file" - If depends on what you got, if you have a netduino plus then you should be able to write to an SD card (I haven't done this so sorry I can't explain it better). You can also use something like this: http://www.sparkfun.com/products/9873 to send serial data to a c sharp app (this will work with any netduino).

Let me know what you decide to do and I'll be glad to help.

#4 adrian.campos

adrian.campos

    New Member

  • Members
  • Pip
  • 1 posts

Posted 09 February 2013 - 06:53 AM

Omar, I know this is an old post but I am just starting to get my hands dirty with netduino. I am having issues with getting a correct distance measurement. If you look at the picture you can see that my lcd screen is displaying 1467 mm when its clearly no where near that big a gap from my sensor to the black box. I used your code exactly with no changes due to the fact that it was much neater than my version (which was still getting me wrong answers). Posted Image



#5 roguemat

roguemat

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationSouth Africa

Posted 12 February 2013 - 10:08 PM

Quick question, what do these have over the 4$ ones I posted in the other thread?

 

from my uneducated view, they seem pretty similar(1 pin vs 2 though). I'm getting sub-cm accuracy on my 4$ one.


I make Windows Phone stuff for beer money and rent (in order of priority). I've got a blog and am on the Twitter machine.

#6 JerseyTechGuy

JerseyTechGuy

    Advanced Member

  • Members
  • PipPipPip
  • 870 posts

Posted 13 February 2013 - 02:08 AM

Quick question, what do these have over the 4$ ones I posted in the other thread?

 

from my uneducated view, they seem pretty similar(1 pin vs 2 though). I'm getting sub-cm accuracy on my 4$ one.

 

I didn't see the other thread.  Can you post a link to the thread or the other Ultrasonic Sensor?  I know they do sell them in difference distance capabilities and maybe that is the difference.



#7 roguemat

roguemat

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationSouth Africa

Posted 13 February 2013 - 06:31 AM

I didn't see the other thread.  Can you post a link to the thread or the other Ultrasonic Sensor?  I know they do sell them in difference distance capabilities and maybe that is the difference.

Sorry - was on my phone.

http://forums.netdui...with-your-mind/

The specs say that the range is between 2CM to 4M with an accuracy of 3MM. The results I'm getting are between 2CM and 2.5M and I am getting the 3MM accuracy.

I haven't tried getting past 2.5M - and I assume that it's actually a problem with my code, at-least partly. Although I don't need even 2M for anything I'm planning.


I make Windows Phone stuff for beer money and rent (in order of priority). I've got a blog and am on the Twitter machine.

#8 JerseyTechGuy

JerseyTechGuy

    Advanced Member

  • Members
  • PipPipPip
  • 870 posts

Posted 13 February 2013 - 11:50 AM

Thanks for the link.  I hadn't had time to read your blog yet but did see it and book marked it the day you posted it. 

 

So it looks like the sensor you are using says: [font="Arial, 'sans-serif';font-size:14px;"]Detecting distance is from 2cm to 450cm (4.5 m).[/font]

[font="Arial, 'sans-serif';font-size:14px;"]The Parallax PING sensor says: [/font]Provides precise, non-contact distance measurements within a 2 cm to 3 m range.

 

So these sensors are basically the same as far as distance measurement.  They both send a 40khz ultrasonic tone.  The main difference is the Parallax version shares the Trigger (Trig) and Echo pins in one pin called Signal (Sig).  They both require that a 10us (microsecond) high pulse be sent to the Trig or Sig lines to start the sound wave at which point the Echo or Sig lines should be monitored for the return pulse.  This return pulse is used to measure the distance based on the time it took to return.

 

For the Ping, I've been using the following Class Code.  It works well with the Ping.  The only difference with your sensor will be using two tristate ports instead.  So you'll need to rework the code a bit to use one GPIO for sending (Trig) and another for receiving (Echo).  Not sure how this differs from your code, but it's worked pretty well with my setup and is accurate to a few centimeters.

 

    /// <summary>    /// Helper class to work with Parallax Ping))) sensor    /// </summary>    public class Ping    {        /// <summary>        /// The PING))) returns a pulse width of 73.746 uS per inch.        /// </summary>        const int TO_INCH = 73746;        /// <summary>        /// The PING))) returns a pulse width of 29.033 uS per centimeter.        /// </summary>        const int TO_CM = 29034;        /// <summary>        /// Ticks per microsecond        /// </summary>        const int TicksPerMicrosecond = (int)TimeSpan.TicksPerMillisecond / 1000;        /// <summary>        /// Enumeration to indicate in what units we want the distance back        /// </summary>        public enum DistanceUnits        {            Inches,            Centimeters,            Millimeters        }        /// <summary>        /// Read/Write port attached to the connected pin        /// </summary>        private TristatePort _pin;        //Pin on the microcontroller that is used to communicate with Ping))) Sensor        public Ping(Cpu.Pin pin)        {            _pin = new TristatePort(pin, false, false, Port.ResistorMode.Disabled);        }        /// <summary>        /// Returns distance in requested units        /// </summary>        /// <param name="units">distance units to use</param>        /// <returns>distance</returns>        public int GetDistance(DistanceUnits units)        {            //Set Write mode 'ON'            _pin.Active = true;            _pin.Write(true);            _pin.Write(false);            //Set Read mode 'ON'            _pin.Active = false;            bool high = false;            //Wait for start of the echo pulse.            do            {                high = _pin.Read();            }            while (!high);            //Measure current time            long startTime = System.DateTime.Now.Ticks;            // Wait for end of echo pulse.            while (high)            {                high = _pin.Read();            }            //Get total ticks accounting for roundtrip            int ticks = (int)(System.DateTime.Now.Ticks - startTime) >> 1;            int microSeconds = ticks / TicksPerMicrosecond;            if (units == DistanceUnits.Inches)                return microSeconds * 1000 / TO_INCH;            else if (units == DistanceUnits.Centimeters)                return microSeconds * 1000 / TO_CM;            else                return microSeconds * 10000 / TO_CM;                    }    }


#9 roguemat

roguemat

    Advanced Member

  • Members
  • PipPipPip
  • 54 posts
  • LocationSouth Africa

Posted 13 February 2013 - 01:42 PM

Thanks for the link.  I hadn't had time to read your blog yet but did see it and book marked it the day you posted it. 

 

So it looks like the sensor you are using says: [font="Arial, 'sans-serif';font-size:14px;"]Detecting distance is from 2cm to 450cm (4.5 m).[/font]

[font="Arial, 'sans-serif';font-size:14px;"]The Parallax PING sensor says: [/font]Provides precise, non-contact distance measurements within a 2 cm to 3 m range.

 

So these sensors are basically the same as far as distance measurement.  They both send a 40khz ultrasonic tone.  The main difference is the Parallax version shares the Trigger (Trig) and Echo pins in one pin called Signal (Sig).  They both require that a 10us (microsecond) high pulse be sent to the Trig or Sig lines to start the sound wave at which point the Echo or Sig lines should be monitored for the return pulse.  This return pulse is used to measure the distance based on the time it took to return.

 

For the Ping, I've been using the following Class Code.  It works well with the Ping.  The only difference with your sensor will be using two tristate ports instead.  So you'll need to rework the code a bit to use one GPIO for sending (Trig) and another for receiving (Echo).  Not sure how this differs from your code, but it's worked pretty well with my setup and is accurate to a few centimeters.

 

   

Your code looks similar to what I am using - which is from one of the members in this forum.

So it looks like the main difference is the number of pins?

In terms of accuracy, I'm using a ruler and sliding a paper along it to test. I can move it to 100cm (etc) and move half a cm more and I get 100.5 - so it seems very accurate.

 

Another question I have is how many of these (or the ping) can a normal Netduino (1) take? The datasheet says the ping uses 20mA - but isn't that already higher than the 16mA max per pin on the Netduino? Or is that the wrong way to work it out because it's drawing power straight from the 5v/3.3v?


I make Windows Phone stuff for beer money and rent (in order of priority). I've got a blog and am on the Twitter machine.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.