The Lawnmower Robot

Introduction: The Lawnmower Robot

"A beautiful Lawn doesn't happen itself"

When a Lawn is not well maintained, it turns into a grassland (there is a significant difference between both).

When it comes to maintaining lawns, mowing is the most tedious task which is not only dull but also highly repeatable and often consumes huge numbers of the human and material resource. To cut down on the consumption of the protection of lawns, we think of an idea to make an intelligent lawn mower which can replace the traditional lawn mower.

A normal intelligent lawn mower consists of the perception system, the control system, the moving system and mowing system. The perception system can detect the environmental values, the moving mechanic and the mowing mechanic and send the results to the control system. The control system can compare the data sent from the perception with that in its database and correct instructions for the moving and mowing mechanics to get a stable running situation. Compared with the traditional lawn mower, the intelligent lawn mower has advantages of the environmental protection, the low human power consumption and high security.

An intelligent lawn mower is worth studying and has large quantities of commercial values, social values and academic values, which can make reflections on the development of robotics and automatics indirectly.

Our aim was to work as a team and we planned tasks and split among ourselves which benefited for the results. Our team composition was a good mixture of multi-talents and multicultural colleagues.

Step 1: Mechanical Design

The 3D designing has been done with Catia V5. Individual structural parts were created separately and assembled in an assembly file. A '.STL' format of the assembly is available for viewer's reference.

After brainstorming, components that could be used for the robots were roughly drafted. The interfaces that need to be provided for a commercial component to fit in was provided in a generic manner in the initial stages. Later up on procurement of actual parts like motors, sensors we refined their interfaces in later stages before Laser cutting.

Structural rigidity: The body parts are assembled with each other by means of small assembly protrusions. Apart from that, we have used L-clamps as shown in images to assemble the body parts as it could make the structure firm and rigid. The L-clamps was manufactured through 3D printing.

Drive: For the Lawnmower, we have used Continuous tracks instead of individual Rotary wheels. Compared with wheels, continuous tracks have high performance and optimized traction system, which is a plus in power delivery efficiency. Also, the traction is high even on slippery surfaces like snow or wet concrete (conditions of a Lawnmower)

Bumpers and Sensors: Practically speaking, there are a lot of chances for a robot in lawn to face numerous obstacles like a light post, fence, Rocks, etc. So it is essential to provide a safety mechanism in order to save it from damage. Bumpers are given for the robots in the front which uses a limit switch operation. When the bumper hits the smaller obstacles in front, the robot changes its direction. Apart from the Bumpers, Ultrasonic sensors are provided to sense obstacles from a range of distance.

Pretension Mechanism: For a Lawnmower, it is common to have different terrestrial surfaces. Of that, wet surfaces, muddy terrain, rocks, and stones are quite challenges. In order to achieve traction even during small obstacles, the driving tracks should be flexible (dynamic) a bit to be able to climb or move over it. We have achieved such dynamics in the tracks using tensile spring and giving force to only the top wheels on each side.

Step 2: Components Required

    • Structure/Body - 5mm clear Plexiglass: Laser Cut
    • L-brackets, Fixtures, Peripheral parts: 3D printed
    • Tracks and wheels: Procured from Commercial market (check here)
    • DC geared motors (2): for Driving wheels type: ( jga25-370-12V-120)
    • Brushed DC gear motor (1): For blades (6-24 V/0.240A/ 11 000 RPM) MO103 ELAK electronics
    • Cooling fan (1): as Heatsink (12 volts)
    • Ultrasonic Sensors (2): 1 parallax ping, 1 hc sr04. or the use of 2 hc sr04 is possible.
    • Battery 12V DC - (1)
    • Arduino-Mega (1)
    • Adafruit motor shield Version 1
    • 6P toggle switch (1)
    • Tactile Bump Sensor (2)
    • Other fasteners

    Why we chose it?

    DC geared motors (2): These motors are meant for the wheels of the robot where we require high torque and Low speed. High torque helps in load pulling and since Lawn mowing is a slow operation, we only need low-speed motors. It is also vital that we use a geared motor for better power transmission and to avoid damaging the motor coils. RPM of the DC geared motors was 120 RPM with high torque reaching 8 kg.cm.

    Brushed DC gear motor (1): This motor is responsible for the cutting action of grass. So we have decided to use High RPM low torque motor. It is also essential that the blades do not get stuck while cutting the grass. So minimum torque is also considered.

    Adafruit motor shied: This board is capable of driving 4 dc motors, and can withstand maximum current of 2 Amp per channel. Which perfectly fits the current requirement, taking into consideration the stall current of the DC motor and different operating points.

    Arduino Mega: More digital pins and analog pins than Arduino Uno. Since a lot of sensors were used leading to the use of a lot of pins. Arduino mega was the best fit for the robot's brain.

    6P toggle switch: The need for 6 pin toggle switch was driven by the advanced enhancement of the grass cutting robot. Two modes where embedded; first mode was the automatic mode moving in random motion depending on sensors, the second mode was manual mode driven by a joystick. So the toggle switch will ensure the transition between those two modes.

    Cooling fan: The Major enemy of electronics is heat. So a cooling fan is chosen with specification: 12Volts, 0.3 Amps. the robot is to cut grass, so it will be working for a time more than 1 hours hence this justifies the need of cooling fan for electronics to ensure the optimal performance and power consumption.

    NOTE: Joystick will be further discussed in the further steps.

    Step 3: Body Works

    Helpful process:

    • Laser Cutting (Plexiglass material structure)
    • 3D printing (Peripheral parts of the robot)
    • Assembly

    Designs were done with the help of Catia V5. We also made sure that the interface given for commercial components like motors, sensors, drive unit was appropriate from the information gathered.

    Laser Cutting: After designing the whole robot, the individual body parts were produced through Laser cutting of Plexiglass. Files in .DXF format were used for Laser cutting.

    3D printing: The other sub-components like Bumpers, L-clamps, Battery holders, etc. were manufactured through 3D printing at the Robotics Laboratory at the VUB premises. We used PLA material (polymer) for the parts.

    Later parts were assembled to become the whole body with the help of fasteners.

    Step 4: Circuit and Programming

    Circuit:

    Fritzing software was used to design and plan the circuit. The circuit figure is clear and easy to connect. Some details about circuit :

      • For ultra-sonic: two digital pins are dedicated from the arduino for trigger and echo( trigger write, echo read)
      • For limit switch: one digital pin is dedicated from the Arduino as read.
      • For the DC driving motors: two wires were taken from each channel of the motor shield to connect the motor
      • For the cooling and cutting: directly power by the battery without passing through motor shield ( for current limitations of motor shield)
      • Toggle switch: connects the positive of battery to the motor shield power pin, also one pin is dedicated form the toggle switch to connect with one digital read pin in the Arduino which act as mode detector ( manual, automatic) if the toggle switch is in the upward position the pin reads high ( +ve connects with pin) and vice versa if toggle switch is downward( ground connects with pin)
      • All the ground and +5volts of the sensors were taken from board design to take one positive and one ground from the Adafruit shield and distributes them on several output pins.( bread board would help but wouldn't be professional)

      Components connection:

      • Limit Switch: limit switch has 3 pins: normally closed(NC), normally open (NO), and common(com). the com pin is associated with a read pin in the Arduino, while NC is associated to ground and NO to +5Volts. The Arduino reads low when the switch is not engaged so the robot keeps on moving forward, when it is toggled the Arduino reads hight, then sends a command to the driving motors to move back then turn in the opposite direction of the toggled switch( if left switch is toggled the robot moves back then turns right)
      • Ultra Sonic sensor: the trigger and echo pins of the US sensor is associated to read pins in the Arduino. It reads the distance up to 500 cm, one can set the minimum distance where the robot detects an obstacle and sends a command to the motors to turn in the opposite direction of the first sensor that detects the minimum distance. ( if the left US sensor detects an obstacle at 20 cm away from the bot then the robot turns right)
      • Parallax PING Ultrasonic Sensor: this sensor uses two pins to get powered, and one pin that acts as trigger and echo, hence one read pin associated.

      • DC driving motors: the two driving motors are connected to the channels of Adafruit, one must take care of the correct connection of the motors with channels and flip the wire connection if necessary since the Arduino doesn't know the direction the motor is turning in.

      Frequencies for channel 1 & 2 are: MOTOR12_64KHZMOTOR12_8KHZ, MOTOR12_2KHZ, MOTOR12_1KHZ.

      Frequencies for channel 3 & 4 are: MOTOR34_64KHZ, MOTOR34_8KHZ, MOTOR34_1KHZ.

      Note: Higher frequencies will produce less audible hum in operation, but may result in lower torque with some motors.

      • 6P toggle switch: the toggle switch has two common pins in the middle and 2 upper pins and 2 lower pins. The first column of the switch is dedicated to power from battery where the common middle is associated with the +ve motor shield power channel while the upper and lower is dedicated to the battery +ve cathode. The second column is dedicated to the mode of the robot, where the common is connected to a read pin of the Arduino while the upper is connected to the ground of Arduino and the lower pin is connected to +5Volts. In this case, the Arduino is programmed that if it reads high from that pin it will work with mode1 which is automatic, and if it reads low it will work with mode2 which is manual. It all depends on the position of the toggle switch, in both positions upper and lower, the power is ensured with the 1st column connection.
      • Cooling fan and Cutting motor: One can connect the two motors also with channels from Adafruit motor shield but considering the limitations of the motor-shield current, and to prevent any probability of burning the board, the two motors were directly connected to the battery supplying 12Volts. Considering that the two motors ratings work with 12 volts and that both motors are required to function at the high RPMs to ensure the wanted performance.

      Code: code is uploaded to a file where every line has a comment that explains what you need to know. It is a well-structured code programmed to ensure the best performance of the robot. The user is capable to change different variables such as ( minimum distance where the robot should turn, the angle the of rotation while turning left or right by adjusting the delay, the backward distance covered by adjusting the delay...)

      Note: instead of two HC-SR04 sensors, one HC-SR04 was used and the other was Parallax PING Ultrasonic Sensor. Both function the same with a little bit difference in the pin connection and coding, but one can use two HC-SR04.

      Arduino Main Program:

      #include <br>#include 
      void setup() {
        Serial.begin(9600);
      }
      void loop() {
        // Set the mode of the robot for manual or automatic// 
        //==================================================//
        int m=53;
        pinMode(m, INPUT);
        //int  mode=digitalRead(m);// read switch value//
        int mode=0;
       
        //==================================================//
        // if switch set up then automatic mode is set//
        //=======================================================================================================================//
        //=======================================AUTOMATIC MODE=================================================================//
        if(mode==0)
       {int d=25;                         // distance where ultra sonic sensors tell the robot that is should rotate// 
        int dm=5;                        // offset from ultra sonic sensor detects untel 5 cm ( since one of the sensors reads zero between the readings//
        long L=LimitSwitchLeft();        // set variable L showing the condition of the left limit switch (0 not toggeled)//
        long R=LimitSwitchRight();      // set variable R showing the condition of the Right limit switch (0 not toggeled)//
        long UL=readPingLeft();        // read the value of left ultra sonic sensor//
        long UR=readPingRight();
        Serial.print(UR);// read the value of right ultra sonic sensor//       
       MoveForward();                // tell the robot to move forward// 
          if (L==1 || R==1)          // check condition if one of the limit switches is hit then the robot should move back and turn in the opposite direction of that switch// 
      { MoveStop();
        delay(1000);
        MoveBackward();
        delay(2000);
        MoveStop();
        delay(1000);
        if((L==1 && R==0) ||(L==1 && R==1)){MoveRight();
                                            MoveStop();
                                            delay(400);}
        if(L==0 && R==1){MoveLeft();
                         MoveStop();
                         delay(400);}  
      }
       if ((UL>dm && ULdm && URdm && ULd)){MoveLeft();
                       MoveStop();
                       delay(400);} 
         }
        }
       //============================================================================================================================//
       //======================================== MANUAL MODE CODE==================================================================//
      else if (mode==1) 
             {
               int xpin= A15;
               int ypin= A14 ;
               int m=53;
               pinMode(m, INPUT);
               int vx=analogRead(xpin);
               delay(50);
               int vy=analogRead(ypin);
               delay(50);
               int s=s=digitalRead(m);
               Move(vx, vy,s);}
        
      }
      //===========================================================================================================================//
      //===========================================================================================================================//
      //========================================================FUNCTION USED===================================================================//
      //===========================================================================================================================//
      //===========================================================================================================================//
      // Function that turns on fan
      void Fan() {
           AF_DCMotor fan(3, MOTOR34_64KHZ);
           fan.run(BACKWARD);
           fan.setSpeed(100);
      }
      //=========================================================//
      // Function that turns on the cutter//
      void cutter() {
           AF_DCMotor cutter(4, MOTOR34_8KHZ);
           cutter.run(FORWARD);
           cutter.setSpeed(255);
      }
      //=========================================================//  
      //=========================================================//        
      // Function that reads the ultrasonic left sensor distance
      // returns its value in cm
      int readPingLeft() { 
        delay(70);
        long  duration,  cmL;
        const int pingPin = 31;// left ultrasonic sensor pin 
        pinMode(pingPin, OUTPUT);
        digitalWrite(pingPin, LOW);
        delayMicroseconds(2);
        digitalWrite(pingPin, HIGH);
        delayMicroseconds(5);
        digitalWrite(pingPin, LOW);
        pinMode(pingPin, INPUT);
        duration = pulseIn(pingPin, HIGH);
         cmL = duration/29/2;
       return cmL;
      }
      //=========================================================//
      // Function that reads the ultrasonic right sensor distance
      // returns its value in cm
      int readPingRight() { delay(5);
        #define TRIGGER_PIN  49 
        #define ECHO_PIN     45
        NewPing sonar(TRIGGER_PIN, ECHO_PIN, 200);
        delay(70);                     
        unsigned int cmR = sonar.ping()/US_ROUNDTRIP_CM;
        return cmR;
        
      }
      //=========================================================//
      //=========================================================//
      // Function that reads the Limit Switch Left sensor 
      // returns 1 or 0
      int LimitSwitchLeft() { 
           int SwitchpinL=39;
           int SwitchstateL=0;
           pinMode(SwitchpinL, INPUT);
           SwitchstateL=digitalRead(SwitchpinL);
           return SwitchstateL;
      }   
      //=========================================================//
        // Function that reads the Limit Switch Right sensor 
       // returns 1 or 0
      int LimitSwitchRight() { 
           int SwitchpinR=38;
           int SwitchstateR=0;
           pinMode(SwitchpinR, INPUT);
           SwitchstateR=digitalRead(SwitchpinR);
           return SwitchstateR;
      }   
      //=========================================================//
       // Function that moves the robot forward
      void MoveForward() { int speedSet=0;
           AF_DCMotor motorLeft(1, MOTOR12_8KHZ);
           AF_DCMotor motorRight(2, MOTOR12_8KHZ);
           
           motorLeft.run(FORWARD);
           motorRight.run(FORWARD);
          
                    motorLeft.setSpeed(255);
                    motorRight.setSpeed(255);
                 
      }
      //=========================================================//
      // Function that moves the robot backward
      void MoveBackward() { int speedSet=0;
           AF_DCMotor motorLeft(1, MOTOR12_8KHZ);
           AF_DCMotor motorRight(2, MOTOR12_8KHZ);
        
           motorLeft.run(BACKWARD);
           motorRight.run(BACKWARD);
           for (speedSet = 0; speedSet < 250; speedSet += 2) // slowly bring the speed up to avoid loading down the batteries too quickly
               {
                    motorLeft.setSpeed(speedSet);
                    motorRight.setSpeed(speedSet);
                    delay(5);
                 }
      }
      //=========================================================//
      // Function that moves the robot Left
      void MoveLeft() {
           AF_DCMotor motorLeft(1, MOTOR12_8KHZ);
           AF_DCMotor motorRight(2, MOTOR12_8KHZ);
          
           motorLeft.setSpeed(250);
           motorRight.setSpeed(250);
           motorLeft.run(BACKWARD);
           motorRight.run(FORWARD);
           delay(1000);
      }
      //=========================================================//
      // Function that moves the robot Right
      void MoveRight() {
           AF_DCMotor motorLeft(1, MOTOR12_8KHZ);
           AF_DCMotor motorRight(2, MOTOR12_8KHZ);
       
           motorLeft.setSpeed(255);
           motorRight.setSpeed(255);
           motorLeft.run(FORWARD);
           motorRight.run(BACKWARD);
            delay(1000);
      }
      //=========================================================//
      void MoveStop() {
           AF_DCMotor motorLeft(1, MOTOR12_1KHZ);
           AF_DCMotor motorRight(2, MOTOR12_1KHZ);
       
        motorLeft.run(RELEASE);  
        motorRight.run(RELEASE);
        delay(5);
      }
      //======================================================================================================================================================================//
      //======================================================================================================================================================================//
      //======================================================================================================================================================================//
      //================================================== JOY STICK FUNCTIONS===============================================================================================//
      //======================================================================================================================================================================//
      //======================================================================================================================================================================//
      //======================================================================================================================================================================//
      void Move(float vx,float vy, int s)
      {          float v1=((vx-509))*255/514;
                 float v2=((vy-521))*255/502;
                  AF_DCMotor motorLeft(1, MOTOR12_8KHZ);
                  AF_DCMotor motorRight(2, MOTOR12_8KHZ);
                  motorLeft.setSpeed(abs(v1));
                  motorRight.setSpeed(abs(v1));
                  if(v1<0)
                  { if( vy>519 &&vy<522)
                  {motorLeft.run(FORWARD);
                  motorRight.run(FORWARD);
                  motorRight.setSpeed(abs(v1));}
                    if( vy>523)
                  {motorLeft.run(BACKWARD);
                  motorRight.run(FORWARD);}
                  if( vy<518)
                  {motorLeft.run(FORWARD);
                  motorRight.run(BACKWARD);}
                  }
                   if(v1>0)
                  { if( vy>519 &&vy<522)
                  {motorLeft.run(BACKWARD);
                  motorRight.run(BACKWARD);
                  motorRight.setSpeed(abs(v1));}
                    if( vy>522)
                  {motorLeft.run(FORWARD);
                  motorRight.run(BACKWARD);}
                  if( vy<518)
                  {motorLeft.run(BACKWARD);
                  motorRight.run(FORWARD);}
                  }      
                  
        }

      Step 5: Testing

      We tested the Robots for various scenarios and following were some key tasks it could do:

      • Lawn Mowing - Automatic mode - random motion
      • Detection of blockades
      • Sensing obstacles
      • Lawn Mowing - Manual mode - using Remote control
      • Parking the mower in a compact space

      Step 6: Advanced Joystick Control

      Joystick:

      As it is well know that random motion for a lawn mower would sometimes lead to uncovered spaced, it all depends on how random is random. So we decided to go with a more advanced option which allows the user to manually control the lawn mower with a joystick. This, in fact, adds a little bit fun to the project, where the user can manually control his grass cutting robot that looks like a tank which adds more fun in controlling manually this robot.

      How Arduino joystick works:

      • The joystick in the picture is nothing but two potentiometers that allow us to measure the movement of the stick in 2-D.
      • Powered by two pins Vcc and ground.
      • reads from 3 pins
      • 1 pin for vx which reads values due to resistance in x-direction
      • 1 pin for vy which reads values due to resistance in y-direction
      • 1 pin for a switch which reads high or low
      • sensors are characterized by a value between 0 and 1024.

      Circuit Connection:

      The joystick is powered by two pins +vcc and ground.

      Associating two read analog pins for the vx and vy from the Arduino mega.

      The Challenge:

      The challenging part was how to transform from the values read by the pins which are (0 to 1024) to commands for the motors and the direction of movement. It is well known that the Adafruit motor shield has valid values for 'speed' between 0 and 255 with 0 being off and 255 at full throttle. One can develop a certain algorithm to control the motors using the joystick.

      The Solution:

      One can read the values from the joystick with two read pins. The center position the vx and vy pins read 512 normally but with offsets sometimes due to the quality of electronics. We can set a new variable v1 and v2, where v1=(vx-512)*255/512, which transforms the value of readings from joystick to a scaling of -255 till 255. Now it is easy to determine the speed which we should set the motors to move at based on the position of the joystick. To determine the direction, in which one can distinguish different cases:

      • if v1 is positive while v2 remains zero, the joystick is toggled in the forward position without any direction. In this case, both motors move forward.
      • if v1 is negative while v2 remains zero. the joystick is toggled in the backward position without any direction. In this case, both motors move backward
      • if v1 is positive and v2 positive, the joystick is toggled in the upper right direction, in this case, the robot should move right, hence left motors is toggle forward and left motor is toggled backward.
      • The rest of the cases should be clear as it is demonstrated in the Arduino code the last function (joystick mode)

      Step 7: Going Further

      It cost less than €120 for us to build this lawnmower robot which is simple and effective by all means.

      The following are some interesting additional features that could improvise this project.

      • Grass detection system: When our robot runs off from the lawn, it could not detect the terrain and get back to the Lawn. We can avoid this by adding color sensors.
      • Robot Path programming: Definite trajectories of the robot movement can be controlled through programming based upon requirement.
      • Mowing level adjustment: One can wish to have different levels of grasses based on his requirements. It is possible to advance the robot design such that we can define the trimming level of the grass. It would be as useful as possible.
      • Sensors on all sides: In this robot, we have sensors only on the front side of the robots thereby sensing obstacles only on the front. We can improvise it more by adding sensors on all sides.
      • Display Screen: With more advancement, it is essential for a user to know how long can the robot operates. So, giving LCD to the robot will be essential for a user to identify some parameters like the need for charging, Full-charge, etc.
      • Mobile monitoring: By staying inside the home, one can locate the position of the robot or control the movement of the robots. An app could be handy in smartphones for this purpose.

      Step 8: Credits

      Team:

      • Karim Shhaitly
      • Omidreza Kamalian
      • Nabil Zouaoui
      • Anand Varadharajan
      • Zhe Wang

      Instructors:

      • Prof. Dr. Ir. Bram Vanderborght
      • Ir. De Beir Albert
      • Ir. Hoang-Long Cao

      Share

        Recommendations

        • Water Contest

          Water Contest
        • Fix It! Contest

          Fix It! Contest
        • Metalworking Contest

          Metalworking Contest

        Discussions

        Heartily Congratulations Anand.. Good to see your work..
        The Bumper Design looks infinity awesome..
        Also it's good to see both Manual and Automatic modes.