Engine control – move 45°, wait, move 45°, wait

HomeForumsMonoBrick EV3 FirmwareEngine control – move 45°, wait, move 45°, wait

This topic contains 9 replies, has 3 voices, and was last updated by Author Image Anders Søborg 2 years, 6 months ago.

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
    Posts
  • #5004
    Author Image
    Auctor137
    Participant

    Hi everybody,

    I’m trying to solve a Rubik Cube with the EV3 Set and therefore I have to write a program, which does this routine eight times:

    
    - wait time x (scanning the color, less than 1s)
    - move 45° degrees counterclockwise
    

    I tried this code for the beginning

    
    using System;
    using System.Threading;
    using MonoBrickFirmware;
    using MonoBrickFirmware.Movement;
    using MonoBrickFirmware.Display;
    using MonoBrickFirmware.UserInput;
    
    namespace MoveMotorA90°
    {
        class Program
        {
            static void Main(string[] args)
            {
                Motor motorA = new Motor(MotorPort.OutA);
                motorA.ResetTacho();
                motorA.On();   
    		// First 45°
                motorA.SpeedProfile(-80, 15, 15, 15, true);		// move motorA 45°
    								// 80% speed, 15° accerelate, 15° hold speed, 15° break, break at end
                LcdConsole.WriteLine("Position A: " + motorA.GetTachoCount());
    			Thread.Sleep(1000);
    		// Second 45°	
    			motorA.SpeedProfile(-80, 15, 15, 15, true);	// move motorA 45°
    			LcdConsole.WriteLine("Position A: " + motorA.GetTachoCount());
    			Thread.Sleep(1000);
    		// Third 45°	
    			motorA.SpeedProfile(-80, 15, 15, 15, true);	// move motorA 45°
    			LcdConsole.WriteLine("Position A: " + motorA.GetTachoCount());
    			Thread.Sleep(1000);
                LcdConsole.WriteLine("Program shutdown in 2s");
                Thread.Sleep(2000);
                motorA.Off();
            }
        }
    }
    
    

    It doesn’t work.
    Sometimes the engine does not even the first 90°, it stops at 89° but the program waits for the 90°. If I turn the engine with my hand a little bit the program continues. Or it does the first 90°, displays his tacho count “90°”, then he starts again but does only 70° or less or more degrees.

    Another big problem is the time, I programmed 1 second to wait, but the Brick waits longer.
    I also tried to delete the time to wait, but the Brick still does wait for about 4-6s. Why is it doing that?

    I would really appreciate some help or a easy to understand explanation of the function I have to use.

    #5008
    Author Image
    Anders Søborg
    Key Master

    Hi there

    Great project that you are working on. I moved your topic to the right forum. Anyway to answer your questions

    Sometimes the engine does not even the first 90°, it stops at 89° but the program waits for the 90°.

    Your program does not use the waithandle that is returned from the speedprofile function. The execution continues but you wait 1000 ms. Please have a look at the motor example found here

    /Anders

    #5009
    Author Image
    Anders Søborg
    Key Master

    Hi there

    Sorry I did not answer your second question.

    I also tried to delete the time to wait, but the Brick still does wait for about 4-6s. Why is it doing that?

    The program need to JIT compile each function call (only the first time they are called). That is simply the nature of running on the .NET framework, but on a small processor like the one in the LEGO brick this can sometime takes a little bit longer than expected. On a PC you do not notice it while on the LEGO brick you will… One way to avoid this is to AOT (Ahead Of Time) compile the program (using the menu) from the program menu on the firmware. Another way is to call the function that take a long time to execute once to make the program JIT compile it – this way it executes fine the next time.

    /Anders

    #5010
    Author Image
    Anders Søborg
    Key Master

    Hi there

    I just tried you program, and it turns out that what you have observed

    …If I turn the engine with my hand a little bit the program continues…

    is in fact a error in the firmware that happens when you move a very small amount and the program has not been AOT compiled. I already fixed it and will create a new release tomorrow. A temporary workaround is to make the motor move a big step the first time you create a profile. I modified your program so it looks like this.

    using System;
    using System.Threading;
    using MonoBrickFirmware;
    using MonoBrickFirmware.Movement;
    using MonoBrickFirmware.Display;
    using MonoBrickFirmware.UserInput;
    
    namespace MoveMotorA90
    {
        class Program
        {
            static void Main(string[] args)
            {
                Motor motorA = new Motor(MotorPort.OutA);
                ManualResetEvent stop = new ManualResetEvent(false); 
                bool run = true;
                WaitHandle motorWaitHandle;
                ButtonEvents press = new ButtonEvents();
                press.EnterPressed += delegate 
                {
                	stop.Set();
                	run = false;		
                };
    			motorA.SpeedProfile(30, 300, 300, 300, true).WaitOne();
    			motorA.ResetTacho();
    			while(run)
    			{
    				LcdConsole.WriteLine("Position A: " + motorA.GetTachoCount());
    				motorWaitHandle = motorA.SpeedProfile(30, 15, 15, 15, true);
    				WaitHandle.WaitAny(new WaitHandle[]{motorWaitHandle, stop}); 
    			}
                motorA.Off();
    			LcdConsole.WriteLine("Position A: " + motorA.GetTachoCount());
            }
        }
    }

    Let me know how it goes…

    /Anders

    #5013
    Author Image
    Jacek S
    Participant

    Hi,

    Few days ago I was trying to fix it on my own.

    This is my version of pooling mechanism:

    
    	    private bool started = false;
    		private void PollFunction (Object source, ElapsedEventArgs e)
    		{
    			if (!Monitor.TryEnter (this)) {
    				//cancel has the lock
    				return;
    			}
    			//Do the polling
    			if (IsRunning ()) {
    			    start.Set ();
    			    started = true;
    			} 
    			else 
    			{
    			    if (started)
    			    {
    			        stop.Set ();
    			        started = false;
    			    }
    			}
    			Monitor.Exit(this);
    		}
    
    	    protected void StartPooling()
    	    {
                    waitHandle.Reset();
                    start.Set();
    		stop.Set();
    		started = false;
                    stop.Reset();
                    start.Reset();
    	        timer.Start();
    	    }
    
    		protected WaitHandle WaitForMotorsToStartAndStop()
    		{
    			//Optimize the poll function to save this exstra thread
    			(new Thread(() => {
    				start.WaitOne();
    				stop.WaitOne();
    				timer.Stop();
    				start.Reset();
    				stop.Reset();
    				waitHandle.Set();
    		    })).Start();
    			return waitHandle;
    		}
    

    And start pooling call in the speedprofile method:

    
    		public WaitHandle SpeedProfile(sbyte speed, UInt32 rampUpSteps, UInt32 constantSpeedSteps, UInt32 rampDownSteps, bool brake)
    		{
    			output.SetPower (0);
                            StartPooling();
    			output.SetStepSpeed (speed, rampUpSteps, constantSpeedSteps, rampDownSteps, brake);
    			return WaitForMotorsToStartAndStop();
    		}
    

    I also noticed that LcdConsole.WriteLine method is not thread safe. There should be lock block:

    
    		static public void WriteLine(string format, params Object[] arg)
    		{
    			if (cw == null)
    				cw = new ConsoleWriter();
    		    lock (cw)
    		    {
    		        cw.WriteLine(string.Format(format, arg));
    		    }
    		}
    

    Jacek

    #5014
    Author Image
    Anders Søborg
    Key Master

    Hi there

    I also noticed that LcdConsole.WriteLine method is not thread safe. There should be lock block:

    I don’t think this is an issue since the kernel module is thread safe. Have you seen this fail?

    And start pooling call in the speedprofile method:

    Great I will have a look at it. I actually think by looking at it that your suggestion is better than mine… I will have a look at it tonight.

    /Anders

    #5015
    Author Image
    Jacek S
    Participant

    I don’t think this is an issue since the kernel module is thread safe. Have you seen this fail?

    Yes I have seen text displayed in the same line many times, when I had a lot of threads.

    (I think the problem is with scrollPos variable)
    Jacek

    • This reply was modified 2 years, 7 months ago by Author Image Jacek S.
    #5017
    Author Image
    Anders Søborg
    Key Master

    Hi again

    Ok great – make a pull request on Git – so you can get credit for the improvements… thanks

    /Anders

    #5025
    Author Image
    Auctor137
    Participant

    Thanks a lot Anders, your code works great.
    I’ve modified it a bit, to do only 8 turns (=360degrees).

    and I’ve started another Thread about the nxt color sensor.

    #5027
    Author Image
    Anders Søborg
    Key Master

    Hi there

    I will have this issue solved in the next release – which will be soon…

    /Anders

Viewing 10 posts - 1 through 10 (of 10 total)

You must be logged in to reply to this topic.

Posted in

Make a donation