Arduino line following robot for beginners in C++(Arduino) - c++

I'm working on a school project with very little resources. I need to make a line following robot which finds the way through a maze by turning left when possible. I already have a small body, but the robot doesn't seem to turn left/follow the line when needed. I also have no clue how I can get rid of small deviations and how I can make the robot turn when there are no more lines?
Materials:
Arduino Leonardo
qtr-8a ground sensor
two basic DC motors
Code:
#include <DRV8835MotorShield.h> //setup for motors
DRV8835MotorShield motors;
void setup() {
// put your setup code here, to run once:
motors.flipM1(true);
motors.flipM2(true);
}
void loop() {
//left groundsensor= analogRead(A0);
//rightgroundsensor = analogRead(A2);
//middlegroundsensor = analogRead(A1);
//motorstM1//right weel
//motors.setM2Speed(100);//left weel
if(analogRead(A0) > 750){ //turn left
motors.setM1Speed(100);
motors.setM2Speed(-100);
}
else if(analogRead(A1) > 750){//nothing left, so go straight
motors.setM1Speed(100);
motors.setM2Speed(100);
}
else if(analogRead(A2) > 750){//nothing in the middle, so robot has deviated, turn right a bit, if the deviation is to the rigth, I don't need the next loop
while(analogRead(A0) < 750){//turn right till black line is in the middle again
motors.setM1Speed(-100);
motors.setM1Speed(100);
}
}
else{//if they are all < 750, it's a deviation or a dead end, I will have to watch how the robot deviates so that I can turn let it always turn in the opposite direction
while(analogRead(A1) < 750){//turn right/left till black line is in the middle again
motors.setM1Speed(-100);
motors.setM1Speed(100);
}
}
}

//left groundsensor= analogRead(A0);
//rightgroundsensor = analogRead(A2);
//middlegroundsensor = analogRead(A1);
I'm assuming the line is wide enough that it can not be between 2 sensors and have both sensors report white. Correct?
Lets consider all the cases the car can run into:
Straight line
Ideally left should be white and middle black. In that case drive straight. But the car will drift left or right.
If A0 gets black turn more to the left. If A1 gets white turn more to the right.
Left turn, Left Branch
A0 and A1 both turn black, turn to the left.
4 way cross
A0, A1 and A2 turn black, turn to the left.
Right branch
A2 turns black, keep going straight
Right turn
A2 turns black and a bit later A1 turns white, turn right
As you see A2 can be ignored. And if you merge all the cases you get:
| A0 | A1 | movement
| white | white | turn right
| white | black | straight
| black | white | turn left or right, shouldn't really be happening
| black | black | turn left
So check for those 4 cases in loop() with a small delay and it should solve the maze.
Note: If the car gets stuck turning one direction for a long time you might want to go a bit straight. If the line is too thick you might just turn on the line and never see the edge. If you have white, white driving in a spiral to find the line again could help. Both cases indicate your loop is too slow or your speed to high. You should never loose the edge of the line.

Related

Turning Issue With Vex Robot C++

When we use the joystick with axises 1 and 2 to turn, when we turn left the robot turns right and when we turn right the robot turns left. We've tried switching different values to make some negative to reverse this but nothing seems to work. We've also tried making the left motor reversed instead of the right motor and it corrected the problem but the forward and backward are switched.
while (true) {
int rightSpeed= (Controller1.Axis3.position(vex::pct) +
(Controller1.Axis1.position(vex::pct) + Controller1.Axis4.position(vex::pct)));
int leftSpeed= (Controller1.Axis1.position(vex::pct) -
(Controller1.Axis2.position(vex::pct) + Controller1.Axis3.position(vex::pct)));
if (leftSpeed>15||leftSpeed<-15){
RightMotor.spin(vex::directionType::fwd, leftSpeed, vex::velocityUnits::pct);
}
if (rightSpeed>15||rightSpeed<-15){
LeftMotor.spin(vex::directionType::fwd, rightSpeed, vex::velocityUnits::pct);
RightMotor.spin(vex::directionType::fwd, -leftSpeed, vex::velocityUnits::pct);
}
}

C++ Space Invaders Movement

I'm really kind of new to c++ and quite bad at it but I'm making a space invaders game for my university project. I'm having trouble with the alien movement system and how to get the aliens to spawn in a line (once they get to a side of the screen they move down and then across).
Firstly here is the code I'm using to move the alien movement
if (currentSpritePos.x < 975 || currentSpritePos.x > 0)
{
this->AlienVelocity.x = this->AlienVelocity.x*-1;
}
if (currentSpritePos.x == 0)
{
cout << "Im at the wall wooo and going to move down";
//AlievVelocity.x*+1;
setSpritePos({ 0, 75 });
}
I can get the aliens to go left and move down but for some reason they aren't moving right, I commented the line out "AlienVelocity.x*+1", I thought that would have just made them go right since "-1" made them go left...
To get the aliens to spawn in a line I've made an array and set so only 2 aliens to spawn just for testing purposes.
for (int aly = 0; aly < 2; aly++) // Change the 35 to number of desired aliens
{
theAliens.push_back(new cAliens);
theAliens[aly]->setSpritePos({ (100, 50) + 200 });
theAliens[aly]->setSpriteTranslation({ 0, 0 });
theAliens[aly]->setTexture(theTextureManager->getTexture("alien"));
theAliens[aly]->setSpriteDimensions(theTextureManager->getTexture("ship")->getTWidth(), theTextureManager->getTexture("alien")->getTHeight());
}
On the 2nd line in side the for statement I put "+200+ because I thought that would just put the next alien +200 points but obviously not. I'm not sure on how to fix this as well...
if (currentSpritePos.x < 975 || currentSpritePos.x > 0)
{
this->AlienVelocity.x = this->AlienVelocity.x*-1;
}
This code says that whenever the aliens are between 0 and 975 to reverse the velocity. I believe this is the exact opposite of what you want. This means they should just go back and forth and never move across the screen. Swap the compare signs.
For moving down, take the current y position and add the row length to it, This should be done when the velocity is reversed - in the same if statement.
Start with those changes and see if you can figure out the rest.

Box2d Detect when a body is fully inside another body and which side it came in from

I need to detect when a body is fully inside another body and which side it came in from.
I have balls that bounce around the screen, and can enter the space of other square bodies. I need to know when the ball is fully inside the box, and from which side it came in on. This is NOT just collision detection on a side of the box, as the ball needs to be fully inside the box before anything triggers. I'm using b2FixtureDef::filter::maskBits and b2FixtureDef::filter::categoryBits to allow balls and boxes to not collide with each other.
I'm new to box2d, but not to C++, so I may be missing some functions that could make this easier for me. I started writing the following code, which works when a ball passes the correct edge, but also when it passes other edges.
Is there a way to do this without copying the ball into another data structure that keeps track of where it first contacts the box?
NOTE: This code is an example. It may not actually compile or do exactly what I say it does.
void CBox::captureBalls(std::list<CBall> &balls)
{
std::list<CBall> capturedBalls;
std::list<CBall>::iterator ball = balls.begin();
while (ball != balls.end()) {
bool capture = false;
int ballMinX = ball->getX() - ball->getRadius();
int ballMaxX = ball->getX() + ball->getRadius();
int ballMinY = ball->getY() - ball->getRadius();
int ballMaxY = ball->getY() + ball->getRadius();
switch (this->captureSide) {
case Top:
if ((ballMinX >= this->x) &&
(ballMaxX < (this->x + this->width)) &&
//(ballMinY >= this->y) &&
(ballMaxY < (this->y + this->height)))
capture = true;
break;
case Right:
if (//(ballMinX >= this->x) &&
(ballMaxX < (this->x + this->width)) &&
(ballMinY >= this->y) &&
(ballMaxY < (this->y + this->height)))
capture = true;
break;
case Bottom:
if ((ballMinX >= this->x) &&
(ballMaxX < (this->x + this->width)) &&
(ballMinY >= this->y) /*&&
(ballMaxY < (this->y + this->height))*/)
capture = true;
break;
case Left:
if ((ballMinX >= this->x) &&
//(ballMaxX < (this->x + this->width)) &&
(ballMinY >= this->y) &&
(ballMaxY < (this->y + this->height)))
capture = true;
break;
}
if (capture) {
capturedBalls.push_back(ball);
balls.erase(ball++);
}
else {
++ball;
}
}
}
To detect when a ball is fully inside the box, you could use a sensor fixture inside the box, that is smaller than the box by the diameter of the ball. In the diagram below the black rectangle is the box and the red dashed rectangle is the sensor. (If the balls all have different diameters this would not work.)
As to "which side it came in", I think you need to define what you mean by that, before anyone could help. I mean, look at the possible cases you are dealing with. The blue ball is the most straight-forward in that it approaches on one side in a constant direction. When you detect that it touches the sensor, you could use the direction of travel as suggested by sp2danny, to do a raycast from outside the box to the current position of the ball, and the side it entered is pretty obvious. But this would not work for the green or pink balls. For the pink ball in particular, what side would you consider it entered from?
Now I am assuming that the balls are free to enter the boxes from any angle. But if they had a solid obstruction at their corners, it might be clearer to define which side they came in. You could use four sensors around the exterior, and detect when a ball finishes touching these.
However, it would not be bullet-proof because in rare cases a ball could go from touching one side sensor to another in one time step, without touching nothing in between (green ball). For really fast balls, they could also potentially go from touching one side sensor, to completely inside without ever touching the sensor for the side they "came in" (pink ball). On the plus side though, this would handle the case when you have many different sizes of ball.
Ok... now that I've written up a whole post saying how it can't be done easily, I had a good idea, although it would only work when all balls are the same size. You could use two sensors inside the box, one inset by the radius of the balls, and one inset by the diameter of the balls. When the ball first touches the outer of these sensors, it means the center of the ball has crossed from being outside, to inside the box (but the ball as a whole may not be fully inside). At this point, take a raycast between the previous and current positions, and note which side it intersected. Continue on until the ball also touches the inner sensor, then you know it is fully inside, and you have already noted which side it originally came in from. If the ball stops touching the outer sensor at any point, reset to the starting state.
Note that it is still possible for a ball to first touch the box from one side, then move so that the first time its center is inside the box is from a different side (orange ball). But I am assuming you would not count a mere touch as "came in".

Reverse animation direction when hitting the side of the screen

I am creating a space invaders game for my university assignment. I am breaking the parts down on paper, I thought a good place to start would be to move the sprites across the screen. The issue I have at the moment is this, when the sprite his the right hand side of the screen it would just carry on moving, so I added this code:
if (invadersSprite.getPosition().x > 650)
{
std::cout << "WIDTH_END" << std::endl;
}
I basically used this for debugging for future reference. The output popped up into the console so I knew I was onto something. So, I started moving on from the output to actually moving the sprites back to the left hand side of the screen. I am now having more issues then expected.
I declared some ints for up, left, right and down just for easability when it comes to reading the code.
int spriteWalkSpeed = 50;
int up=-spriteWalkSpeed, down=spriteWalkSpeed, left=-spriteWalkSpeed, right=spriteWalkSpeed;
I've tried using the SFML move commands and also setPosition, but none of them really work as I thought they should.
move:
The issue I have had with this one is it basically stops in the middle of the screen. It still animates the leg movement and such, but it doesn't move left or right.
if (invadersSprite.getPosition().x > 650)
{
invadersSprite.move(left, 00);
}
setPosition:
This is a little closer to what I am after, but still no cigar. The movement pauses for around a second and then pops up at the left hand side of the screen. What I need is to move back down the screen.
if (invadersSprite.getPosition().x > 650)
{
invadersSprite.setPosition(left, 00);
}
I haven't been using SFML for very long so I am a little puzzled by this.
EDIT
At the moment the sprite is moving to the right of the screen, as needed:
if(spriteTimer>delay)
{
invadersSprite.setTextureRect(area);
++count;
invadersSprite.move(right,0);
if(count==SPRITECOLS) //WE HAVE MOVED OFF THE RIGHT OF THE IMAGE
{
area.left=0; //reset texture rect at left
count=0; //reset count
}
else
{
area.left+=spaceWidth; //move texture rect right
}
spriteTimer=0; //we have made one move in the sprite tile - start timing for the next move
}
Your current logic will only move the sprite left once if the x-coord is greater than 650 - but that's not exactly what you want. What you want is for the sprite to continuously move left after reaching the edge.
To do this you'll need to keep track of a current velocity for your sprite. For example, when your sprite starts, it will be moving right:
xVelocity = right;
Then you can have 2 conditions that will switch direction (when hitting edges of screen):
if (invaderSprite.getPosition().x >= screenWidth) {
// hit the right side of screen
xVelocity = left;
} else if (invaderSprite.getPosition().x <= 0) {
// hit the left side of screen
xVelocity = right;
}
Now, on ever game tick, you simply move your sprite according to its current velocity:
invaderSprite.move(xVelocity, yVelocity);
There are some other things that will need to be fixed, like taking the width of the sprite into consideration, changing the y velocity, etc., but this is the main idea.

Collision Detection Between Rectangles - Resulting Angles

Basically I have a bunch of rectangles floating around at 8 different angles (45 degrees, 90 degrees etc). I have collision detection going on between all of them, but one thing still doesn't work as it should. I don't know if I'm just not thinking or what, but I can't seem to get the resulting angles right. I've also tried searching multiple places, but haven't really gained anything from what I've found.
NOTE: the angle system here starts at 0 at the top and increases clockwise.
NOTE: all rectangles have the same mass
Say one rectangle going straight right (90 degrees) hits another going straight left (270 degrees). They will hit off of each other just fine.
Now say one going left gets hit by one going up. Here I can't simply reverse the angles or anything.
If you have more than one way, consider the following: unless I rearrange the CD so it spreads into the other code, I have the positions of all of the rectangles. The CD checks by seeing if two are overlapping, not by comparing where they are going.
As I've been working on pretty much everything except for the collision detection until now, I only have tonight left to get it working and add a few other small things before I'm done.
If you know of a way to make the angles come out right without hardcoding, great. At this point I'm ready to hardcode it (not too much really) if all I have is which rectangle hits the other (ex 2), or if they both do (ex 1). Either one is really helpful.
I think you mean something like this...
Each Rectangle has this functionality, testing against, say an array of other objects.
Obstacle* obstacle = new Obstacle;
Obstacle** obstacles = obstacle*[];
For(int i = 0; i <3; i++)
{
obstacles[0] = New Obstacle(x,y, etc...);
etc...
}
Or something similar... this is a little rusty
void collision(obstacles)
{
for(int i = 0; i < obstacles.sizeOf();i++)
{
//bottom y
if((this.ypos + this.height) > (obstacles[i].ypos - obstacles[i].height))
obstacles[i].doYCollision(this);
//top y
if((this.ypos - this.height) < (obstacles[i].ypos + obstacles[i].height))
obstacles[i].doYCollision(this);
//right x
if((this.xpos + this.width) > (obstacles[i].xpos - obstacles[i].width))
obstacles[i].doXCollision(this);
//left x
if((this.xpos - this.width) < (obstacles[i].xpos + obstacles[i].width))
obstacles[i].doXCollision(this);
}
}
again im a little rusty but if you follow it you should be able to relaise what im doing.
then all you need is the resulting function calls.
void doYCollision(Obstacle obstacle)
{
// Whatever y direction they are going do the opposite
obstacle.yDir = obstacle.yDir * -1;
}
void doXCollision(Obstacle obstacle)
{
// Whatever x direction they are going do the opposite
obstacle.xDir = obstacle.xDir * -1;
}
where yDir, xDir is the x and y velocity of the current object.
i should point out again this is very rusty and without having some code from you this is the best ive got. but either way this should start you off into collision detection, the code above shoudl allow for all collisions with all obstacles/objects/pink flamingos/ whatever youve got. Im hoping also that itll do what you want when it comes to multiple collisions at the same time.
You shouldnt need to worry too much about the exact angle (unless you need it for something else), as velocity is a vector mass so has both speed and direction and you can get direction by treating x and y as two different elements. You can do this using the dot product method aswell => http://www.topcoder.com/tc?d1=tutorials&d2=geometry1&module=Static, but if they are just rectangles this should be fine.
Hopes this helps