Can't drive straight forward

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Can't drive straight forward

Post by HaWe » 13 Dec 2010, 18:39

I think that that the algorithm that syncs the NXT motors might only work if you leave the speed beneath 100%
that's a good point.
IIRC I think I've read sth like this already in a nxtasy thread before.

PS: in Robotc I once had this "jerkiness" problem too. If one added
nPidUpdateInterval = 15;
to the task main, this problem could be healed. I'm not sure if a command like this exists in NXC as well.

airblader
Posts: 10
Joined: 11 Dec 2010, 11:33

Re: Can't drive straight forward

Post by airblader » 13 Dec 2010, 18:53

Hey guys,

sorry the answer took so long. For one reason I wanted to test it first, but also I had problems with the forum. Whatever, it works at the moment.
First of all thanks for the answer(s). That really seems to be the problem. I'll just stay beneath 100%, that seems to work (and makes sense).

However, I have a few additional questions on which I'd really appreciate your help. First of all, at the moment I am using two functions like this:

-- first question cancelled --

The second problem is this: I'd like to have a function to drive a curve while still driving forwards. For that I'm thinking of parameters for the (resulting) angle, a forward speed and the speed of how fast it turns. My first attempt was this:

Code: Select all

void __driveFwdCurveRight (long angle, int forward_speed, int curve_speed) 
{ 
 Acquire (mWheel); 

 RotateMotorEx (WHEEL_BOTH,                                                     // start motors with turn ratio depending on curve speed 
                forward_speed, 
                angle * __deg_ratio, 
                curve_speed, 
                TRUE, TRUE); 
  
 Release (mWheel); 
}
However, this happens way too fast (which I expected). Is there even a way to do it with RotateMotorEx or should I switch to OnFwdSync and use Wait commands? Also, in general .. is it a good idea to use RotateMotorEx for driving straight forward? I use it to make a function that allows me to have the distance (in mm or cm) I want to drive forward as the parameter. Of course I could also try using OnFwdSync and wait commands and just do some tests on how long the pause would have to be.

Thanks so far for everything and also thanks in advance!

air

HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Can't drive straight forward

Post by HaWe » 13 Dec 2010, 19:46

I'm not sure if I understand your question correctly, but if you want to drive forward, the turnpct (syncratio) =100 (both same speed forward)
and if you want to turn on the stop, turnpct=-100,
and if you want to drive a curve, it's supposed to be something in between...
(...or what was actually your question...)

Code: Select all

void RotateMotorEx  ( byte  outputs,  
  char  pwr,  
  long  angle,  
  char  turnpct,  
  bool  sync,  
  bool  stop   
 )   [inline] 

Rotate motor. 

Run the specified outputs forward for the specified number of degrees.

Parameters:
... 
turnpct      Turn ratio, -100 to 100. The direction of your vehicle will depend on its construction. 
sync         Synchronise two motors. Should be set to true if a non-zero turn percent is specified 
             or no turning will occur. 
... 
The "angle" in the parameter list is the relative encoder number (I had prefered to use the latter term instead of "angle" which is not intuitively to understand).

But the arc "angle" of your circle you want to drive depends on the distance between the wheels and the wheel size (and the sync ratio).
Do you need the trigonometric formula to calculate the turn angle or the driven arc?

If you want to drive your robot unlimited in a curve you need to use OnFwdSync instead (with the correct sync ratio).

Again, I'm not sure what is the essence of your question...

airblader
Posts: 10
Joined: 11 Dec 2010, 11:33

Re: Can't drive straight forward

Post by airblader » 13 Dec 2010, 20:51

Hi,

thanks. I'm studying math, so I think I'll be fine when it comes to trigonometric functions or similar things, thank you. ;)
Before I go further into explaining I think I will just test some things out. Might be more to learn by that anyway. I'll also compare using RotateMotorEx and OnFwdSync. One difference I see at the moment is that apparently there is no way to use RotateMotorEx and keeping the robot driving .. executing two following RotateMotorEx commands always results in the motors stopping in between.

I guess I will use RotateMotorEx for the movement of the project to get out of the way of obstacles and OnFwdSync for the line follower part of the task. For now I think all my questions has been answered and if there'll be new ones I'll know where to ask.

Thanks a lot!

air

linusa
Posts: 228
Joined: 16 Oct 2010, 11:44
Location: Aachen, Germany
Contact:

Re: Can't drive straight forward

Post by linusa » 14 Dec 2010, 00:32

airblader wrote: Before I go further into explaining I think I will just test some things out.
It might help to know what you're trying to do. Sometimes questions point into the wrong direction (or not the best one), without us realizing.

I'm just asking: You want to drive straight lines and apparently also curves? Does the driven distance have to be precise (as in: how many degrees do I want to drive)?

The thing is: TurnRatio (NXC calls it turnpct) does work ok for curves, but we had someone testing the whole feature, and rejected it after careful evaluation. 0 is for straight lines, and -100 to 100 are curves (-50 and 50 should make one or the other wheel stop). This doesn't work perfectly, or at least not reproducible every time it seems. On the other hand, small values between 1 and 20 should make nice curves, try it.

If you find time, read the NXC Guide, section about motors / "output module". Another important recommendation: Get the document "Executable File Specification" of the LEGO Mindstorms NXT SDK. They have a section about motor commands and parameters that helps as well. http://mindstorms.lego.com/en-us/suppor ... x#Advanced
airblader wrote:I'll also compare using RotateMotorEx and OnFwdSync. One difference I see at the moment is that apparently there is no way to use RotateMotorEx and keeping the robot driving
OnFwdSync is just a wrapper for a certain set of SetOutput commands. This combo doesn't support a TachoLimit, so you don't have precise motor movements like "drive 1000 degrees".

RotateMotorEx is basically an OnFwdSync command, followed by a loop that monitors the TachoCount (motor position) until the target is reached. Then the brakes are jammed in. Regarding your older question: No, I wouldn't use the OnFwdSync and Wait commands, it's just not precise enough.

If you want to see some examples how you can use the various SetOutput parameters, here are some examples: http://www.mindstorms.rwth-aachen.de/tr ... ctions.nxc . This is not necessary of course, but it may help to understand how the motor internals of the firmware work.
airblader wrote: .. executing two following RotateMotorEx commands always results in the motors stopping in between.
This is "by design", at least the (simple) way RotateMotorEx was developed.

What do you want to change "during runtime" with the second motor command? Can you join the commands to one single command? If so, then do it.

Or do you want to drive an "8-shaped figure" on the floor? I've done that once. You can try to update certain motor values (like TurnRatio) during runtime using the SetOutput command, but it might get "buggy" then.
RWTH - Mindstorms NXT Toolbox for MATLAB
state of the art in nxt remote control programming
http://www.mindstorms.rwth-aachen.de
MotorControl now also in Python, .net, and Mathematica

airblader
Posts: 10
Joined: 11 Dec 2010, 11:33

Re: Can't drive straight forward

Post by airblader » 14 Dec 2010, 21:32

Hi,

thanks for your reply.
I'm just asking: You want to drive straight lines and apparently also curves? Does the driven distance have to be precise (as in: how many degrees do I want to drive)?
Yes, that is what I want to do. And well, precision is never a bad thing to have, is it? ;) However, most of the times we might be able to fix unprecise driving by using our sensor values. The thing I do want to achieve however is this: Imagine driving the robot down a street. Now an obstacle (f.ex. a standing car) is in the way (detected by the lowspeed sensor), so I need to steer left to drive by it. One way would be to stop, turn left, stop, drive forward, stop, turn right, drive forward, stop, turn right, drive forward, stop, turn left and drive forward. However, this does cost tons of time and since it's a competition it'll be about time. So a much more effective way would be to detect the obstacle and without stopping just turning a smooth curve to the left, drive by it and after the obstacle turn back in again with a smooth curve and without stopping.
For that matter I am going to try updating the flags by using the SetOutput command. However, this might take a while since having a working version is more important at the moment. Improving details like this shouldn't be the task with the highest priority at the moment, because a smooth curve doesn't help if we don't even finish the lap. ;) But I might just try some things in my spare time.
RotateMotorEx is basically an OnFwdSync command, followed by [..]
That's interesting. Does it mean RotateMotorEx internally calls OnFwdSync which itself calls SetOutput? Would you recommend fully working with SetOutput myself to get better results (meaning: are the built-in commands that crappy?)?
Or do you want to drive an "8-shaped figure" on the floor? I've done that once. You can try to update certain motor values (like TurnRatio) during runtime using the SetOutput command, but it might get "buggy" then.
As described above, that basically is what I want to do, yes. It's not like there is much of a difference between 8-shaped figures and smooth curves in general. I might take a look at updating motor values using SetOutput. It seems like some work, but some work that might be worth the time. However, I'd appreciate if you could say anything about what kind of "buggy" you mean? What problems can it cause?

Another thing:
Today we built our robot using the design ideas we had. However, the robot is very asymmetrical (but that's needed for the task we have to achieve). The funny thing is: Using OnFwdSync (with OUT_REGMODE_SYNC) makes it drive a curve again (likely because of the asymmetry) .. instead of driving straight forward. But using RotateMotorEx works absolutely fine. That appeared to be interesting to me, especially after you now mentioned that RotateMotorEx basically is a OnFwdSync command.

Thanks again, I really appreciate your help.

air

linusa
Posts: 228
Joined: 16 Oct 2010, 11:44
Location: Aachen, Germany
Contact:

Re: Can't drive straight forward

Post by linusa » 15 Dec 2010, 00:35

airblader wrote: Yes, that is what I want to do. And well, precision is never a bad thing to have, is it? ;)
No, of course not. I know it sounds silly I asked that. In this case, the problem is that you have to take care of "precise braking" yourself if you don't want to use RotateMotor. Now we can try to figure out if it's worth it for you to do something else / more advanced.
airblader wrote: ...
However, this does cost tons of time and since it's a competition it'll be about time. So a much more effective way would be to detect the obstacle and without stopping just turning a smooth curve to the left, drive by it and after the obstacle turn back in again with a smooth curve and without stopping.
This is going to be really really tough. I think I wouldn't recommend doing it. In my experience, the curve driving works empirical: You set some value, you see if it's the curve you want, and you keep that setting. Changing this on the fly or trying to understand how this TurnRatio exactly works will be difficult. We tried that, and we couldn't really find a formula or understand how this works. LEGO say they interpolate from 0 (both wheels spin equally fast), to 50 (one wheel spins, other is stopped), to 100 (both wheels spin in opposite directions). 0 works (driving straight line), but 50 doesn't all the time, and the whole thing doesn't seem linear.

The really cool and advanced thing which might be VERY promising (and since your working with control theory anyway): Code your own (PID) controller, but power the wheels independently on your own (without speed regulation, without sync). This way you can make your own sync, and your own turn ratio. Unfortunately, that'll be quite some development time.
airblader wrote: However, this might take a while since having a working version is more important at the moment. Improving details like this shouldn't be the task with the highest priority at the moment, because a smooth curve doesn't help if we don't even finish the lap. ;) But I might just try some things in my spare time.
Sure, as always :-)
airblader wrote: For that matter I am going to try updating the flags by using the SetOutput command.
airblader wrote: Does it mean RotateMotorEx internally calls OnFwdSync which itself calls SetOutput? Would you recommend fully working with SetOutput myself to get better results (meaning: are the built-in commands that crappy?)?
Ok, it basically works like this:
The firmware checks the output module map every tick (= 1ms). This map is basically just some variables / registers. Depending on what params are set, the motors are operated (and regulated). So you can set a new power value, and then have to set the "UPDATE_POWER" flag. 1 ms the firmware realizes this, and acts accordingly. So, at the lowest level, it's always about these motor registers. And they are set via SetOutput. Be careful: Don't overwrite your own flags. Sometimes a Wait(1) is needed to "commit" a setting.

OnFwd* commands are macros / convenient calls to certain parameter combos (which are set, as mentioned, with SetOutput).

Now, RotateMotor is uses the same motor fields. If RotateMotor uses OnFwd or SetOutput, I don't know, I'd guess SetOutput. But in the end it's all the same. RotateMotor is blocking as you've noticed. It's a macro / function, which starts a motor and then monitors it inside a loop (so by stalling a motor, you can keep your program (or at least your task) inside this loop).

Here you can see a log of how RotateMotor works: http://www.mindstorms.rwth-aachen.de/tr ... tateEx.png

You can see the different runstates and regmodes. Note the oscillations: Once the TachoLimit is reached, the brakes are enabled, leading to a very hard stop (not nice). Braking is just SetOutput with runstate RUNNING and regmode SPEED and power = 0.

This is btw. the same thing the NXT-G "MotorBlock" does: http://www.mindstorms.rwth-aachen.de/tr ... _NoReg.png

Only the NXT-G "MoveBlock" uses the RAMPDOWN runstate: http://www.mindstorms.rwth-aachen.de/tr ... eBlock.png . Similar pictures were posted by gloomyandy a couple of days ago in a thread "Motor Control" I think. But sorry, I disgress, that's not important right now.


As you said, you should do some more tests and focus on the basics. My overall experience was: "doing things on your own" helps, as in: "don't trust the firmware regulating your motors". On the other thing, that's a very complicated, big task.
airblader wrote:
Or do you want to drive an "8-shaped figure" on the floor? I've done that once. You can try to update certain motor values (like TurnRatio) during runtime using the SetOutput command, but it might get "buggy" then.
As described above, that basically is what I want to do, yes. It's not like there is much of a difference between 8-shaped figures and smooth curves in general. I might take a look at updating motor values using SetOutput. It seems like some work, but some work that might be worth the time. However, I'd appreciate if you could say anything about what kind of "buggy" you mean? What problems can it cause?
The "figure 8" I was driving on the floor was static. All I had to do was switch directions when one circle was done, to get the other circle. (so 8 = OO basically ^^). Dynamically adjusting TunRatio etc. "on the fly" is another thing.

With "buggy" I mean: Driving in sync means sending two SetOutput commands, one for each motor. You set certain flags, and then commit the settings. The motors start running. If you just set new values, the firmware won't accept it. You have to reset certain counters and turn off the motors in between (something like a "soft restart"), otherwise your robot will dance :-). Honestly. The firmware's internal error corrections will "rewind" the difference in distance of the two wheels, it's all crazy. So you have to reset the BlockTachoCount. All manageable, not a problem. The thing is: During this short "dead spot" of the motors (couple of ms), they keep on spinning. You commit the new commands, and it's not a very nice smooth movement anymore. You can do it, but in my experience: Some strange effects, lots of experiments necessary, the occasional "duh?" moment, etc.

Anyway, I don't want to discourage you AT ALL. Please, try it. You have more information to start with now than I had years ago, that could make a difference. Maybe I simply "didn't get it" or something, or I wanted to try different things. I don't want to sound too negative. I'm just trying to tell you what's "most time consuming" from my point of view.
airblader wrote: Another thing:
Today we built our robot using the design ideas we had. However, the robot is very asymmetrical (but that's needed for the task we have to achieve). The funny thing is: Using OnFwdSync (with OUT_REGMODE_SYNC) makes it drive a curve again (likely because of the asymmetry) .. instead of driving straight forward.
I don't get that. Yes, asymmetry might be a problem, but that's what SYNC is for. On the other hand, if you neither use SYNC nor SPEED, the motors run more stable (not regulated, but with a constant power).

Since both commands just use certain SetOutput parameters, they SHOULD be the same, yes. But you have to really find out what state your motors are in.

If you have access to MATLAB, try our toolbox. It comes with a tool called GUI_WatchMotorState. This will monitor your Output flags during runtime, even while an NXC program is running. You can watch what's happening in realtime. This looks like this:
http://www.mindstorms.rwth-aachen.de/tr ... rState.png

There might be similar tools in BricxCC. I don't have an NXT right now and can't test, but check the "Tools" menu in BricxCC, maybe this will help too.

Right now, looking at your results, it's impossible that both commands do the same, since you see different results...

airblader wrote: Thanks again, I really appreciate your help.
cheers 8-)
RWTH - Mindstorms NXT Toolbox for MATLAB
state of the art in nxt remote control programming
http://www.mindstorms.rwth-aachen.de
MotorControl now also in Python, .net, and Mathematica

airblader
Posts: 10
Joined: 11 Dec 2010, 11:33

Re: Can't drive straight forward

Post by airblader » 16 Dec 2010, 10:32

Hi,

sorry it took some time, but I was (better to say: am) sick and stuff.

Well I am far away from creating my own PID controller or anything. So I'll just drop the idea of smooth curves for the moment and focus on stopping in between but making the turns and stuff as accurate as I can get them to be. I already implemented the "soft start" feature (didn't have the time to really test it yet though, but it seems promising). Since I just don't have an opportunity I did it by using OnFwdSync for the soft start and then go into RotateMotorEx, so it looks like this:

Code: Select all

void rot_driveFwd (long dist, int speed, bool safe_start = TRUE)
{
 Acquire (mWheel);
 
 if (safe_start && (speed >= 25 || speed <= -25))
 {
  for (int i = 1; i <= 4; i++)
  {
   OnFwdSync (WHEEL_BOTH, i * (speed / 4), OUT_REGMODE_SYNC);                   // set motors moving increasingly
   Wait (safe_start_interval);
  }
 }
 
 RotateMotorEx (WHEEL_BOTH,                                                     // rotate both motors
                speed,
                dist * _rot_mm_ratio,
                0,
                TRUE,
                TRUE);
 
 Release (mWheel);
}
However, using this won't give me the chance to do an "soft brake", because the RotateMotorEx command is going to hit the brakes .. except I set the last parameter to FALSE. But I don't think I'll need it anyway, at least I didn't experience the robot turning a little when braking. He might just move a little bit too far, but there is absolutely no problem with that.
And when it comes to precide 90° turns I don't need such a feature either. It would depend on the floor way too much anyway. Just not turning too fast should be enough here. The rest will be managed by using the lowspeed sensor to keep track of the distance to the wall, so I can get it to drive by an obstacle without moving away or anything.

Still, I feel like this solution to it isn't very nice at all. You think it will be worth doing it by just using SetOutput (and increasing the speed with this command, too) instead of this OnFwdSync+RotateMotorEx combination?
Anyway, I don't want to discourage you AT ALL. Please, try it. You have more information to start with now than I had years ago, that could make a difference. Maybe I simply "didn't get it" or something, or I wanted to try different things. I don't want to sound too negative. I'm just trying to tell you what's "most time consuming" from my point of view.
I get that. And if this set was mine you could bet I'd try all those things myself, too. However ... it's not mine, I just have it for the competition. There is no time to go into low-level programming experiments and I just rely on my intuition, the nxc guide and what more experienced people tell me. ;) I'm pretty sure that it's *very* unlikely for me trying those things and have a big epiphany you didn't have after a short time. :D

Since I study math I do have MatLab (we get it for free from the university), however, I'm not a too big of a fan of it *cough* :D I was surprised that OUT_REGMODE_SYNC and RotateMotorEx (with sync=TRUE) led to completely different results, too. However, I'll take a closer look to that once I feel better and have the time to. If someone would have asked me before I tried it, I would have said it's more likely that RotateMotorEx screws it up while OnFwdSync should get it to drive straight. It really was a surprising result. Since it was just a small test it might not even be correct. I'll try it again to make sure.

So, sorry I don't have new results or anything. As I said, I'm sick at the moment so I can't do much. However, I didn't want to not reply for a too long time. Just saying: I'm still here, even if it takes some time for me to respond. ;)

Edit: By the way .. at the moment I'd like to beat up whoever was responsible for developing the (rechargeable) battery of the NXT. We had built our robot, now we got the battery charger (and the CD), so I wanted to put in the rechargeable battery instead of a bunch of AA batteries, but it makes the nxt computer bigger .. so I had to change the comple layout of the robot. *sigh. Really, who developed a battery that makes the computer bigger than using single batteries? ;)

air

Post Reply

Who is online

Users browsing this forum: No registered users and 10 guests