L298 Motor Driver Problems

Scheme: Screenshot - acff7d108aabcf25930598a6b6f88b5f - Gyazo
PowerSource: 9V (http://melt.ru/upload/iblock/92b/92b8e98cc04565f893dd866b6fe616f1.jpg)




	public partial class Program
	{
		private enum Dir
		{
			None,
			Stop, 
			Fwd,
			Bck,
			Lft,
			Rth,
		}

		GT.Timer timer = null;

		void ProgramStarted()
		{
			Debug.Print( "Program Started" );

			joystick.JoystickPressed += new Joystick.JoystickEventHandler( joystick_JoystickPressed );

			timer = new GT.Timer( 100, GT.Timer.BehaviorType.RunOnce );
			timer.Tick += new GT.Timer.TickEventHandler( timer_Tick );
			timer.Start();
		}

		void joystick_JoystickPressed( Joystick sender, Joystick.JoystickState state )
		{
			DoMovement( Dir.Stop );
		}

		void timer_Tick( GT.Timer timer )
		{
			var pos = joystick.GetJoystickPosition();

			var x = ( byte )( pos.X * 200 ) - 100;
			var y = ( byte )( pos.Y * 200 ) - 100;

			try
			{
				var dx = Dir.Stop;
				var dy = Dir.Stop;

				if ( y > 50 )
				{
					dy = Dir.Fwd;
				}
				else if ( y < -50)
				{
					dy = Dir.Bck;
				}

				if ( x > 50 )
				{
					dx = Dir.Rth;
				}
				else if ( x < -50 )
				{
					dx = Dir.Lft;
				}

				var cmd = GetCmd( dx, dy );

				DoMovement( cmd );
			}
			catch ( Exception ex )
			{
				Debug.Print( ex.Message + ", \r\n" + ex.StackTrace );
			}

			timer.Start();
		}

		private Dir GetCmd( Dir dx, Dir dy )
		{
			switch ( dy )
			{
				case Dir.Fwd:
					switch ( dx )
					{
						case Dir.Lft:
						case Dir.Rth:
							return dx;
						default:
							return dy;
					}
				case Dir.Bck:
					switch ( dx )
					{
						case Dir.Lft:
						case Dir.Rth:
							return dx;
						default:
							return dy;
					}

				case Dir.Stop:
					return dy;

				default:
					return Dir.None;
			}
		}

		private Dir _CurrentMove = Dir.Stop;
		private void DoMovement( Dir cmd )
		{
			if ( cmd == Dir.None )
				return;

			if ( _CurrentMove != cmd )
			{
				Debug.Print( "Movement: " + cmd ); 

				_CurrentMove = cmd;

				switch ( cmd )
				{
					case Dir.Stop:
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor1, 0 );
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor2, 0 );
						break;
					case Dir.Fwd:
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor1, 100 );
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor2, 100 );
						break;
					case Dir.Bck:
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor1, -100 );
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor2, -100 );
						break;
					case Dir.Lft:
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor1, -100 );
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor2, 100 );
						break;
					case Dir.Rth:
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor1, 100 );
						motorControllerL298.MoveMotor( MotorControllerL298_2.Motor.Motor2, -100 );
						break;
				}

				Thread.Sleep( 500 );
			}
		}
	}


Problem 1

I have noise sound when try positive direction speed (when use speed [-100;-1] it has no noise sound)
same like this post video: http://www.tinyclr.com/forum/topic?id=8486&page=1#msg87053

Problem 2

When i try use positive directions (Dir.Fwd) - it has no reaction on motors
exactly this lines disable motor in driver



                    // Set direction and power.
                    m_Direction1.Write(false); << -----------------
                    m_Pwm1.Set(1000, (double)(_newSpeed / 100.0));



                    // Set direction and power.
                    m_Direction2.Write(false); << -----------------
                    m_Pwm2.Set(1000, (double)(_newSpeed / 100.0));


Any know how fix this?

p.s.
I don’t want use Ramp

p.p.s.
Current driver has some errors with div/0 in Ramp command, when try set current speed twice.
Can fix with this lines - because this is not usercode problem.


            //////////////////////////////////////////////////////////////////////////////////
            // Motor1
            //////////////////////////////////////////////////////////////////////////////////
            if (_motorSide == Motor.Motor1)
            {
				if ( m_lastSpeed1 == _newSpeed ) return; << --------------

				// Save our speed
				m_lastSpeed1 = _newSpeed;



            //////////////////////////////////////////////////////////////////////////////////
            // Motor2
            //////////////////////////////////////////////////////////////////////////////////
            else
            {
				if ( m_lastSpeed2 == _newSpeed ) return; << --------------------

				// Save our speed
				m_lastSpeed2 = _newSpeed;

Tests:
[ul]0 -> -100 - work done without noise[/ul]
[ul]-100 -> 0 - work done without noise[/ul]
[ul]0 -> 100 no reaction[/ul]
[ul]100 -> 0 no reaction[/ul]
[ul]0 -> 50 work done and has annoyed noise sound[/ul]
[ul]50 -> 0 engine still work and has annoyed noise sound[/ul]
[ul]0 -> -100 - work done without noise[/ul]
[ul]-100 -> 0 - engine work with reverted direction and has annoyed noise[/ul]

What’s wrong ?

If this test sample to complex - i can show more simple…

@ Volhv - Check the following post which discusses some of the issues with the motor driver
http://www.tinyclr.com/forum/jump/9171/91507

Issue with check current speed with return - true, i write about in first post… but this is not so sirious problem
i have problem with positive direction of motors 8(

In my tests i use custom driver


using System;
using Microsoft.SPOT;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GTI = Gadgeteer.Interfaces;
using Microsoft.SPOT.Hardware;
using Gadgeteer;
using System.Threading;

namespace Spider_v0
{
    public class MotorControllerL298_2 : GTM.Module
    {
        GTI.PWMOutput m_Pwm1;
        GTI.PWMOutput m_Pwm2;

        OutputPort m_Direction1;
        OutputPort m_Direction2;

        int m_lastSpeed1 = 0;
        int m_lastSpeed2 = 0;

        // This example implements  a driver in managed code for a simple Gadgeteer module.  The module uses a 
        // single GTI.InterruptInput to interact with a sensor that can be in either of two states: low or high.
        // The example code shows the recommended code pattern for exposing the property (IsHigh). 
        // The example also uses the recommended code pattern for exposing two events: MotorControllerL298High, MotorControllerL298Low. 
        // The triple-slash "///" comments shown will be used in the build process to create an XML file named
        // GTM.GHIElectronics.MotorControllerL298. This file will provide Intellisense and documention for the
        // interface and make it easier for developers to use the MotorControllerL298 module.        

        // Note: A constructor summary is auto-generated by the doc builder.
        /// <summary></summary>
        /// <param name="socketNumber">The socket that this module is plugged in to.</param>
        public MotorControllerL298_2(int socketNumber)
        {
            // This finds the Socket instance from the user-specified socket number.  
            // This will generate user-friendly error messages if the socket is invalid.
            // If there is more than one socket on this module, then instead of "null" for the last parameter, 
            // put text that identifies the socket to the user (e.g. "S" if there is a socket type S)
            Socket socket = Socket.GetSocket(socketNumber, true, this, null);

            socket.EnsureTypeIsSupported(new char[] { 'P' }, this);

            // Set up the PWM pins
            m_Pwm1 = new GTI.PWMOutput(socket, Socket.Pin.Seven, false, this);
            m_Pwm2 = new GTI.PWMOutput(socket, Socket.Pin.Eight, false, this);

            m_Direction1 = new OutputPort(socket.CpuPins[9], false);
            m_Direction2 = new OutputPort(socket.CpuPins[6], false);

            m_Pwm1.Set(1000, 0);
            m_Pwm2.Set(1000, 0);

            // This creates an GTI.InterruptInput interface. The interfaces under the GTI namespace provide easy ways to build common modules.
            // This also generates user-friendly error messages automatically, e.g. if the user chooses a socket incompatible with an interrupt input.
            this.input = new GTI.InterruptInput(socket, GT.Socket.Pin.Three, GTI.GlitchFilterMode.On, GTI.ResistorMode.PullUp, GTI.InterruptMode.RisingAndFallingEdge, this);

            // This registers a handler for the interrupt event of the interrupt input (which is below)
            this.input.Interrupt += new GTI.InterruptInput.InterruptEventHandler(this._input_Interrupt);
        }

        private void _input_Interrupt(GTI.InterruptInput input, bool value)
        {
            this.OnMotorControllerL298Event(this, value ? MotorControllerL298State.Low : MotorControllerL298State.High);
        }

        private GTI.InterruptInput input;

        /// <summary>
        /// Gets a value that indicates whether the state of this MotorControllerL298 is high.
        /// </summary>
        public bool IsHigh
        {
            get
            {
                return this.input.Read();
            }
        }

        /// <summary>
        /// Represents the state of the <see cref="MotorControllerL298_2"/> object.
        /// </summary>
        public enum MotorControllerL298State
        {
            /// <summary>
            /// The state of MotorControllerL298 is low.
            /// </summary>
            Low = 0,
            /// <summary>
            /// The state of MotorControllerL298 is high.
            /// </summary>
            High = 1
        }

        /// <summary>
        /// Represents the desired motor to use.
        /// </summary>
        public enum Motor
        {
            /// <summary>
            /// The left motor, marked M1, is the one in use.
            /// </summary>
            Motor1 = 1,

            /// <summary>
            /// The right motor, marked M2, is the one in use.
            /// </summary>
            Motor2 = 2,
        }

        /// <summary>
        /// Used to set a motor's speed.
        /// <param name="_motorSide">The motor <see cref="Motor"/> you are setting the speed for.</param>
        /// <param name="_newSpeed"> The new speed that you want to set the current motor to.</param>
        /// </summary>
        public void MoveMotor(Motor _motorSide, int _newSpeed)
        {
 #if DEBUG
			Debug.Print( "Motor: " + _motorSide + ", Speed: " + _newSpeed );
 #endif
            // Make sure the speed is within an acceptable range.
            if (_newSpeed > 100 || _newSpeed < -100)
                new ArgumentException("New motor speed outside the acceptable range (-100-100)", "_newSpeed");

            //////////////////////////////////////////////////////////////////////////////////
            // Motor1
            //////////////////////////////////////////////////////////////////////////////////
            if (_motorSide == Motor.Motor1)
            {
				if ( m_lastSpeed1 == _newSpeed )
					return;

                // Save our speed
                m_lastSpeed1 = _newSpeed;

                // Determine the direction we are going to go.
                if (_newSpeed < 0)
                {
                    // Set direction and power.
                    m_Direction1.Write(true);
                    m_Pwm1.Set(1000, (double)((100 - System.Math.Abs(_newSpeed)) / 100.0));
                }
                else
                {
					if ( _newSpeed == 0 )
						_newSpeed = 1;

                    // Set direction and power.
                    m_Direction1.Write(false);
                    m_Pwm1.Set(1000, (double)(_newSpeed / 100.0));
                }
            }
            //////////////////////////////////////////////////////////////////////////////////
            // Motor2
            //////////////////////////////////////////////////////////////////////////////////
            else
            {
				if ( m_lastSpeed2 == _newSpeed )
					return;

                // Save our speed
                m_lastSpeed2 = _newSpeed;

                // Determine the direction we are going to go.
                if (_newSpeed < 0)
                {
                    // Set direction and power.
                    m_Direction2.Write(true);
                    m_Pwm2.Set(1000, (double)((100 - System.Math.Abs(_newSpeed)) / 100.0));
                }
                else
                {
					if ( _newSpeed == 0 )
						_newSpeed = 1;

                    // Set direction and power.
                    m_Direction2.Write(false);
                    m_Pwm2.Set(1000, (double)(_newSpeed / 100.0));
                }
            }
            //////////////////////////////////////////////////////////////////////////////////
        }
        /// <summary>
        /// Used to set a motor's speed with a ramping acceleration. <see cref="MoveMotor"/>
        /// <param name="_motorSide">The motor <see cref="Motor"/> you are setting the speed for.</param>
        /// <param name="_newSpeed"> The new speed that you want to set the current motor to.</param>
        /// <param name="_rampingDelayMilli"> The time in which you want the motor to reach the new speed (in milliseconds).</param>
        /// </summary>
        public void MoveMotorRamp(Motor _motorSide, int _newSpeed, int _rampingDelayMilli)
        {
            int temp_speed;
            int startSpeed;
            int lastSpeed;

            int timeStep;
            int deltaTime = 0;

            // Determine which motor we are going to change.
            if (_motorSide == Motor.Motor1)
            {
                temp_speed = m_lastSpeed1;
                startSpeed = m_lastSpeed1;
                lastSpeed = m_lastSpeed1;
            }
            else
            {
                temp_speed = m_lastSpeed2;
                startSpeed = m_lastSpeed2;
                lastSpeed = m_lastSpeed2;
            }

			if ( _newSpeed == lastSpeed )
				return;

            // Determine how long we need to wait between move calls.
            timeStep = _rampingDelayMilli / (_newSpeed - lastSpeed);

            ////////////////////////////////////////////////////////////////
            // Ramp
            ////////////////////////////////////////////////////////////////
            while (_newSpeed != temp_speed)
            {
                // If we have been updating for the passed in length of time, exit the loop.
                if (deltaTime >= _rampingDelayMilli)
                    break;

                // If we are slowing the motor down.
                if (temp_speed > _newSpeed)
                {
                    temp_speed += ((startSpeed - _newSpeed) / timeStep);
                }
                // If we are speeding the motor up.
                if (temp_speed < _newSpeed)
                {
                    temp_speed -= ((startSpeed - _newSpeed) / timeStep);
                }

                // Set our motor speed to our new values.
                MoveMotor(_motorSide, temp_speed);

                // Increase our timer.
                deltaTime += System.Math.Abs(timeStep);

                // Wait until we can move again.
                Thread.Sleep(System.Math.Abs(timeStep));
            }
            ////////////////////////////////////////////////////////////////
        }

        /// <summary>
        /// Represents the delegate that is used to handle the <see cref="MotorControllerL298High"/>
        /// and <see cref="MotorControllerL298Low"/> events.
        /// </summary>
        /// <param name="sender">The <see cref="MotorControllerL298_2"/> object that raised the event.</param>
        /// <param name="state">The state of the MotorControllerL298</param>
        public delegate void MotorControllerL298EventHandler(MotorControllerL298_2 sender, MotorControllerL298State state);

        /// <summary>
        /// Raised when the state of <see cref="MotorControllerL298_2"/> is high.
        /// </summary>
        /// <remarks>
        /// Implement this event handler and the <see cref="MotorControllerL298Low"/> event handler
        /// when you want to provide an action associated with MotorControllerL298 activity.
        /// The state of the MotorControllerL298 is passed to the <see cref="MotorControllerL298EventHandler"/> delegate,
        /// so you can use the same event handler for both MotorControllerL298 states.
        /// </remarks>
        public event MotorControllerL298EventHandler MotorControllerL298High;

        /// <summary>
        /// Raised when the state of <see cref="MotorControllerL298_2"/> is low.
        /// </summary>
        /// <remarks>
        /// Implement this event handler and the <see cref="MotorControllerL298High"/> event handler
        /// when you want to provide an action associated with MotorControllerL298 activity.
        /// Since the state of the MotorControllerL298 is passed to the <see cref="MotorControllerL298EventHandler"/> delegate,
        /// you can use the same event handler for both MotorControllerL298 states.
        /// </remarks>
        public event MotorControllerL298EventHandler MotorControllerL298Low;

        private MotorControllerL298EventHandler onMotorControllerL298;

        /// <summary>
        /// Raises the <see cref="MotorControllerL298High"/> or <see cref="MotorControllerL298Low"/> event.
        /// </summary>
        /// <param name="sender">The <see cref="MotorControllerL298_2"/> that raised the event.</param>
        /// <param name="MotorControllerL298State">The state of the MotorControllerL298.</param>
        protected virtual void OnMotorControllerL298Event(MotorControllerL298_2 sender, MotorControllerL298State MotorControllerL298State)
        {
            if (this.onMotorControllerL298 == null)
            {
                this.onMotorControllerL298 = new MotorControllerL298EventHandler(this.OnMotorControllerL298Event);
            }

            if (Program.CheckAndInvoke((MotorControllerL298State == MotorControllerL298State.High ? this.MotorControllerL298High : this.MotorControllerL298Low), this.onMotorControllerL298, sender, MotorControllerL298State))
            {
                switch (MotorControllerL298State)
                {
                    case MotorControllerL298State.High:
                        this.MotorControllerL298High(sender, MotorControllerL298State);
                        break;
                    case MotorControllerL298State.Low:
                        this.MotorControllerL298Low(sender, MotorControllerL298State);
                        break;
                }
            }
        }
    }
}

I’m getting that moderately high pitch electrical whine from my L298 too, also one of the motors seems to be going significantly faster than the other.

Did you try to swap the motors to see if the output is different or the motors are?

I confirm, same reaction.

Yes, but nothing changes…

BTW, @ Gus, why GHI dont use standart for swaping directions?
DataSheet: http://www.ghielectronics.com/downloads/Gadgeteer/Module/Motor%20Driver%20L298%20sch.pdf

in many resources i see next scheme:

  1. stop motor, wait
  2. set speed and positive directon
  3. start motor, wait
  4. stop motor, wait
  5. set another direction (before set negative direction stop is need)
  6. start motor, wait

Why in datasheet ports named ENA and ENB solded with +5 ?

Here’s a video of the issue I’m having, mainly so you can hear the noise. Can’t be bothered with the series of youtubes tonight so it’s an avi, not a large download: http://bogus.wswarren.com/img/l298.avi

Tried swapping motors and it didn’t yield any results…only one of the L298’s speed LEDs lights when I set both motors to 95 speed so I’m pretty sure it’s a hardware thing. It must be one of the mislabeled ones too, seeing as how the motor went backwards when it got a forward command.

Have you tried to change the frequency in the driver?

No, all I’ve done is set speed with MoveMotor and MoveMotorRampNB. How would I go about changing the frequency?

You need to use the driver source code.

Yes, same noise…

Which frequency can work?

Maybe this help

DataSheet.L298: http://www.sparkfun.com/datasheets/Robotics/L298_H_Bridge.pdf

ELECTRICAL CHARACTERISTICS

  • Symbol: fc (Vi)
  • Parameter: Commutation Frequency
  • Test Conditions: IL = 2A
  • Typ. : 25
  • Max. : 40
  • Unit : KHz

Think this is same problem

Have any idea how fix this ?