[UPDATE: This project is now being ported to a proper Google Code repository and manual. For instructions, start there. You can also join the ArduRover User Group here.]
Hello to ALL, the new firmware for APMRover v2 has been tested successfully on my rover on may 1st, 2012 on full autonomous reco mission following a navigation plan. This new release of the APMRover v2 works on the APM v1.4 with the OilPan shield (magnetometer + MT3329 GPS) and also of course on the APM v2. The previous version of the APMRover v1.0 was a light size version specially designed for the APM1280 CPU (only) board and the MT3329 GPS.
For the frame, I have used a Traxxas Monster Jam Grinder with a brushed and high power motor Titan 12T and its XL-5 ESC.
The APMrover UGV is able to run itself following a list of recorded waypoints. The waypoints list (FPL) can be preloaded with the APM Mission Planner OR better in live, recorded by the pilot himself (with the SW7) during a manual run and then replayed in a full autonomous mission.
The firmware APMrover2 for APM v1 + OilPan or APM v2 successfully tested can be downloaded HERE
The APMrover v2 is also online on the official ArduPilot-Mega GIT repository HERE
Below the PID setup for the APMrover v1 and v2:
The light firmware APMrover1 for APM v1 (CPU 1280 or 2560) that I have tested can be downloaded HERE
Here's how to connect your cables:
More infos at: http://diydrones.com/profile/JeanLouisNaudin
Have Fun and Enjoy with the APMrover...
Regards, Jean-Louis
Comments
With that additional code running on say, another Arduino, what if you have it trigger what mode the APM was in depending on if an obstacle was present or not? I guess it would depend on whether or not AUTO mode picks up where it left. So basically, the Arduino could say
if NO_OBSTACLE
run in AUTO mode
else
switch to manual, take over basic maneuvers like back up and move, then switch back to AUTO.
I suppose the APM could do that too but if you use a two processor system, one for avoidance and the other for autonomy, that would be an easy way to take over.
Hi Alan,
With the code I presented in my last post, the "go straight" (navigate) part of the program will only be executed if there are no obstacles in the rovers path I believe.
Regards,
TCIII
Yes, I was just thinking about that. Lowest task is default. "Emergency" tasks must be able to overide the base task. Alternate tasks can overide or block lower tasks as need be. "At the bottom of the program"? At the bottom of the main program loop? The last task to call in a task loop? if you use position in a task loop to determine priority. Or, if you have blocking or conditional calls to tasks in the task loop, then it really doesn't matter what the position is. And remember, interrupts can either initiate tasks or do them as well.
Alan
So, is anyone already signed up for the SparkFun AVC that will be using this to run their vehicle? Would be interesting to see how it performs. Aside from avoiding the barrels that will change between runs, it seems it would work quite well.
Hi Alan,
Thanks for the overview, but I have one question. Usually the lowest priority task is located at the bottom of the executable program with the other higher priority tasks executing above it? Comments?
Regards,
TCIII
You've got the basic idea. One routine or layer inhibits another. There is an order of hierarchy. I put the avoidance on the bottom (or the table edge detector, in the case of my latest table-top robot). Nothing inhibits this layer. Above that, I'm looking for a target, or looking for an object to put into the target. But I'd break up the code into subroutines. Might make it easier to see the structure. Also parameterize all the "magic numbers". I use conditional compiles to alter the modes, such as a following mode, or a flee mode. Or call them behaviors.
I have used a "move foward" behavior for a base behavior, and you're right, I'd put a "head for next waypoint" behavior in there.
Another way to control the direction of the 'bot is by "weighted" vectors or directions. All of the controlling forces are added up (vector addition) to get an acceptable heading. Or think "magnetic attraction".
Quite a lot to integrate! Don't forget the camera "blob" following!
Please continue!
Alan
Hi Alan,
I still feel that using two processors, a UNO for obstacle avoidance, and the APM providing steering and speed commands is a better method than trying to use the sonar on the APM.
I am attaching open source code for an autonomous rover using three PINGs and two IR sensors for obstacle avoidance. At the bottom of the avoidance code are lines of code that drive the rover forward in a straight line at a given speed if the program is not avoiding obstacles. This is obviously a form of subsumption. This program will attempt to back up and go around an obstacle if the rover's path is blocked and will try and avoid obstacles that come in at an angle in the front of the rover. I am suggesting that instead of the code that continually trys to move the rover forward in a straight line and given speed, when the code is not avoiding obstacles, be substituted with steering and speed commands from the APM. This input will keep the rover moving toward the next waypoint if it is not avoiding obstacles. Comments?
Regards,
TCIII
//[<o>]MINDS-i Projects. mymindsi.com
//created by MINDS-i 20 Dec 2011
#include <Servo.h>
#include <MINDSi.h>
Servo drive, frontsteer, backsteer; //create servo instances for servos and speed controller
int left, right, front, leftc, rightc, frontc; //create variables to store ping sensor readings
unsigned int starttime;
int frontcenter = 90; //tune midpoint for front and back
int backcenter = 90; //to drive strait and tune forward/reverse speed
int fwdspeed = 108;
int revspeed = 75;
int turn = 35;
/*
This example will drive until it sees a wall in front of it and sends a signal to stop.
Then it will back up in the direction with more space until it sees room to move forward.
It also steers away from walls when approaching at an angle.
Setup:
1. Attach the sensors for backing up to pins 13 and 12 (no specific order).
2. Attach the drive speed controller to pin 2.
3. Attach the front steering servo to pin 3.
4. Attach the back steering servo to pin 4 (for 4 wheel steering only).
5. Attach the front ping sensor to pin 5; the right ping sensor to 6; and the left ping sensor to 7.
*/
void setup() {
pinMode(13, INPUT); //set pins we will get backing sensor data from as inputs
pinMode(12, INPUT);
drive.attach(2); //set pins the servos/speed controller will be attached to
frontsteer.attach(3);
backsteer.attach(4);
frontsteer.write(frontcenter); //move steering servos to center
backsteer.write(backcenter);
drive.write(90); //arm speed controller with nuetral signal for half a second
delay(500);
}
void loop()
{
noInterrupts(); //dissable interrupts for time sensitive sensor readings
if((frontc = getPing(5)) != 0) front = frontc;//get reading excluding bad readings of zero
interrupts(); //reenable interrupts to run servos
delay(15); //delay for cross-talk and time for interrupts to trigger
noInterrupts();
if((rightc = getPing(6)) != 0) right = rightc;
interrupts();
delay(15);
noInterrupts();
if((leftc = getPing(7)) != 0) left = leftc;
interrupts();
delay(15);
if(front < 3000 || left < 650 || right < 650) //something is close in front
{
drive.write(95); //make sure the robot isn't in reverse to ensure the brake triggers
delay(25);
drive.write(0); //activate brake
delay(775); //give time to stop
if(left >= right) { //steer away from objects
frontsteer.write(frontcenter+turn);
backsteer.write(backcenter-turn);
}
else {
frontsteer.write(frontcenter-turn);
backsteer.write(backcenter+turn);
}
drive.write(95); //release brake
delay(50);
drive.write(revspeed); //start reverse
starttime = millis();
while(
((millis()-starttime<1000)
|| front<5500 )
&& ((digitalRead(13)==1)
&& (digitalRead(12)==1)))
{
front = getPing(5);
delay(5);
}
drive.write(90); //stop
frontsteer.write(frontcenter); //turn to drive straight
backsteer.write(backcenter);
delay(1000);
drive.write(fwdspeed); //start going forward again
}
if(left < 4000 && right > 4000) //if left side is getting close
{
frontsteer.write(map(left, 4000, 650, frontcenter, (frontcenter+turn))); //scale the servo from
//center towards turning
backsteer.write(map(left, 4000, 650, backcenter, (backcenter-turn)));//by the ping sensors reported
//distance from the wall
}
else if(left > 4000 && right < 4000) //if right side is getting close
{
frontsteer.write(map(right, 4000, 650, frontcenter, (frontcenter-turn)));
backsteer.write(map(right, 4000, 650, backcenter, (backcenter+turn)));
}
else if(left > 4000 && right > 4000)
{
frontsteer.write(frontcenter); //everything is fine go straight ahead
backsteer.write(backcenter);
drive.write(fwdspeed);
}
}
RC Rover looks interesting! Tagging along.
Hello Jean Louis,
Thanks for the reply. I'm not up to speed yet on the Neato LIDAR, but as I might have "connections" (both social and my company), I'll probably get to experiment with it!
Another thought would be to interact with an external Blackfin Camera/processor. If you've implemented some sort of "Subsumption" (Rodney Brooks) architecture, Then the ability of a "Blackfin behavior" to be reporting when the 'bot is within a certain range of a waypoint and take over and direct the 'bot to the target (orange cone!) would be what I'm after! After the goal was touched, another behavior (back up, and continue) would take over, and the 'bot would proceed to the next waypoint.
Are you using Subsumption? I apologize, I haven't had a chance to study you code yet! Looking forward to it, 'tho.
Sincerely,
Alan
I've forget......
may be to have an average return value from sonar, just for eliminate that a peace of grass crossing in front of the sonar can stop the car.....
what do you think about it?
Thank you very much!!!!
Franco