PWM - control of brushed motor ESC

I am beginning to work with ESCs using the PWM pins on my FEZ Panda II. After digging through many posts and google searches I made some decent progress. However I am a bit confused on the actual range of this particular ESC, or if this is the same across all ESCs.

Below is the code I am using for controlling the motor in 1% increments on a scale from 0-100%.

 static void TestMotor()
        {

            uint low = 1000;
            uint high = 2000;

            try
            {
                led.Write(true);
                motor.Set(true);

                delay = 500;
                for (short percent = 0; percent <= 100; percent++)
                { 
                    SetPulse(motor, 20000, TestMotor_CalcScale(low, high, percent));
                }

                SetPulse(motor, 20000, low);

            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
                motor.Set(false);
            }
        }

        static uint TestMotor_CalcScale(uint low, uint high, short percent)
        {
            uint rtObject = 0;
            uint perpercent = 0;

            try
            {
                perpercent = (high - low) / 100;
                rtObject = low + (uint)(perpercent * percent);
            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
            }

            return rtObject;
        }

        static void SetPulse(PWM pwm, uint period_nanosecond, uint highTime_nanosecond)
        {
            try
            {
                Debug.Print("SetPulse: " + period_nanosecond.ToString() + ": " + highTime_nanosecond.ToString());
                pwm.SetPulse(period_nanosecond * 1000, highTime_nanosecond * 1000);
                led.Write(!led.Read());
                Thread.Sleep(delay);
            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
            }
        }



In the code I have set the lower value to 1000 and upper value to 2000. These are the common values I’ve found posted across many topics and google searches.

My questions are…

  1. After stepping into the code I found that the motor starts around 1260 and peaks around 1750. Is this the common range for all ESCs or will this be unique to each ESC?

  2. I know you can switch the polarity of the motor to control forward/reverse which is also accomplished with an H bridge. But is there an ESC out there that allows another signal for forward/reverse? Or would it be controlled via the high/low or frequency?

Using code tags will make your post more readable. This can be done in two ways:[ol]
Click the “101010” icon and paste your code between the

 tags or...
Select the code within your post and click the "101010" icon.[/ol]
(Generated by QuickReply)

Thanks for the tip! That makes it much easier to read.

Every brand will have its low and high range, but they should all be very close.

There are 2 basic ESC’s out there. Land and AIR. The land type which would be used in say a RC truck has the forward and reverse. Idle is 1.5ms and 1ms is full reverse while 2ms is full forward. Air which is planes and heli’s have no need for reverse so idle is 1ms and full is 2ms.

You’re answer could not have been more precise.

I’ll purchase a land esc from the hobby shop tomorrow and do some testing.

Thanks!

No prob, Just remember one thing. ESC’s need to be armed first. So for a land unit, you need to send it 1.5ms for a few seconds to allow it to arm. Its a safety feature.
you will know its armed by the beeps. Typically the first set of beebs is how many cells you have connected. The next set of tones is that its armed and ready. Only then can you change the freq.

Thanks jdal. I used my old proboat ESC and put together the following code. Works like a charm. I guess the only thing thing I have to work on is being able to build in adjustments to the low/high depending on the esc. They definitly start responding at different ranges.


using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;

namespace FEZ_Panda_II_Application1
{
    public class Program
    {
        static OutputPort led = null;
        static Int32 delay = 1000;

        public static void Main()
        {
            try
            {
                //set led for flashing when sending pulses
                led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);

                //execute procedures for each test
                TestServo();
                TestMotorForwardOnly();
                TestMotorForwardReverse();
            }
            catch( Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
                //dispose
                led = null;
            }
            
        }


        static void TestMotorForwardReverse()
        {
            PWM forwardreversemotor = null;

            try
            {
                forwardreversemotor = new PWM(PWM.Pin.PWM3);
                led.Write(true);
                forwardreversemotor.Set(true);

                //set esc to neutral ( initialize ESC )
                delay = 5000;
                SetPulse(forwardreversemotor, 20000, TestMotorForwardReverse_CalcScale(0));

                //increase esc from 0 ( neutral ) to 100 ( full forward ) with 1/2 second delay between each pulse
                delay = 500;
                for (short percent = 0; percent <= 100; percent++)
                {
                    SetPulse(forwardreversemotor, 20000, TestMotorForwardReverse_CalcScale(percent));
                }

                //set esc to neutral
                delay = 5000;
                SetPulse(forwardreversemotor, 20000, TestMotorForwardReverse_CalcScale(0));

                //increase ecs from 0 ( neutral ) to -100 ( full reverse ) with 1/2 second delay between each pulse
                delay = 500;
                for (short percent = 0; percent >=-100; percent--)
                {
                    SetPulse(forwardreversemotor, 20000, TestMotorForwardReverse_CalcScale(percent));
                }

                //set esc to neutral
                delay = 5000;
                SetPulse(forwardreversemotor, 20000, TestMotorForwardReverse_CalcScale(0));

            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
                //dispose
                forwardreversemotor.Set(false);
                forwardreversemotor = null;
            }
        }

        static uint TestMotorForwardReverse_CalcScale(short percent)
        {
            uint fullreverse = 1000;
            uint neutral = 1500;
            uint fullforward = 2000; //only for reference, not used within calculation
            uint perpercent = 0;
            uint rtObject = 0;

            try
            {
                //perpercent is the amount to adjust from neutral for each percent
                //range is from -100 ( full reverse ) to +100 ( full forward )(
                //0 = neutral
                perpercent = ( neutral - fullreverse ) / 100;
                rtObject = neutral + (uint)(perpercent * percent);
            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
            }

            return rtObject;
        }

        static void TestMotorForwardOnly()
        {
            PWM forwardmotor = null;

            try
            {
                led.Write(true);

                forwardmotor = new PWM(PWM.Pin.PWM2);
                forwardmotor.Set(true);

                //set esc to 0 ( off )
                delay = 5000;
                SetPulse(forwardmotor, 20000, TestMotorForwardOnly_CalcScale(0));

                //increase esc from 0 ( off ) to 100 ( full ) with 1/2 second delay between each pulse
                delay = 500;
                for (short percent = 0; percent <= 100; percent++)
                {
                    SetPulse(forwardmotor, 20000, TestMotorForwardOnly_CalcScale(percent));
                }

                //set esc to 0 ( off )
                delay = 5000;
                SetPulse(forwardmotor, 20000, TestMotorForwardOnly_CalcScale(0));

            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
                //dispose
                forwardmotor.Set(false);
                forwardmotor = null;
            }
        }

        static uint TestMotorForwardOnly_CalcScale(short percent)
        {
            uint low = 1000;
            uint high = 2000;
            uint rtObject = 0;
            uint perpercent = 0;

            try
            {
                //perpercent is the amount to adjust for each percent
                //range is from 0 ( off ) to 100 ( full )
                perpercent = (high - low) / 100;
                rtObject = low + (uint)(perpercent * percent);
            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
            }

            return rtObject;
        }

        static void TestServo()
        {

            PWM servo = null;
            uint low = 600;
            uint high = 2400;
            uint[] highTime = null;

            try
            {
                led.Write(true);
                servo = new PWM(PWM.Pin.PWM1);
                servo.Set(true);

                //this array is just used to set servo to 0 degrees and flip back and forth between -45 and +45
                highTime = new uint[5];
                highTime[0] = TestServo_CalcScale(low, high, 0);
                highTime[1] = TestServo_CalcScale(low, high, -45);
                highTime[2] = TestServo_CalcScale(low, high, 45);
                highTime[3] = TestServo_CalcScale(low, high, -45);
                highTime[4] = TestServo_CalcScale(low, high, 45);

                //iterate through highTime array setting servo location with 2second delay between pulses
                delay = 2000;
                for( int index = 0; index <= highTime.Length - 1; index++)
                {
                    SetPulse(servo, 20000, highTime[index]);
                }

                //move servo from -75 to +75 degrees with 1/10 second delay between pulses;
                //if servo is capable of -180 to +180 you can use those values.  
                //I've found a few servos that start freaking out around 170+- so check your servo before breaking it.
                delay = 100;
                for (short degree = -75; degree <= 75; degree++)
                {
                    SetPulse(servo, 20000, TestServo_CalcScale(low, high, degree));
                }

                //set servo to 0 degrees
                SetPulse(servo, 20000, TestServo_CalcScale(low, high, 0));
            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
                //dispose
                servo.Set(false);
                servo = null;
            }
        }

        static uint TestServo_CalcScale(uint low, uint high, short degree)
        {
            uint high_zero = 0;
            uint rtObject = 0;
            uint perdegree = 0;

            try
            {
                high_zero = low + ( ( high - low ) / 2 );
                perdegree = (( high - low ) / 2 ) / 90;
                rtObject = high_zero + (uint)( perdegree * degree);
            }
            catch( Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
            }

            return rtObject;
        }

        static void SetPulse(PWM pwm, uint period_nanosecond, uint highTime_nanosecond)
        {
            try
            {

                Debug.Print("SetPulse: " + period_nanosecond.ToString() + ": " + highTime_nanosecond.ToString());
                pwm.SetPulse(period_nanosecond * 1000, highTime_nanosecond * 1000);
                //invert LED value ( used to blink led on each pulse )
                led.Write(!led.Read());
                //delay for specified interval
                Thread.Sleep(delay);
            }
            catch (Exception ex)
            {
                Debug.Print("Exception[" + ex.ToString() + "]");
            }
            finally
            {
            }
        }

    }
}