View Full Version : Line Following
pigpc1993
31-03-2011, 19:12
Our line following code works great until it start going straight. The speed has a sudden jolt and then gets off track. We tried setting the speed as low as .05 and yet it still jolts the same amount
Drive Method
public class Drive implements Mechanism{
private static final double SPEED_STOP = 0.0;
private static final double SPEED_FWD_MAX = -.2;
private static final double SPEED_REV_MAX = .2;
RobotDrive m_drive = new RobotDrive(2,1,4,3);
DStation d = new DStation();
public Drive(){
m_drive.setInvertedMotor(RobotDrive.MotorType.kFro ntRight, true);
m_drive.setInvertedMotor(RobotDrive.MotorType.kRea rRight, true);
}
public void initialize(){
stop();
}
public void run(double x, double y){
}
public void joystick(double x, double y){
m_drive.arcadeDrive(y, x);
d.toLCDLine(2, "" + x);
d.toLCDLine(3, "" + y);
}
public void stop(){
m_drive.arcadeDrive(SPEED_STOP,SPEED_STOP,false);
}
public void goForward() {
m_drive.arcadeDrive(SPEED_FWD_MAX, SPEED_STOP, false);
}
public void goBackward() {
m_drive.arcadeDrive(SPEED_REV_MAX, SPEED_STOP, false);
}
public void goLeft() {
m_drive.arcadeDrive(SPEED_STOP, -SPEED_FWD_MAX, false);
}
public void goRight() {
m_drive.arcadeDrive(SPEED_STOP, -SPEED_REV_MAX, false);
}
public void goRightBackward() {
m_drive.arcadeDrive(SPEED_REV_MAX, SPEED_FWD_MAX, false);
}
public void goLeftBackward() {
m_drive.arcadeDrive(SPEED_REV_MAX, SPEED_REV_MAX, false);
}
public void goForwardLeft() {
m_drive.arcadeDrive(SPEED_FWD_MAX, SPEED_FWD_MAX, false);
}
public void goForwardRight() {
m_drive.arcadeDrive(SPEED_FWD_MAX, SPEED_REV_MAX, false);
}
}
Line Follow Method
public class LightSensor extends Maneuver {
DigitalInput l1;
DigitalInput l2;
DigitalInput l3;
Drive drive;
DStation station;
public LightSensor(DigitalInput l1, DigitalInput l2, DigitalInput l3, Drive drive,DStation station, Maneuver pass, Maneuver fail, Maneuver timeout,
double maxTime){
super(pass, fail, timeout, maxTime);
this.drive = drive;
this.station = station;
this.l1 = l1;
this.l2 = l2;
this.l3 = l3;
}
public void run(){
station.toLCDLine(2, l1.get() + "");
station.toLCDLine(3, l2.get() + "");
station.toLCDLine(4, l3.get() + "");
if((l1.get() == false) && (l2.get() == true) && (l3.get() == false)){
drive.goForward();
}
else if((l1.get() == false) && (l2.get() == false) && (l3.get() == true)){
drive.goRight();
}
else if((l1.get() == true) && (l2.get() == false) && (l3.get() == false)){
drive.goLeft();
}
else if((l1.get() == true) && (l2.get() == true) && (l3.get() == true)){
drive.stop();
}
else{
drive.goRight();
}
}
public void stop(){
drive.stop();
station.toLCDLine(1, "Stop");
}
youxinche95
31-03-2011, 22:25
do you have a method that you can supply the cartesian x and y. I looked at your Drive method, and there is an arcadeDrive() that accepts an x and and y and a boolean... not sure what the boolean does, but oh well, it seems to be all set to false. I assume the line trackers are assembled in a linear fashion as in
FRONT
|
1 2 3
|
CENTER
Anyways, It looks as though you have a mecanum drive so you can strafe...
Anyways, try this pseudocode out.
double myX = 0;
double myY = 0.5; //some constant forward velocity
if(l1.get()) { //if a boolean returns true, ie the get(), go into if
myX -= 0.5; //0.5 is just some horizontal feed for motors.
if(13.get()) { //no need for == true
myX += 0.5;
if(l2.get()) {
myX /= 2; // close to lining up to line, so slow down
if(l1.get() && l2.get() && l3.get()) {
myY = 0;
arcadeDrive(myY, myX, false);
This was really quickly made, so I'm not sure if it will work... anyways, good luck :D
pigpc1993
01-04-2011, 11:46
do you have a method that you can supply the cartesian x and y. I looked at your Drive method, and there is an arcadeDrive() that accepts an x and and y and a boolean... not sure what the boolean does, but oh well, it seems to be all set to false. I assume the line trackers are assembled in a linear fashion as in
FRONT
|
1 2 3
|
CENTER
Anyways, It looks as though you have a mecanum drive so you can strafe...
Anyways, try this pseudocode out.
double myX = 0;
double myY = 0.5; //some constant forward velocity
if(l1.get()) { //if a boolean returns true, ie the get(), go into if
myX -= 0.5; //0.5 is just some horizontal feed for motors.
if(13.get()) { //no need for == true
myX += 0.5;
if(l2.get()) {
myX /= 2; // close to lining up to line, so slow down
if(l1.get() && l2.get() && l3.get()) {
myY = 0;
arcadeDrive(myY, myX, false);
This was really quickly made, so I'm not sure if it will work... anyways, good luck :D
Thanks for the help. I don't know much about the drive. Right now we are using a kitbot so we can finish up the code so we can apply it all at the competition. I'll let you know how it goes. Thanks again.
Jared Russell
01-04-2011, 13:06
Unless your line sensors are really far apart (and even if they are), it will always be possible for two of the three to see the line at once. You don't seem to have coded logic to take care of this case.
For example, currently, if your LEFT and MIDDLE see the tape, but the right does not, you would turn right with the code you posted. Is this really what you want?
If you start driving straight but then seem to veer off to the side, perhaps this is the issue?
pigpc1993
01-04-2011, 13:10
Unless your line sensors are really far apart (and even if they are), it will always be possible for two of the three to see the line at once. You don't seem to have coded logic to take care of this case.
For example, currently, if your LEFT and MIDDLE see the tape, but the right does not, you would turn right with the code you posted. Is this really what you want?
If you start driving straight but then seem to veer off to the side, perhaps this is the issue?
Maybe. I'll do some testing today. I'll keep you guys posted.
Fletch1373
01-04-2011, 23:38
What is the reasoning for inverting the front-right and back-left motors? Was youxinche95 correct that you're using mecanum wheels? If so, there are drive functions available in the WPILib Library to handle that.
Going on the assumption that you are using mecanum, I would recommend reading about these functions in the RobotDrive class: mecanumDrive_Polar (http://www.wbrobotics.com/javadoc/edu/wpi/first/wpilibj/RobotDrive.html#mecanumDrive_Polar(double, double, double)) and mecanumDrive_Cartesian (http://www.wbrobotics.com/javadoc/edu/wpi/first/wpilibj/RobotDrive.html#mecanumDrive_Cartesian(double, double, double, double)). With either of these, you specify a direction vector(in either X- and Y-speed values, or as separate magnitude and direction).
You can simply strafe to the right or left, or rotate independent of direction depending on the values returned from the line sensors.
As for testing for all possible cases, you would have to write a lot of code... or would you? :rolleyes:
While working with my team, 3555 and also a rookie this year, the programmers and I decided to figure out all possible cases and when they could happen. Knowing that we have 3 sensors that return boolean true/false values, we can use simple algebra to calculate the number of possible cases as 2^3 or 8. We also decided that a switch-case statement would work best to allow us to group similar cases together(such as left only and left/middle being tripped both telling the robot it has to move left). In order to use the switch-case, we need all the sensor values to be packed together into a single variable.
Now converting from boolean to integer is kinda weird in Java. (int)l1.get() doesn't work... from what I've found, the simplest way to do it would be with a ternary operator(don't know what this is? then run away while you still can....). For anyone that doesn't know, a ternary operator takes a condition statement and does something based on it's result, all on a single line(basically it's an if-else, but all on one line... and makes sight-reading of code very difficult sometimes[usually])... So to build our packed variable, we took 3 ternary operators, bit-shifted them to the appropriate place, then bitwise-OR'd them together.
int lineL = ((L1.get())?1:0);
int lineM = ((L2.get())?1:0);
int lineR = ((L3.get())?1:0);
int line = lineL<<2 | lineM<<1 | lineR;
After this, we can use the line variable in our switch statement. Our cases are the base-10 integer representation of the 3bit packed variable(0,1,2,3,4,5,6,7). Doing some simple binary conversions(and leaving comments with them already done), allows you to organize your cases in a logical way(if you plan to group them at least. Otherwise order doesn't matter.). Just remember not to include a break; for the cases you plan to group. When they are used the program can run down the list executing code for the similar case instead(so you don't have to write the code multiple times).
switch(line)
{
case 4: // 1_0_0
// notice no break
case 6: // 1_1_0
// do some code
break;
<insert more cases>
}
pigpc1993
02-04-2011, 12:10
What is the reasoning for inverting the front-right and back-left motors? Was youxinche95 correct that you're using mecanum wheels? If so, there are drive functions available in the WPILib Library to handle that.
Going on the assumption that you are using mecanum, I would recommend reading about these functions in the RobotDrive class: mecanumDrive_Polar (http://www.wbrobotics.com/javadoc/edu/wpi/first/wpilibj/RobotDrive.html#mecanumDrive_Polar(double, double, double)) and mecanumDrive_Cartesian (http://www.wbrobotics.com/javadoc/edu/wpi/first/wpilibj/RobotDrive.html#mecanumDrive_Cartesian(double, double, double, double)). With either of these, you specify a direction vector(in either X- and Y-speed values, or as separate magnitude and direction).
You can simply strafe to the right or left, or rotate independent of direction depending on the values returned from the line sensors.
As for testing for all possible cases, you would have to write a lot of code... or would you? :rolleyes:
While working with my team, 3555 and also a rookie this year, the programmers and I decided to figure out all possible cases and when they could happen. Knowing that we have 3 sensors that return boolean true/false values, we can use simple algebra to calculate the number of possible cases as 2^3 or 8. We also decided that a switch-case statement would work best to allow us to group similar cases together(such as left only and left/middle being tripped both telling the robot it has to move left). In order to use the switch-case, we need all the sensor values to be packed together into a single variable.
Now converting from boolean to integer is kinda weird in Java. (int)l1.get() doesn't work... from what I've found, the simplest way to do it would be with a ternary operator(don't know what this is? then run away while you still can....). For anyone that doesn't know, a ternary operator takes a condition statement and does something based on it's result, all on a single line(basically it's an if-else, but all on one line... and makes sight-reading of code very difficult sometimes[usually])... So to build our packed variable, we took 3 ternary operators, bit-shifted them to the appropriate place, then bitwise-OR'd them together.
int lineL = ((L1.get())?1:0);
int lineM = ((L2.get())?1:0);
int lineR = ((L3.get())?1:0);
int line = lineL<<2 | lineM<<1 | lineR;
After this, we can use the line variable in our switch statement. Our cases are the base-10 integer representation of the 3bit packed variable(0,1,2,3,4,5,6,7). Doing some simple binary conversions(and leaving comments with them already done), allows you to organize your cases in a logical way(if you plan to group them at least. Otherwise order doesn't matter.). Just remember not to include a break; for the cases you plan to group. When they are used the program can run down the list executing code for the similar case instead(so you don't have to write the code multiple times).
switch(line)
{
case 4: // 1_0_0
// notice no break
case 6: // 1_1_0
// do some code
break;
<insert more cases>
}
I'm sorry but I don't understand what a Mecanum drive is exactly. I'm going to research it. Anyway we found out what our problem was. youxinche95 was correct with the else statement and we also had a bad Victor. Apparently it smoked at one point or another and was only able to go at full power even after multiple calibration attempts. I don't understand why it happened like that. We tried running it again after calibration and it started smoking more so we replaced it. Thanks for the help guys.
Edit:
I looked at pictures and information about Mecanum drives and we don't have that.
youxinche95
02-04-2011, 22:47
Glad to be of assistance. Go FIRST!
pigpc1993
03-04-2011, 01:36
Glad to be of assistance. Go FIRST!
Thanks a lot again! We would have been in a little bit of trouble if we didn't figure this out since our competition is this week.
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.