Page 1 of 2

NXC - motors synchronization

Posted: 12 Feb 2012, 08:02
by psorek
I need to turn motor OUT_A and OUT_B parallelly. Every motor has previously defined degree (signed) what i want to turn. The move must start and end in the same moment for these motors. How can i do it?

I thought about function RotateMotorEx (), but i dont understand how to use it like i wanted.

i have two variables which are needed to do it.
int x; // degree for OUT_A
int y; // degree for OUT_B


sorry about my english, i have problems with vocabulary conected with robots :)

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 13:29
by HaWe
that's not precisely possible by NXC for any combination of target values: The synch mode is rather odd.
You only can roughly do this if you choose PWM-power in relation to the number of degrees to go.
You may choose independend PWM values for 2 independend motor control functions (1 specific call for each single motor).
So because you don't need a sync mode for just 1 motor, you may better use

Code: Select all

void RotateMotor  ( byte  outputs,  char  pwr,  long  angle )

instead of RotateMotorEx .

E.g. if A has to run 3000 degrees and B has to run 4000 degrees then you could choose pwrA=60 and pwrB=80
Start both in independend RotateMotor calls:

Code: Select all

RotateMotor(OUT_A, 60, 3000);
RotateMotor(OUT_B, 80, 4000);
HTH!

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 18:37
by psorek
I am at 90% sure that RotateMotor function waits until rotation is done. It can be a problem -.-
Maybye 2 tasks with RotateMotor running paralelly?

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 18:52
by HaWe
yes, of course, if required!

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 19:08
by mattallen37
If I needed precise control of keeping two motors closely in sync, I would try using a custom P or PD controller for the differential (and add and subtract that value to and from the two motor speeds).

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 19:41
by psorek
precision is needed, because it will be a ploter.

How works RotateMotor? Does it wait until rotating is ended?

How to write this parallelly turning with tasks? Please, write an example for me :)

Code: Select all

int Mox, Moy, a;
mutex Mx, My;

task MoveX()
{
     Acquire (Mx);
     RotateMotor (OUT_B, (50*Mox)/a, abs(Mox));
     Release (Mx);
}

task MoveY()
{
     Acquire (My);
     RotateMotor (OUT_A, (50*Moy)/a, abs(Moy));
     Release (My);
}

void PenMove (int x, int y)
{
     PenPosx+=x;
     PenPosy+=y;
     x*=Cx;
     y*=Cy;
     a=max(x, -x);
     int b=max(y, -y);
     a=max(a, b);
     Precedes (MoveX, MoveY);
     Wait (100);
     Acquire (Mx);
     Release (Mx);
     Acquire (My);
     Release (My);
}
why it doesn't work (dsnt compile)

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 20:57
by mattallen37
psorek wrote:why it doesn't work (dsnt compile)
You need a main task, so the program knows where to start.

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 21:07
by afanofosc
Do you have any thoughts as to why the code you posted might not compile? What do the error messages and their line numbers tell you?

One thing for sure is every NXC program requires a task called "main" which you don't have in what you posted. That's one problem. There are many others from what I can see.

Here's an example of how to start two tasks that each rotate a single motor:

Code: Select all

int power_a;
int angle_a;
int power_b;
int angle_b;

task moveA()
{
  RotateMotor(OUT_A, power_a, angle_a);
}

task moveB()
{
  RotateMotor(OUT_B, power_b, angle_b);
}

task waitForAB()
{
  Follows(moveA, moveB);
  // do something once both have reached their destination
  PlayTone(TONE_A4, SEC_5);
  ExitTo(startMovingAB);
}

task startMovingAB()
{
  Precedes(moveA, moveB);
  // calculate the correct values for power_a, power_b, angle_a, and angle_b
  power_a = 40+Random(50);
  power_b = 40+Random(50);
  angle_a = 180+Random(3600)*sign(Random()); 
  angle_b = 180+Random(3600)*sign(Random());
}

task main()
{
  Precedes(startMovingAB);
}
The above code is completely untested and may not even compile.

John Hansen

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 21:22
by psorek
It was only part of code. I have to read about "Follows" function. I think so i know why it didn't work.

Re: NXC - motors synchronization

Posted: 12 Feb 2012, 21:46
by afanofosc
I have tried out the code I posted and with a couple minor changes it works great. You might consider using something like this approach for your plotter.

Code: Select all

int power_a;
int angle_a;
int power_b;
int angle_b;

task moveA()
{
  RotateMotor(OUT_A, power_a, angle_a);
}

task moveB()
{
  RotateMotor(OUT_B, power_b, angle_b);
}

task startMovingAB()
{
  Precedes(moveA, moveB);
  // calculate the correct values for power_a, power_b, angle_a, and angle_b
  power_a = 40+Random(50);
  power_b = 40+Random(50);
  angle_a = 180+Random(3600)*sign(Random());
  angle_b = 180+Random(3600)*sign(Random());
}

task waitForAB()
{
  Follows(moveA, moveB);
  // do something once both have reached their destination
  PlayTone(TONE_A4, MS_500);
  Wait(SEC_1);
  ExitTo(startMovingAB);
}

task main()
{
  Precedes(startMovingAB);
}
This program will randomly move A and B simultaneously at random power levels. Once both motors have reached their target the waitForAB task will start running and at the end of that task it starts up the startMovingAB task again which will choose new power levels and angle targets for OUT_A and OUT_B before scheduling the two motor movement tasks to run simultaneously again.

The RotateMotor API function calls Acquire and Release internally so there is no reason to explicitly acquire a mutex outside these function calls. Precedes and Follows are task scheduling directives rather than API commands, per se. They tell the compiler to configure the RXE executable so that the firmware's task scheduler will correctly schedule tasks to execute. The directives can be placed anywhere within a task or subroutine but they do not execute any code at runtime so their position within a routine is arbitrary. I recommend putting them at the start of the routine. If you tell the compiler that a task follows multiple other tasks then it will not execute until all of the tasks it follows have finished executing. This is a data-flow programming paradigm. All the required inputs to a routine must be available before the routine will begin to execute. The ExitTo routine allows you to at runtime tell the task scheduler to exit the current routine and schedule the specified routine to begin execution.

John Hansen