Hey Duane, I seem to be having an issue with the robot autodriving sometimes. I tried to comment out some things that I thought might be causing it to start on its own and also I changed the couple things you had mentioned that might cause the autodriving from earlier posts but it still seems to start up sometimes by itself.
Here are some things I commented out to try and make it stop:
This whole function I commented out basically
PRI AutoDrive(localCommand, localIndex)
InputNoticed
'previousThrottle := channel[Control#THROTTLE_CHANNEL]
{ if keyboardFlag
'InputNoticed
'Bot.RefreshSpeeds
elseif inputFlag }
' if keyboardFlag == 0 and inputFlag == 0 ' auto mode //might need this
' globalIndex := localIndex
' repeat
' if InputNoticed
' quit
' if localCommand == TURN_COMMAND
' Bot.Turn(speed, turnRate)
' elseif localCommand == STRAIGHT_COMMAND
' Bot.Straight(speed)
' result := ||(previousThrottle - channel[Control#THROTTLE_CHANNEL])
' while globalIndex > 0 and throttleChangeFlag == 0
' previousThrottle := channel[Control#THROTTLE_CHANNEL]
'if throttleChangeFlag and cnt - throttleTimer > ignoreThrottleInterval
' throttleChangeFlag := 0 //till here might need this
{PUB OmniLoop | localIndex, localRotation, previousGIndex
' repeat while keyboardFlag == 0 and inputFlag == 0 ' just do loop once
' AutoDrive(STRAIGHT_COMMAND, Header#REFRESH_RATE / 2) '** don't really like this
I had changed the keyboard flag to 1 like you had said in a previous post. Not sure what else it could be.
Now on to the fun stuff. Here is the code I have added to accept my serial stuff from Arduino
Parallax Code:
repeat
if Pst.CharIn == "!" 'Starting Char
case Pst.CharIn '-1000 to 1000 Speeds
"W":
Bot.Straight(300) 'Positive Straight
"D":
Bot.SideWays(500) ' Positive Right
"X":
Bot.Straight(0) ' Stop
"S":
Bot.Straight(-500) 'Negative Backwards
"A":
Bot.SideWays(-500) ' Negative Left
"Q":
Bot.StrBreakLeft(300)'StrBrake Left
"E": 'StrBrake Right
Bot.StrBreakRight(300)
"Z": 'SideBrake Left
Bot.SideBreakForward(300)
"C": 'SideBreak Right
Bot.SideBreakRear(300)
"F": 'Turn Left
Bot.TurnLeft(300)
"G": 'Turn Right
Bot.TurnRight(300)
Here is stuff from the fourmotor encoder file
PRI StraightPrivate
repeat result from 0 to HIGHEST_MOTOR_ID
long[targetPtr][result] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD ' since target speeds have now been set
//all of these are for error correction if using a compass or in our case we are using two ultrasonics to stay parallel to a wall. We decided that we would need to break certain sets of wheels to correct if it was veering off //course. There might be a better way to do this not sure yet.
PRI StrBreakLeftPrivate
long[targetPtr][0] := globalSpeed * 0.9
long[targetPtr][1] := globalSpeed * 0.9
long[targetPtr][2] := globalSpeed
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI StrBreakRightPrivate
long[targetPtr][0] := globalSpeed
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := globalSpeed * 0.9
long[targetPtr][3] := globalSpeed * 0.9
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI SideBreakForwardPrivate
long[targetPtr][0] := -globalSpeed
long[targetPtr][1] := globalSpeed * 0.9
long[targetPtr][2] := -globalSpeed * 0.9
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI SideBreakRearPrivate
long[targetPtr][0] := -globalSpeed * 0.9
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := -globalSpeed
long[targetPtr][3] := globalSpeed * 0.9
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI MainLoop
'' This loop runs in its own cog. Control of object is done
'' by setting the variable "command" through public methods.
repeat
case command
SIDEWAYS_CMD:
SideWaysPrivate
STRAIGHT_CMD:
StraightPrivate
TURN_CMD:
TurnPrivate
TURNRIGHT_CMD:
TurnRightPrivate
TURNLEFT_CMD:
TurnLeftPrivate
STRBREAKLEFT_CMD:
StrBreakLeftPrivate
STRBREAKRIGHT_CMD:
StrBreakRightPrivate
SIDEBREAKFORWARD_CMD:
SideBreakForwardPrivate
SIDEBREAKREAR_CMD:
SideBreakRearPrivate
INDIVIDUAL_CMD:
SetSpeedsPrivate
'other: 'NO_NEW_CMD
Now my arduino code is just serial commands that I send:
Serial.print('!'); //this is to make sure parallax knows its an actual movement command
Serial.print('W'); //this would just cause it to go forward at a certain speed.
at the moment I dont have it taking speed and direction commands I just hardcoded those because the serial seemed to be to slow to turn on all four wheels at once, I could have probably created a buffer to store each command that came in and then pass it to the functions above.
It's great you're modifying the code to suit your needs.
As you may know, Spin uses indentation as part of its syntax. The forum software removes the indentation unless you use code tags. They're easy to use, but I'll let Phil explain how to use them in the following link.
As I mentioned before, there are still lots of bugs in the code. I didn't really feel like it was ready to be released but I thought having something was better than nothing.
I'm still working on improving the encoder code to measure the time between encoder pulses instead of just counting encoder pulses within a set time period. Counting pulses works fine when the robot is moving fast, but at slow speed, there aren't enough encoder ticks per 1/50 second refresh period to accurately gauge speed. The guy who designed the Rover 5 suggested I measure the time between pulses to increase the low speed accuracy. I think this should work well but it takes some time to get the kinks worked out.
Once I have the encoder stuff worked out, I'm going to try to make the code work better when used as a slave.
You mentioned using a compass. What kind of compass are you using?
What kind of ultrasound sensor(s) are you using?
Even though I intend to use a compass and ultrasound with my robot, I'm not sure if it would be helpful to include these devices as part of the slave code. It might be better to have the master board monitor sensors directly but I'm not sure.
You may find, once you learn enough Spin, that you can do everything you need done with just the Propeller and not need the Arduino at all. IMO, the Propeller is a great microcontroller to know how to use if one is interested in robotics.
Here is the reposted code in a nicer format thanks for the tip!
Here is the stuff I have added so far
repeat
if Pst.CharIn == "!" 'Starting Char
case Pst.CharIn '-1000 to 1000 Speeds
"W":
Bot.Straight(300) 'Positive Straight
"D":
Bot.SideWays(500) ' Positive Right
"X":
Bot.Straight(0) ' Stop
"S":
Bot.Straight(-500) 'Negative Backwards
"A":
Bot.SideWays(-500) ' Negative Left
"Q":
Bot.StrBreakLeft(300)'StrBrake Left
"E": 'StrBrake Right
Bot.StrBreakRight(300)
"Z": 'SideBrake Left
Bot.SideBreakForward(300)
"C": 'SideBreak Right
Bot.SideBreakRear(300)
"F": 'Turn Left
Bot.TurnLeft(300)
"G": 'Turn Right
Bot.TurnRight(300)
and from the fourmotors file
PRI MainLoop
'' This loop runs in its own cog. Control of object is done
'' by setting the variable "command" through public methods.
repeat
case command
SIDEWAYS_CMD:
SideWaysPrivate
STRAIGHT_CMD:
StraightPrivate
TURN_CMD:
TurnPrivate
TURNRIGHT_CMD:
TurnRightPrivate
TURNLEFT_CMD:
TurnLeftPrivate
STRBREAKLEFT_CMD:
StrBreakLeftPrivate
STRBREAKRIGHT_CMD:
StrBreakRightPrivate
SIDEBREAKFORWARD_CMD:
SideBreakForwardPrivate
SIDEBREAKREAR_CMD:
SideBreakRearPrivate
INDIVIDUAL_CMD:
SetSpeedsPrivate
'other: 'NO_NEW_CMD
PUB TurnRight(localspeed)
globalSpeed := localSpeed
command := TURNRIGHT_CMD
PUB TurnLeft(localspeed)
globalSpeed := localSpeed
command := TURNLEFT_CMD
PUB StrBreakLeft(localspeed)
globalSpeed := localSpeed
command := STRBREAKLEFT_CMD
PUB StrBreakRight(localspeed)
globalSpeed := localSpeed
command := STRBREAKRIGHT_CMD
PUB SideBreakForward(localspeed)
globalSpeed := localSpeed
command := SIDEBREAKFORWARD_CMD
PUB SideBreakRear(localspeed)
globalSpeed := localSpeed
command := SIDEBREAKREAR_CMD
PRI SideWaysPrivate
long[targetPtr][0] := -globalSpeed
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := -globalSpeed
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI TurnRightPrivate
long[targetPtr][0] := globalSpeed
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := -globalSpeed
long[targetPtr][3] := -globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI TurnLeftPrivate
long[targetPtr][0] := -globalSpeed
long[targetPtr][1] := -globalSpeed
long[targetPtr][2] := globalSpeed
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI StrBreakLeftPrivate
long[targetPtr][0] := globalSpeed * 0.9
long[targetPtr][1] := globalSpeed * 0.9
long[targetPtr][2] := globalSpeed
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI StrBreakRightPrivate
long[targetPtr][0] := globalSpeed
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := globalSpeed * 0.9
long[targetPtr][3] := globalSpeed * 0.9
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI SideBreakForwardPrivate
long[targetPtr][0] := -globalSpeed
long[targetPtr][1] := globalSpeed * 0.9
long[targetPtr][2] := -globalSpeed * 0.9
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI SideBreakRearPrivate
long[targetPtr][0] := -globalSpeed * 0.9
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := -globalSpeed
long[targetPtr][3] := globalSpeed * 0.9
SetSpeedsPrivate
command := INDIVIDUAL_CMD
Yes I definitely agree that the parallax is probably going to become one of my goto boards now that I am starting to get familiar with it. At the moment I just dont know enough about the syntax
to code with the parallax unfortunately to add all of the things I want to add. I am using ping parallax ultrasonics to measure my distance and also using two one one side to stay parallel with a wall.
Also when we were trying to write our first PID we would use the time in between pulses of the encoder to compare to a master wheel. Therefore if one wheel was going faster then another
we were able to tell because the pulses on the master wheel would be much higher etc. We decided to just use the ultrasonics to keep parallel due to compass restrictions of EMF.
We have a lot of electronics and we have a height restriction on how big the robot can be, so the pole idea that I saw in your video might not work as good.
Also if you plan to add sensors and what nots it might be better to use it on whatever your master board will be. Serial seems to be a huge pain when trying to send and receive information.
Do you have any ideas what code might be causing the robot to spaz out sometimes on its own?
Yes I definitely agree that the parallax is probably going to become one of my goto boards
"Parallax" or "Parallax Inc." is the company that sells several different microcontrollers. The Propeller is one of these microcontrollers. Calling the chip or board "Parallax" sounds funny IMO. Not a big deal, but I thought I'd mention it.
At the moment I just dont know enough about the syntax
to code with the parallax unfortunately to add all of the things I want to add.
I used C a lot on a PC before I started using Spin on the Propeller. Initially I was disappointed the Propeller didn't use C. It didn't take long for me to prefer Spin over C. There are several versions of C for the Prop but I much prefer Spin now so I haven't switched over to using C.
I am using ping parallax ultrasonics to measure my distance and also using two one one side to stay parallel with a wall.
Pings are nice since they only need one I/O line. The downside to Pings is their price. There are lots of inexpensive ultrasound sensors that work great but use separate echo and trigger pins. The echo lines of multiple sensors can be combined so it's possible to use four sensors with five I/O pins.
Also when we were trying to write our first PID we would use the time in between pulses of the encoder to compare to a master wheel. Therefore if one wheel was going faster then another
we were able to tell because the pulses on the master wheel would be much higher etc.
The object "FourMotorsAndEncoders" does this for you. You just set the target speed and the program increases the PWM or decreases the PWM to bring the wheels to the desired speed. Try setting the speed of one of the wheels and then try to slow the wheel with your hand. The motor will fight your attempt to slow the wheel.
The control algorithm only uses proportional control. My attempts to add integral or differential didn't improve the motors' behavior. The proportional algorithm is in the "ComputeP" method of the "FourMotorsAndEncoders" object. If you wanted to try to added I. and D. to the P. that's the method to do it. Keep in mind the program uses a timed loop of 20ms so your PID algorithm can assume a constant time period between each update. This is assuming you attempt your PID in the Propeller. Trying to run your PID algoritm from the Arduino will be problematic because of the increased latency from serial signals.
We decided to just use the ultrasonics to keep parallel due to compass restrictions of EMF.
We have a lot of electronics and we have a height restriction on how big the robot can be, so the pole idea that I saw in your video might not work as good.
The pole I used was much taller than needed. It was just used the first, relatively short, piece of carbon fiber rod I found. I'll probably use a shorter rod in the future.
Also if you plan to add sensors and what nots it might be better to use it on whatever your master board will be.
In my case the QuickStart is the master board. I was wondering if it would be beneficial to include sensor information as part of the slave component of the program. I'll probably make sensor information an option if it's not hard for me to include it as part of the slave code.
I didn't write the program with the intention of having it be used on a slave board. It was just after the fact that I realized there were already aspects of the code that would allowed another uC to control it.
Serial seems to be a huge pain when trying to send and receive information.
Actually, it's very, very common to have robot components controlled with a serial connection. The Dynamixel robot servos all use a serial interface. I don't think the serial connection itself is the problem here, I think it's one of both of our codes causing the problem.
Do you have any ideas what code might be causing the robot to spaz out sometimes on its own?
No, it's very possible there's something in the code I posted causing the problem but I'm not completely convinced the problem is on the Propeller side of the setup.
As I've said, I'm still working on the code and there's lots of things about it that will be changing.
Thanks for the info duane, I will keep looking into whats causing the robot to auto move. Maybe its picking up junk in the serial? But it woud be odd to pick up a '!' and then character right after that would cause it to move from my functions. I know you had some code that would cause it to automove when it had not received any input after a set amount of time. But I thought I commented most of that out from mainloop in demo4wd. Im sure the serial issues I am having is due to the way I am handling the commands being received since I can't at the moment code in my own buffers to store and parse the info coming in I am just relying on the propeller buffer.
Also yes I know the propeller board not parallax SEMANTICS I SAY!!!!!
Yes I enjoy C, I eally would like to learn python one day. Spin seems interesting OOP and will most likely start using it more. Arduino has huge limitations when it comes to speed.
So I got the ghost to stop finally lol. We are now having it follow walls very good with some new code we wrote. The serial seems to be responding great to just single or double character inputs. like 'W' or "!W". Our computer vision is working but very slow at the moment only 2fps so we are trying to figure out how to get it to work faster. I will post some videos soon as we get more testing in.
I finally made some progress with the next phase of the Rover 5-controlling Java program that runs in my laptop.
I wanted to create a mapping between a given PWM value sent to the motors, and the resulting EncoderCounts/sec. that they output. To have a better chance of ending up with an observable, repeatable curve, I did 11 test runs, running through PWM values of 30-255 each time.
As you can see below, each run has various odd gaps and shifts, which I'm imagining are due to my evolving data collection methodology (I had 50-100 hours of opportunities to evolve it, ugh), and perhaps related to the battery voltage differing for each test run, and decreasing during each one as well:
Right now I'm thinking that these plots are such a mess, that they are mostly just a strong endorsement for using PID to monitor/vary the PWM value to achieve a desired the EncoderCounts/sec. value, rather than trying to set any particular PWM value and praying that that will ever result in any reproducible EncoderCounts/sec. result.
My initial thought for a next step to implement is to fit a curve through the above data, and use the resulting (PWM,EncoderCounts/sec.) pairs as a starting point upon which to base a PID implementation.
I think the main problem I see to your approach is the PWM required to move at any particular speed will vary widely based on the load on the motors. Different surfaces will cause different amounts of resistance to movement. I think forward movement will produce a different load than sideways movement.
I think you're better off with some sort of proportional feedback loop. I doubt you'll need full PID.
How many volts where you using with your tests? How long was the sample time when measuring the speed?
The third graph looks like you were missing encoder pulses. Where you monitoring both encoder lines or did you monitor one pin of the encoders "or"ed together?
The first two graphs looks like you had a sampling time issue where your sampling time wasn't long enough to come up with a good average.
I suppose someone well versed in control theory could use your data to partially tune a PID algorithm but the graphs don't give information about change over time. I think you're making this harder than it needs to be. I think a good control algorithm would take care of adjusting the PWM for you. While I think it's interesting to see your PWM vs speed graph I don't think it's needed to come up with a control algorithm.
Have you figured out a way of monitoring the encoders with your control board? I think I remember you were having trouble with the number of interrupts you were receiving?
I don't think there is an accurate way to measure distance by the encoder values due to slippage. The way we moved around precisely was with ultrasonic sensors using surrounding walls. The meccanum wheels are great for traction but there is always going to be error in the encoder readings due to when the motors are changing directions etc.
Here is what our final robot looked like, Thanks again duane for all your help with the PID. The beagle board XM was used for computer vision, the arduino for serial control of the motors, communication with beagle and other sensors(ultrasonics, IRs, arm Servos) and the propeller for motor control PID.
As there is lot of slipping in mecanum wheels due to one point contact how you were getting correct encoder values using internal encoders?
There will be a lot of error in the encoder values due to slipping.
Is there any way to reduce this error?
I know you're not the first one to worry about this. Post #44 of this thread has a link to an article about using an optical mouse type sensor to compute position. Parallax sells a sensor that should work well in the application.
I haven't used the encoders for anything other than speed control with this robot so far. I haven't tested how accurate the odometry using the encoders is yet. I'd imagine the odometry would be more accurate when the robot is travelling more like a conventional robot straight forward or straight back. I'd think the sideways motion would produce the most error. Again, these are just guesses since I haven't measured these values myself.
Will be posting a video of it, I will try to find one from the competition. Although the computer vision failed horribly at the competition lol. The lighting was just not on our side.
@amano001 and @duane
about getting distance using encoders.
1.What if we use external encoders instead of internal motor encoders? will it help?
2. @amano001 we made a simple bot with maxons having internal encoders and tried to move it in straight line. But it always use to deviate by some 5-10 cms. we were not particulary concerned with the distance but we wanted it to move in straight line, but we couldn't achieve it perfectly.
What do you mean by "external" encoders? If you mean encoders on the wheels themselves then no, it wouldn't help.
When you say it would deviate by 5-10 cm, what distance did you travel? What kind of surface? What kind of wheels(Mecanum?, size, material)? What kind of encoders (how many ticks per rev)? What was the surface like? What did you use as a control algorithm?
I believe in general large thin wheels that don't slip work well for odometry. Slower speeds are also better since you're less likely to have the wheels slip.
1. external encoders in the sense encoders on free wheels, not on the powered wheels.
2.Straight line distance was some 3metres on wooden surface painted with some two layers of paint. we used simple aluminium wheels with grips.(.i am posting the picture)
3.Our Control algorithm was pid with error based on difference between encoder values.
Well this project thread has kind of gone feral. The stop over in Cuba was a bit distracting but
I realized the best video of the robot driving under remote control was of the robot with a bug which limited the movements to 45 degree increments.
Edit: Ugh! I just started watching this. Sorry it's so boring. The robot doesn't start driving until 2:00. I was trying to explain about the technical details. I think I need to try this again with less talking.
I plan to add a CMUcam4 to this robot (the hardware is installed I still need to incorporate it into the software.
I've been working on the software on this robot. The current program is a mess. I'm trying to clean it up and I also want to change the control interface to use Nordic nRF24L01+ transceivers instead of the RC system it's currently using. The robot remote I'm working on uses a Nordic device for communication so I'd like to get all my robots able to interface with the remote.
I've been working on a bunch of stuff lately I just don't have much for to show for it. I sure have a lot of yak hair though.
I never get tired of watching the vision of this rover. Its just a shame those wheels are not cheap. I purchased a 4ch R/C system for use one day in the future. I would be fun to watch two of these rovers race on a track where the sideways movement was an advantage. And some super fast motors =D
I would be fun to watch two of these rovers race on a track where the sideways movement was an advantage.
Racing a Mecanum wheeled robots sounds like it would be fun to watch. The controls (at least on my remote) for the Mecanum wheeled robot are pretty much the same controls used for controlling a quadcopter or a helicopter. The main control difference is the Mecanum wheeled robot doesn't require throttle input. Not needing to keep the Mecanum wheeled robot level is also a big difference. The forward and side motion use the same controls as pitch and roll on a 'copter. Yaw (rotation) is also the same control stick (rudder). It's kind of nice the two types of vehicles use the same controls so my helicopter practice also improve my Mecanum wheeled robot driving skills (and vice versa).
The Mecanum wheels are really a lot of fun. The robot is always a hit when I bring it out for visitors.
The Rover 5 motors work fine with the Mecanum wheels but I hope to build an upgraded version using some motors like these. I have a set of four similar motors from Pololu, I may use with the Mecanum wheels.
Whichever motors are used used with the Mecanum wheels, it's a very good idea to have encoders on the motors. There was a huge improvement in performance when I added encoder feedback to my control algorithm. IMO, just about every ground robot should have encoders but they're even more important than usual when using Mecanum wheels.
One of my future plans is to add a gyro/accelerometer combo to aid the Mecanum wheeled robot with autonomous navigation. I still haven't done much to make this robot drive autonomously other than some experiments with a digital compass. IMO, if a robot is only remote controlled then it's not really a robot. It's just a RC toy. I still have some work to do to change this toy into a real robot.
Thanks Duane, forgot about that one. Yes, the intent of Kepler was to have it be able to "orbit" an arbitrary point whilst changing it's own orientation. I'll probably need a couple more years before that gets done.
I have to wonder at some vehicle designs ?.... the one good thing about this 3 wheeled transporter is it would probably be great for those that can't manage a normal reverse park, we all know someone like that .... but the difficulty of going from A to B over more than a few yards just wouldn't be worth the tradeoff :swear:
Comments
Here are some things I commented out to try and make it stop:
This whole function I commented out basically
PRI AutoDrive(localCommand, localIndex)
InputNoticed
'previousThrottle := channel[Control#THROTTLE_CHANNEL]
{ if keyboardFlag
'InputNoticed
'Bot.RefreshSpeeds
elseif inputFlag }
' if keyboardFlag == 0 and inputFlag == 0 ' auto mode //might need this
' globalIndex := localIndex
' repeat
' if InputNoticed
' quit
' if localCommand == TURN_COMMAND
' Bot.Turn(speed, turnRate)
' elseif localCommand == STRAIGHT_COMMAND
' Bot.Straight(speed)
' result := ||(previousThrottle - channel[Control#THROTTLE_CHANNEL])
' while globalIndex > 0 and throttleChangeFlag == 0
' previousThrottle := channel[Control#THROTTLE_CHANNEL]
'if throttleChangeFlag and cnt - throttleTimer > ignoreThrottleInterval
' throttleChangeFlag := 0 //till here might need this
{PUB OmniLoop | localIndex, localRotation, previousGIndex
pDebubFlag := debugFlag
debugFlag := 1
localIndex := Header#STEPS_PER_FIGURE_8 / 2
localRotation := 0 '600
pseudoIncrement := PSEUDO_CIRCLE / localIndex '112
repeat
InputNoticed
if keyboardFlag == 0 and inputFlag == 0
'result := Bot.Straight(0)
psuedoMagnitude := 0
Control.ComputeTargetSpeeds(psuedoMagnitude, psuedoAngle)
'previousThrottle := channel[Control#THROTTLE_CHANNEL]
globalIndex := localIndex
previousGIndex := localIndex
repeat
if InputNoticed
quit
repeat while globalIndex == previousGIndex
previousGIndex-- ' ** not sure about this
psuedoAngle := Control.IncrementAngle(psuedoAngle, pseudoIncrement)
Control.ComputeTargetSpeeds(psuedoMagnitude, psuedoAngle)
while previousGIndex > 0
if keyboardFlag == 0 and inputFlag == 0
globalIndex := localIndex
previousGIndex := localIndex
repeat
if InputNoticed
quit
repeat while globalIndex == previousGIndex
previousGIndex--
psuedoAngle := Control.IncrementAngle(psuedoAngle, pseudoIncrement)
Control.Refresh
while previousGIndex > 0
globalIndex := 800
previousGIndex := 800
psuedoMagnitude := 0
psuedoAngle := Header#DEFAULT_COURSE * Header#PSEUDOREAL_MULTIPLIER
Control.ComputeTargetSpeeds(psuedoMagnitude, psuedoAngle)
'localRotation := 0
if keyboardFlag == 0 and inputFlag == 0
repeat
if InputNoticed
quit
repeat while globalIndex == previousGIndex
previousGIndex--
while previousGIndex > 0
repeat while keyboardFlag == 0 and inputFlag == 0 ' just do loop once
InputNoticed
'else
if inputFlag
''**Control.Refresh'(Input#ZERO_CENTER_RANGE)
'**Control.SpeedFromXY'(channel[Input#X_CHANNEL],
' channel[Input#Y_CHANNEL], Motion#RC_INPUT)
'pDebubFlag := debugFlag
'debugFlag := 2
Bot.RefreshSpeeds
}
also this stuff in main loop
' repeat
' speed := Header#DEFAULT_SPEED
' turnRate := Header#DEFAULT_TURN_RATE
' AutoDrive(TURN_COMMAND, localIndex)
'speed := Header#DEFAULT_SPEED
' turnRate := -Header#DEFAULT_TURN_RATE
' AutoDrive(TURN_COMMAND, localIndex)
'speed := 200
' turnRate := Header#DEFAULT_TURN_RATE
' AutoDrive(STRAIGHT_COMMAND, 200)
' speed := 0
'turnRate := Header#DEFAULT_TURN_RATE
' AutoDrive(STRAIGHT_COMMAND, 200)
' repeat while keyboardFlag == 0 and inputFlag == 0 ' just do loop once
' AutoDrive(STRAIGHT_COMMAND, Header#REFRESH_RATE / 2) '** don't really like this
I had changed the keyboard flag to 1 like you had said in a previous post. Not sure what else it could be.
Parallax Code:
repeat
if Pst.CharIn == "!" 'Starting Char
case Pst.CharIn '-1000 to 1000 Speeds
"W":
Bot.Straight(300) 'Positive Straight
"D":
Bot.SideWays(500) ' Positive Right
"X":
Bot.Straight(0) ' Stop
"S":
Bot.Straight(-500) 'Negative Backwards
"A":
Bot.SideWays(-500) ' Negative Left
"Q":
Bot.StrBreakLeft(300)'StrBrake Left
"E": 'StrBrake Right
Bot.StrBreakRight(300)
"Z": 'SideBrake Left
Bot.SideBreakForward(300)
"C": 'SideBreak Right
Bot.SideBreakRear(300)
"F": 'Turn Left
Bot.TurnLeft(300)
"G": 'Turn Right
Bot.TurnRight(300)
Here is stuff from the fourmotor encoder file
PRI StraightPrivate
repeat result from 0 to HIGHEST_MOTOR_ID
long[targetPtr][result] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD ' since target speeds have now been set
PRI SideWaysPrivate
long[targetPtr][0] := -globalSpeed
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := -globalSpeed
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI TurnRightPrivate
long[targetPtr][0] := globalSpeed
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := -globalSpeed
long[targetPtr][3] := -globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI TurnLeftPrivate
long[targetPtr][0] := -globalSpeed
long[targetPtr][1] := -globalSpeed
long[targetPtr][2] := globalSpeed
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
//all of these are for error correction if using a compass or in our case we are using two ultrasonics to stay parallel to a wall. We decided that we would need to break certain sets of wheels to correct if it was veering off //course. There might be a better way to do this not sure yet.
PRI StrBreakLeftPrivate
long[targetPtr][0] := globalSpeed * 0.9
long[targetPtr][1] := globalSpeed * 0.9
long[targetPtr][2] := globalSpeed
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI StrBreakRightPrivate
long[targetPtr][0] := globalSpeed
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := globalSpeed * 0.9
long[targetPtr][3] := globalSpeed * 0.9
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI SideBreakForwardPrivate
long[targetPtr][0] := -globalSpeed
long[targetPtr][1] := globalSpeed * 0.9
long[targetPtr][2] := -globalSpeed * 0.9
long[targetPtr][3] := globalSpeed
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI SideBreakRearPrivate
long[targetPtr][0] := -globalSpeed * 0.9
long[targetPtr][1] := globalSpeed
long[targetPtr][2] := -globalSpeed
long[targetPtr][3] := globalSpeed * 0.9
SetSpeedsPrivate
command := INDIVIDUAL_CMD
PRI MainLoop
'' This loop runs in its own cog. Control of object is done
'' by setting the variable "command" through public methods.
repeat
case command
SIDEWAYS_CMD:
SideWaysPrivate
STRAIGHT_CMD:
StraightPrivate
TURN_CMD:
TurnPrivate
TURNRIGHT_CMD:
TurnRightPrivate
TURNLEFT_CMD:
TurnLeftPrivate
STRBREAKLEFT_CMD:
StrBreakLeftPrivate
STRBREAKRIGHT_CMD:
StrBreakRightPrivate
SIDEBREAKFORWARD_CMD:
SideBreakForwardPrivate
SIDEBREAKREAR_CMD:
SideBreakRearPrivate
INDIVIDUAL_CMD:
SetSpeedsPrivate
'other: 'NO_NEW_CMD
'result := @targetSpeed
PUB SideWays(localspeed)
globalSpeed := localSpeed
command := STRAIGHT_CMD
PUB TurnRight(localspeed)
globalSpeed := localSpeed
command := TURNRIGHT_CMD
PUB TurnLeft(localspeed)
globalSpeed := localSpeed
command := TURNLEFT_CMD
PUB StrBreakLeft(localspeed)
globalSpeed := localSpeed
command := STRBREAKLEFT_CMD
PUB StrBreakRight(localspeed)
globalSpeed := localSpeed
command := STRBREAKRIGHT_CMD
PUB SideBreakForward(localspeed)
globalSpeed := localSpeed
command := SIDEBREAKFORWARD_CMD
PUB SideBreakRear(localspeed)
globalSpeed := localSpeed
command := SIDEBREAKREAR_CMD
Now my arduino code is just serial commands that I send:
Serial.print('!'); //this is to make sure parallax knows its an actual movement command
Serial.print('W'); //this would just cause it to go forward at a certain speed.
at the moment I dont have it taking speed and direction commands I just hardcoded those because the serial seemed to be to slow to turn on all four wheels at once, I could have probably created a buffer to store each command that came in and then pass it to the functions above.
Thanks Duane!
As you may know, Spin uses indentation as part of its syntax. The forum software removes the indentation unless you use code tags. They're easy to use, but I'll let Phil explain how to use them in the following link.
As I mentioned before, there are still lots of bugs in the code. I didn't really feel like it was ready to be released but I thought having something was better than nothing.
I'm still working on improving the encoder code to measure the time between encoder pulses instead of just counting encoder pulses within a set time period. Counting pulses works fine when the robot is moving fast, but at slow speed, there aren't enough encoder ticks per 1/50 second refresh period to accurately gauge speed. The guy who designed the Rover 5 suggested I measure the time between pulses to increase the low speed accuracy. I think this should work well but it takes some time to get the kinks worked out.
Once I have the encoder stuff worked out, I'm going to try to make the code work better when used as a slave.
You mentioned using a compass. What kind of compass are you using?
What kind of ultrasound sensor(s) are you using?
Even though I intend to use a compass and ultrasound with my robot, I'm not sure if it would be helpful to include these devices as part of the slave code. It might be better to have the master board monitor sensors directly but I'm not sure.
You may find, once you learn enough Spin, that you can do everything you need done with just the Propeller and not need the Arduino at all. IMO, the Propeller is a great microcontroller to know how to use if one is interested in robotics.
Here is the reposted code in a nicer format thanks for the tip!
Here is the stuff I have added so far
Yes I definitely agree that the parallax is probably going to become one of my goto boards now that I am starting to get familiar with it. At the moment I just dont know enough about the syntax
to code with the parallax unfortunately to add all of the things I want to add. I am using ping parallax ultrasonics to measure my distance and also using two one one side to stay parallel with a wall.
Also when we were trying to write our first PID we would use the time in between pulses of the encoder to compare to a master wheel. Therefore if one wheel was going faster then another
we were able to tell because the pulses on the master wheel would be much higher etc. We decided to just use the ultrasonics to keep parallel due to compass restrictions of EMF.
We have a lot of electronics and we have a height restriction on how big the robot can be, so the pole idea that I saw in your video might not work as good.
Also if you plan to add sensors and what nots it might be better to use it on whatever your master board will be. Serial seems to be a huge pain when trying to send and receive information.
Do you have any ideas what code might be causing the robot to spaz out sometimes on its own?
"Parallax" or "Parallax Inc." is the company that sells several different microcontrollers. The Propeller is one of these microcontrollers. Calling the chip or board "Parallax" sounds funny IMO. Not a big deal, but I thought I'd mention it.
I used C a lot on a PC before I started using Spin on the Propeller. Initially I was disappointed the Propeller didn't use C. It didn't take long for me to prefer Spin over C. There are several versions of C for the Prop but I much prefer Spin now so I haven't switched over to using C.
Pings are nice since they only need one I/O line. The downside to Pings is their price. There are lots of inexpensive ultrasound sensors that work great but use separate echo and trigger pins. The echo lines of multiple sensors can be combined so it's possible to use four sensors with five I/O pins.
The object "FourMotorsAndEncoders" does this for you. You just set the target speed and the program increases the PWM or decreases the PWM to bring the wheels to the desired speed. Try setting the speed of one of the wheels and then try to slow the wheel with your hand. The motor will fight your attempt to slow the wheel.
The control algorithm only uses proportional control. My attempts to add integral or differential didn't improve the motors' behavior. The proportional algorithm is in the "ComputeP" method of the "FourMotorsAndEncoders" object. If you wanted to try to added I. and D. to the P. that's the method to do it. Keep in mind the program uses a timed loop of 20ms so your PID algorithm can assume a constant time period between each update. This is assuming you attempt your PID in the Propeller. Trying to run your PID algoritm from the Arduino will be problematic because of the increased latency from serial signals.
The pole I used was much taller than needed. It was just used the first, relatively short, piece of carbon fiber rod I found. I'll probably use a shorter rod in the future.
In my case the QuickStart is the master board. I was wondering if it would be beneficial to include sensor information as part of the slave component of the program. I'll probably make sensor information an option if it's not hard for me to include it as part of the slave code.
I didn't write the program with the intention of having it be used on a slave board. It was just after the fact that I realized there were already aspects of the code that would allowed another uC to control it.
Actually, it's very, very common to have robot components controlled with a serial connection. The Dynamixel robot servos all use a serial interface. I don't think the serial connection itself is the problem here, I think it's one of both of our codes causing the problem.
No, it's very possible there's something in the code I posted causing the problem but I'm not completely convinced the problem is on the Propeller side of the setup.
As I've said, I'm still working on the code and there's lots of things about it that will be changing.
Also yes I know the propeller board not parallax SEMANTICS I SAY!!!!!
Yes I enjoy C, I eally would like to learn python one day. Spin seems interesting OOP and will most likely start using it more. Arduino has huge limitations when it comes to speed.
I finally made some progress with the next phase of the Rover 5-controlling Java program that runs in my laptop.
I wanted to create a mapping between a given PWM value sent to the motors, and the resulting EncoderCounts/sec. that they output. To have a better chance of ending up with an observable, repeatable curve, I did 11 test runs, running through PWM values of 30-255 each time.
As you can see below, each run has various odd gaps and shifts, which I'm imagining are due to my evolving data collection methodology (I had 50-100 hours of opportunities to evolve it, ugh), and perhaps related to the battery voltage differing for each test run, and decreasing during each one as well:
Right now I'm thinking that these plots are such a mess, that they are mostly just a strong endorsement for using PID to monitor/vary the PWM value to achieve a desired the EncoderCounts/sec. value, rather than trying to set any particular PWM value and praying that that will ever result in any reproducible EncoderCounts/sec. result.
My initial thought for a next step to implement is to fit a curve through the above data, and use the resulting (PWM,EncoderCounts/sec.) pairs as a starting point upon which to base a PID implementation.
How does this sound to you?
=Cliff
I think you're better off with some sort of proportional feedback loop. I doubt you'll need full PID.
How many volts where you using with your tests? How long was the sample time when measuring the speed?
The third graph looks like you were missing encoder pulses. Where you monitoring both encoder lines or did you monitor one pin of the encoders "or"ed together?
The first two graphs looks like you had a sampling time issue where your sampling time wasn't long enough to come up with a good average.
I suppose someone well versed in control theory could use your data to partially tune a PID algorithm but the graphs don't give information about change over time. I think you're making this harder than it needs to be. I think a good control algorithm would take care of adjusting the PWM for you. While I think it's interesting to see your PWM vs speed graph I don't think it's needed to come up with a control algorithm.
Have you figured out a way of monitoring the encoders with your control board? I think I remember you were having trouble with the number of interrupts you were receiving?
As there is lot of slipping in mecanum wheels due to one point contact how you were getting correct encoder values using internal encoders?
There will be a lot of error in the encoder values due to slipping.
Is there any way to reduce this error?
Currently i am working on a precise path tracing mecanum wheel bot but i am not able to solve the above problem.
I will appreciate your little help.
I know you're not the first one to worry about this. Post #44 of this thread has a link to an article about using an optical mouse type sensor to compute position. Parallax sells a sensor that should work well in the application.
I haven't used the encoders for anything other than speed control with this robot so far. I haven't tested how accurate the odometry using the encoders is yet. I'd imagine the odometry would be more accurate when the robot is travelling more like a conventional robot straight forward or straight back. I'd think the sideways motion would produce the most error. Again, these are just guesses since I haven't measured these values myself.
Very cool robot. Thanks for posting the photo but we really need to see a video of your robot in action, preferably in the competition.
Thanks Duane.
about getting distance using encoders.
1.What if we use external encoders instead of internal motor encoders? will it help?
2. @amano001 we made a simple bot with maxons having internal encoders and tried to move it in straight line. But it always use to deviate by some 5-10 cms. we were not particulary concerned with the distance but we wanted it to move in straight line, but we couldn't achieve it perfectly.
Can slow pwm and large wheel radius help?
When you say it would deviate by 5-10 cm, what distance did you travel? What kind of surface? What kind of wheels(Mecanum?, size, material)? What kind of encoders (how many ticks per rev)? What was the surface like? What did you use as a control algorithm?
I believe in general large thin wheels that don't slip work well for odometry. Slower speeds are also better since you're less likely to have the wheels slip.
2.Straight line distance was some 3metres on wooden surface painted with some two layers of paint. we used simple aluminium wheels with grips.(.i am posting the picture)
3.Our Control algorithm was pid with error based on difference between encoder values.
There are lots of threads about using encoders in both the Parallax forums and at LetsMakeRobots.com.
I realized the best video of the robot driving under remote control was of the robot with a bug which limited the movements to 45 degree increments.
Someone over on Let's Make Robots was asking about a Mecanum wheeled robot so I thought I'd update the video.
Edit: Ugh! I just started watching this. Sorry it's so boring. The robot doesn't start driving until 2:00. I was trying to explain about the technical details. I think I need to try this again with less talking.
I plan to add a CMUcam4 to this robot (the hardware is installed I still need to incorporate it into the software.
I've been working on the software on this robot. The current program is a mess. I'm trying to clean it up and I also want to change the control interface to use Nordic nRF24L01+ transceivers instead of the RC system it's currently using. The robot remote I'm working on uses a Nordic device for communication so I'd like to get all my robots able to interface with the remote.
I've been working on a bunch of stuff lately I just don't have much for to show for it. I sure have a lot of yak hair though.
I started out with Fingertech Mecanum wheels.
The Fingertech wheels don't come close to working as well as the Vex wheels and the Vex wheels cost less than the Fingertech wheels.
At $60 (US) the Vex wheels are a great deal. Of course even if they're a great deal, $60 is still a lot to spend on wheels.
Racing a Mecanum wheeled robots sounds like it would be fun to watch. The controls (at least on my remote) for the Mecanum wheeled robot are pretty much the same controls used for controlling a quadcopter or a helicopter. The main control difference is the Mecanum wheeled robot doesn't require throttle input. Not needing to keep the Mecanum wheeled robot level is also a big difference. The forward and side motion use the same controls as pitch and roll on a 'copter. Yaw (rotation) is also the same control stick (rudder). It's kind of nice the two types of vehicles use the same controls so my helicopter practice also improve my Mecanum wheeled robot driving skills (and vice versa).
The Mecanum wheels are really a lot of fun. The robot is always a hit when I bring it out for visitors.
The Rover 5 motors work fine with the Mecanum wheels but I hope to build an upgraded version using some motors like these. I have a set of four similar motors from Pololu, I may use with the Mecanum wheels.
Whichever motors are used used with the Mecanum wheels, it's a very good idea to have encoders on the motors. There was a huge improvement in performance when I added encoder feedback to my control algorithm. IMO, just about every ground robot should have encoders but they're even more important than usual when using Mecanum wheels.
One of my future plans is to add a gyro/accelerometer combo to aid the Mecanum wheeled robot with autonomous navigation. I still haven't done much to make this robot drive autonomously other than some experiments with a digital compass. IMO, if a robot is only remote controlled then it's not really a robot. It's just a RC toy. I still have some work to do to change this toy into a real robot.
Here's a video you can tire of watching, it's the only video I have of my Mecanum robot;
I know I've seen another video of your robot. I think it was made during a Propeller Expo.
Your robot is one of the reasons I want to upgrade the motors on mine. Your robot definitely had much more power than mine.
I often think of what your robot's name (Kepler) implies. I keep hoping to get a pair of omni directional robots to kind of dance around each other.
I got my omni wheeled robot robot to "spin straight".
But I'd really like to get the robots to be able to do more complex motions preferably as they move around one another.
I found the other Kepler video.
It was on erco's YouTube channel.
Some basic info:
-4 Servo Outputs externally powered
-9 GPIO Pins
-8 Analog Inputs
-SD Card
-Serial Port
We are currently working on the new version of this board to make minor improvements and move the headers to the exterior of the board for connecting shields together. Here is our github page for the Robot Shield https://github.com/fastrobotics/810001_robot-shield
and a link to a demo video on a robot: https://www.youtube.com/watch?v=DXkjqCKs9c8
We have a lot of other things we're working on too. Check out our facebook for more info: https://www.facebook.com/fastrobotics