Lawn Mower Robot Programming

hello everyone,

First english isn’t my native language so I’ll do my best to explain my problem. Second, I understand all (I think) the ideas I’m using here but I’m not always using the right words to express them.

Until now I have already code lots of thing with arduino like a weather station with a wemos d1 mini using thingspeak and followed a course about java and basic language programming at the uni. All my projects always needed a few actions in the main loop. Like reading sensors and updating the thingspeak data base and goind to sleep (for my weather station).

This time for the mower it’s way more complicated. I’m searching the (best or most suitable) way to do it.

My robot navigate thanks to a MPU6050 to go straight and do precise turns. The sensor must be read each time it has data in its buffer (FIFO) or it will overflow even when i’m not using it. The sensor triggers a interrupt pin each time it has new data in its buffer but calling this function from the ISR doesn’t work. I think it’s due to the fact that the function isn’t finished before the ISR calls it again. So i’m using a flag for the moment which indicates to the loop that there’s data in the buffer.

The robot needs to perform all these kind of tasks (reading sensor, avoiding obstacles, I’ll call these the “necessary tasks”) while doing a special mowing pattern or following a guide wire, “basic task”. So how can I create a loop that does always the necessary tasks and a particular basic task at the same time. Swithcing between basic tasks will be done according to a condition like when the battery is low, follow the guide wire to the charging port. I hope you undertsand what I mean.

My solution for the moment : I’m using a variable “mode” which represent what the basic task of the robot is at the moment. Every time a condition is true, it changes the “mode” to the needed one (like with low battery). In the main loop there is a switch(mode){} which calls the necessary functions the robot need to perform.

In the code there is 3 tab, one for the main code, one with all the functions relative to the MPU6050 and the last with the robot’s ones (moving, turning, etc). The code is really long so I didn’t put it in code mode. Good idea or not ?

Already a big thanks for all the answers I’ve found in this forum !

MOCmowerV1.0.ino (759 Bytes)

MPU6050.ino (5.47 KB)

Robot.ino (3.71 KB)

Hi MOCmaniac Welcome to the forum.
Your project sounds fun.

Go google "Arduino several things at the same time" to find Robin2's excellent tutorial on how to manage multiple tasks.

Be aware that navigating with a mower is a complex task that few have been successful at. The commercial models behave like Roomba vacuum cleaners, randomly mowing until the detect an obstacle or a border marking wire.

Thanks vinceherman,

I've already read Robin2 demo and fully understood it. I'm quite familiar with millis() programming instead of delay(). My problem is more about how to do the right action among others while doing important stuff like reading sensors value which will determine the action the robot has to do.

I've read a little bit about state machine and the purpose of it but is this the way (or any other one !) to go for my robot or does the switch(mode) will do the job ?

The navigation part isn't the most difficult in this project, I've already linked all the actions the robot has to do according to conditions, just need to translate this into code. It'll take some time off course but the working principle is already make

EDIT : state machine and enum

you will definatly need to over come a problem with your navigation. the digital compass may give you your rotation but this would be a difficult task without also knowing your position. Using the rotation speed of the wheels or a time factor that it has been moving will be worthless in any calculations. if you dont intend to use a random movement algorithym like vinceherman mentioned, you will need to do just as much work on your lawn making markers as you will working on your mower!

Just for clarification, each time my mower will detect an object or the boundary wire it will turn of certain angle according to the compass. There won't be any precise positioning system with GPS, movement tracking or anything else. The compass is used to do straight lines and turning of x degres.

Could we please come back to my main question about how to implement the programming of it like I explained in me first message.

looks like you are on the right path for the programming. your conept of switch statements should be fine with your mode variable. i would create some vaiables that all the modes share like some numbers that are set for the speed of each wheel. and maybe a statis variable saying whether a turn is in progress or completed. anyways, i would like to see more posts about how this works out. I would love to make a robot mower too! LOL

As I see it you have two options: 1) Your robot goes straight until it hits something and then it goes back a nodge before it turns a certain degree (but never 90) to the left or to the right and continues or 2) You use some sort of tracking device (GPS, triangulation, fence) to create a map of the area the robot is allowed to move inside.

The first method is quite simple and it should allow most area to be covered but it will most likely have "black spots" where the robot never comes. The latter method is quite hard to get right but one way to do it is to let the robot plot the outer perimeter and then move inside the plotted area in parallel lanes / stripes and each time it meets an obstacle it goes around it and resumes it's lane when the obstacle has been cleared.

i think i'm going to keep my method for the programming using switch(mode).

It seems like some of you are interested about this project so perhaps I'll make a topic somewhere so you could follow it.

In case you are wondering if this project is to difficult for me. I'm in second year of engineering at the UCL (Belgium). Last year I won with a friend an yearly contest between all the first year students (approx 600 students). We maked a weather station connected to thingspeak's servers with an android app to display the measures. So doing big projects which needs time and effort doesn't scared me at all. And I also designed my own corexy 3d printer from scratch. (And it is working pretty well until know !)

For the moment, my mower is doing these tasks :

  • goes out of charging station

  • follow the boundary wire to be sure that all the perimeter is perfectly cut once until it's back to the station

  • start to mow and each time it sees the wire or hit an obstacle, turn of 175°, 120°, depending on the pattern (off course it needs tests but that's the general idea)

  • when the battery is low, find and follow the boundary wire to the station and charge.

  • if the mower is lifted from the ground, stop everything until it's back on it

During all these task, it will avoid obstacles somehow according to the current mode it's into. (like when it's following the wire it must go around the obstacle to find the wire back.

This is only a small part of all the things I've already thought about !

You should be able to get it to work using interrupts. However, you have to remember that your ISR cannot block. Ever. So those while loops inside readAngles() would need to be eliminated. Get some queues and flags so that the ISR only services the hardware and sets status flags.

You seem to be implementing a sort of multitasking kernel, with two priorities. This is actually a really good idea. However, you're in a "nice guy" environment where none of your tasks can hog the processor or bad things will happen. If any of your tasks block, you should re-engineer them so that you can continue with other tasks until the required events happen.

Thanks Jimmus !

I knew while loops are to be banned from this code, thanks for pointing this point in case I didn't knew it ! So basically I CAN'T use any while loop except if I want my code to do mad things.

I saw some people who make for the loop to be executed at a certain frequency. Is there any advantage ? I know it's a good thing for the PID control but the library already does that for me. According to me, checking all my conditions as fast as possible is the best way. Am I right ?

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html . Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks. Tom.. :slight_smile:

MOCmaniac:
I saw some people who make for the loop to be executed at a certain frequency. Is there any advantage ? I know it's a good thing for the PID control but the library already does that for me. According to me, checking all my conditions as fast as possible is the best way. Am I right ?

I think you are correct. I don't think you care exactly when your loop is executed, as long as it is often enough to handle the events that happen. Adding extra complexity to control exactly when it is called will slow it down. I don't see any reason why you would want to do that.

SOLUTION + CODE EXAMPLE

I took a look at finite state machine and based my code on the same working principle. And it’s working pretty well for the moment !

My robot goes 5 seconds forward, stop for 1.5 second, goes backward for 5 seconds, stop 1.5 second and repeat the loop.

Hope this example will help someone (contains only the necessary functions).

The other files are in attachment (otherwise : The message exceeds the maximum allowed length (9000 characters).

States :

enum States {STOP, FORWARD, BACKWARD, TURN};
int state = STOP;
int previousDrivingState = BACKWARD;
unsigned long timer = millis();
const int STOP_DELAY = 1500;
const int DRIVING_DELAY = 5000;

void updateStates() {
  switch (state) {

    case STOP:
      Serial.println("STOP");
      stopAll();
      if (millis() - timer > STOP_DELAY) {
        if (previousDrivingState == FORWARD) {
          state = BACKWARD;
        } else {
          state = FORWARD;
        }
        timer = millis();
      }
      break;

    case FORWARD:
      Serial.println("FORWARD");
      forwardCompass(0);
      if (millis() - timer > DRIVING_DELAY) {
        previousDrivingState = state;
        state = STOP;
        timer = millis();
      }
      break;

    case BACKWARD:
      Serial.println("BACKWARD");
      backwardCompass(0);
      if (millis() - timer > DRIVING_DELAY) {
        previousDrivingState = state;
        state = STOP;
        timer = millis();
      }
      break;

    default:
      Serial.println("ERROR");
      break;
  }
}

MOCmowerV1.1.ino (199 Bytes)

MPU6050.ino (4.93 KB)

Robot.ino (2.65 KB)

States.ino (1.07 KB)

hi, i love the idea , cant offer any programming suggestions yet but you might like to try adafruit bnoo55 instead of your mpu6050 i think you will get much more precise control very easy .

Thanks Ronald !
My robot is currently able to move as intended in my house. I added a proximity sensor at the front (HC-SR04) as an obstacle detector. My MPU6050 sometimes goes crazy, googling the problem brings me back to this forum. Apparently it's a common problem on these cheap boards. I'll fix the capacitor and resistors value first then I'll upgrade it for a more reliable one. My robot is also in a test phase, I want to see if I'm able to complete the project (especially at the code level) before buying kinda expensive sensors. I'm only 19 so I think twice before starting a big project like this one. I want to be sure it won't be a failure