An autonomous roving CNC weeding/cultivating machine guided by GPS and coloured markers.

Similar projects worth following
Two years ago I initiated the Weedinator Project to fight back against the onslaught of weeds which threatened to dominate the leeks that I was growing. In the meantime, the weeds seem to have adapted to my mechanised approach and the war is far from over.

I am now ready to take the fight to a higher level with an autonomous GPS/Objects guided roving CNC machine.

In the world of professional agriculture, a lot of focus has been put on large, incredibly expensive machines that work in huge open fields where just one crop is grown. Whilst this is incredibly efficient and produces very cheap food, it's not good for pretty much everything else!

There does exist a substantial backlash against this farming model where small farmers grow 'organic' vegetables on small farms with respect to the environment and indigenous wildlife. Some might call this the 'Permaculture' movement, but I'm really not sure if permaculture would embrace modern 'robot' technology or not as historically robots take away people's jobs and help destroy communities.

Here I introduce the Weedinator - an autonomous agricultural electric tractor that can be used on small farms to cultivate, till and weed seed beds. It can travel up and down 56 inch wide beds, several times a day if necessary, performing a multitude of quite delicate tasks which a big tractor might struggle with. Some of the key advantages are:

  • Less need for heavy cultivation such as ploughing which destroys soil structure.
  • Preservation of soil health by keeping essential natural micro-organisms and nutrients near the top of the seed bed rather than burying them.
  • No fumes or pollution especially in glasshouses or polytunnels.
  • Will help small farms compete financially with big industrial producers.

Will the Weedinator destroy jobs or will it encourage lots more people to set up small farms and help protect the environment?

Last year's efforts resulted in a tractor mounted weeding machine which worked reasonably well except for the fact that it was not accurate enough and sometimes ended up destroying the leeks as well as the weeds. The video below shows the results:

Since then I have been exploring CNC, GPS and GPRS technology and feel 97.2% confident that I can create a roving weeding machine that can also perform other tasks such as cultivating (digging) and mowing with the right attachments. Think 'Moon buggy' or the 'Mars Rover' and that will be what I'm aiming for. Actually, there is already an open source project for the CNC part - the Farm Bot.

The machine will carry it's own electric generator running on gas/diesel and be propelled forwards/backwards/sideways with stepper motors/servos. Coloured markers, detected by an object recognition system, will be placed in the soil to create grids for the Weedinator to work within as GPS is not accurate to the scale of 1 mm which will be necessary to avoid killing the crops. GPS will be used to navigate to particular fields or seed beds.

As time goes on a more intelligent object recognition system will be incorporated to detect individual weeds:

The flame thrower will be mounted on a normal CNC frame with 3 axis of movement and the nozzle itself will be shrouded by metal sheet to prevent damage to the crops themselves. Individual weeds could be zapped by a small gas powered butane torch as used by a chef when making crème brulee.

This may seem like a very ambitious project, but the actual chances of achieving success are quite high. Much of it depends on the quality of the code written for reading the GPS data and transforming that into real-time steering and motion. It all just seems like great fun to me!

Programming new coordinates into the Weedinator via the cell phone network is not going to be difficult as much of the task of handling GPRS data has already been covered in my weather station project.

There is a risk that as the project evolves we will run out of programming space or computing power on the MCU ...... So ....... Just add another one and get them talking to each other via the I2C bus, which I also had up and running on the weather station project, although my code for this communication does now seem a little bit 'clunky'.

The greatest 'risk' is due to the cost involved in buying all the components - the GPS system is expensive...

Read more »


First part of the set of instructions for building the machine.

Adobe Portable Document Format - 2.29 MB - 11/13/2017 at 15:16


Components list 01.xlsx

Electronic components

sheet - 11.12 kB - 08/28/2017 at 09:07


weedinator 01.wav

The next Weedinator video is going to need a sound track. Here's a snapshot of what it might comprise.

Waveform Audio File Format (WAV) - 8.93 MB - 05/20/2017 at 09:45


Adobe Portable Document Format - 1.59 MB - 05/07/2017 at 13:01


Adobe Portable Document Format - 1.23 MB - 05/07/2017 at 13:01


View all 15 files

  • WEEDINATOR Does Doughnuts

    TegwynTwmffat☠01/28/2018 at 15:34 0 comments

    The control system has been switched to a 3 core MCU running at 200 MHz, the 'ShieldBuddy'. This enabled the whole steering and drive system to be hosted on one device. The first core runs 330 lines of code to control the stepper motors with full differential on both the steering and drive, using the 'micros' function. The next core has serial debugging and a 4 second delay so that it can be read easily. The third core oversamples some potentiometers to control the machine on a 5 core cable.

    /*** Don't worry, the normal Arduino setup() and loop() are below this block! ***/
    /* LMU uninitialised data */
    /* Put your LMU RAM fast access variables that have no initial values here e.g. uint32 LMU_var; */
    /* LMU uninitialised data */
    /* Put your LMU RAM fast access variables that have an initial value here e.g. uint32 LMU_var_init = 1; */
    const int ledPin =  13;
    int ledStateOne = LOW;   
    int ledStateTwo = LOW;   
    int ledStateThree = LOW;
    int ledStateFour = LOW;
    unsigned long previousMicrosOne = 0;
    unsigned long previousMicrosTwo = 0;
    unsigned long previousMicrosThree = 0;
    unsigned long previousMicrosFour = 0;
    long intervalOne = 1000;
    long intervalTwo = 1000;
    long intervalThree = 1000;
    long intervalFour = 1000;
    int difference=0;
    int previousFinalSteeringValue=15300;
    long rightWheel=0;
    long leftWheel=0;
    long wheelsPosition=0;
    int finalDriveValue=0;
    long finalSteeringValue =0;
    /*** Core 0 ***/
    void setup()
      pinMode(ledPin, OUTPUT);
      pinMode(5,OUTPUT); //STEP
      pinMode(6,OUTPUT); //DIRECTION HIGH is clockwise
      pinMode(7,OUTPUT); //STEP
      pinMode(8,OUTPUT); //DIRECTION HIGH is clockwise
      pinMode(9,OUTPUT); //STEP
      pinMode(10,OUTPUT); //DIRECTION HIGH is clockwise
      pinMode(11,OUTPUT); //STEP
      pinMode(12,OUTPUT); //DIRECTION HIGH is clockwise
    void loop()
      unsigned long currentMicrosOne = micros();
      unsigned long currentMicrosTwo = micros(); 
      unsigned long currentMicrosThree = micros();
      unsigned long currentMicrosFour = micros();
    if (finalDriveValue>=600) //Forwards.
      intervalThree = (600000/finalDriveValue)-300; // 250 is max speed.
      intervalFour =  (600000/finalDriveValue)-300; // 250 is max speed.
      if (currentMicrosThree - previousMicrosThree >= intervalThree)
        digitalWrite(9,ledStateThree); // Drive motor step
      if (currentMicrosFour - previousMicrosFour >= intervalFour)
        digitalWrite(11,ledStateFour); // Drive motor step
    if (finalDriveValue<400) //Backwards.
      intervalThree = (finalDriveValue*2)+250; // 250 is max speed.
      intervalFour = (finalDriveValue*2)+250; // 250 is max speed.
      if (currentMicrosThree - previousMicrosThree >= intervalThree)
        digitalWrite(9,ledStateThree); // Drive motor step
      if (currentMicrosFour - previousMicrosFour >= intervalFour)
        digitalWrite(11,ledStateFour); // Drive motor step
      difference = finalSteeringValue - previousFinalSteeringValue;
      if((difference>500)&&(wheelsPosition>=0)) // Clockwise from the centre
        if (currentMicrosTwo - previousMicrosTwo >= intervalTwo) // Right wheel (SLOW)
          digitalWrite(7,ledStateTwo); //STEP
        if (currentMicrosOne - previousMicrosOne >= intervalOne) // Left wheel (FAST)
          digitalWrite(5,ledStateOne); //STEP
          previousFinalSteeringValue++; // This must be within backets containing 'changeStateOne'.
    Read more »

  • Differential Steering Geometry

    TegwynTwmffat☠01/23/2018 at 10:44 0 comments

    If the WEEDINATOR is navigating a turn and has it's inside wheel at 45 degrees, the outside wheel is NOT 45 degrees, it's more like 30 degrees. Also, the inside wheel may be turning at 1 km/hour, but the outside wheel will be significantly faster, more like 1.35 km/hour.

    When working out the geometry, a few assumptions are made:

    • The chassis will pivot about one of the back wheels as shown in the diagram above.
    • The effective centre of the pivot circle will move along a line extended from the centres of the two back wheels, depending on the angle of turn.
    • The geometry will take the form of a sine curve.

    A full scale drawing was made of the WEEDINATOR front wheels and chassis with 8 different permutations of inside wheel angle between 0 and 90 degrees and the respective turn centres were mapped out as shown in the drawings above.

    The effective radii were measured from the drawing and plotted on a graph in Microsoft Excel.

    Two graphs were produced, one of the ratio of the left and right front wheel axles and another for the ratio of the two radii for each particular turn angle.

    I then 'fudged' up some formulae to mimic the empirical results based on a sine curve. One of the fudgings looks like this:

    speedRatio= (sin(inner*1.65*pi/180)+2.7)/2.7;      // inner is the inner turn angle.

    The curves were fudged by changing the values shown in red in the excel file until the curves fitted together.

    Full details and downloadable files are shown here:

  • Weedinator does a 3 Point Turn

    TegwynTwmffat☠01/17/2018 at 18:07 0 comments

  • Maiden Voyage of the Weedinator

    TegwynTwmffat☠01/15/2018 at 13:23 2 comments

  • More GNSS Tests

    TegwynTwmffat☠12/20/2017 at 19:02 0 comments

    You really can't have enough graphs in a project and testing the Sat Nav always produces a shed load of data. This time the Base and Rover are separated by 100 m to see what error, if any, is added. I can't decern any noticeable additional error at all. The 'Fix' was obtained at about 1650 on the horizontal and from then on the total error was pretty much 40 mm, as before :)

  • Ublox Accuracy

    TegwynTwmffat☠12/13/2017 at 10:36 0 comments

    I managed to hook up a datalogger to the Weedinator control board via I2C and get some idea of the Ublox M8M Satellite positioning performance:

    On 'Cold Start', the module started off with lots of error and gradually the error became reduced until, after about 2 hours, it got a RTK fix between rover and base (shown as the red cross). During that 2 hour period, the base module is continually building up and updating an average value for latitude and longitude and after the pre-programmed time interval decides that it has got a good fix.

    The next 2 graphs shows behaviour after a 'Hot start' where the base module has already calculated a good average. The top graph is over a 200 minute period and occasionally the fix is lost and the rover sends a NMEA message to the Weedinator that the fix has temporarily become unreliable.

    The lower graph is a 'zoom in' on the red box in the top graph and shows a good representative snap shot of the Ublox performance, with total deviation of 40 mm, with is good enough to guide the Weedinator to it's loacation, but possibly not good enough to cultivate the soil around individual plants?

  • Data Flow Diagram

    TegwynTwmffat☠12/11/2017 at 14:38 2 comments

    I thought it would be interesting to map out how the data flows between the various modules:

    The intention is to offload all of the control modules away from the Master, the Arduino Due, so that any timing issues can be avoided - some of the modules use multiple timers and interrupts which would conflict with each other if they were on the same MCU.

    The Spark fun compass would only work on the Due itself and even then only through the serial port rather than I2C, which would have been preferred. Coincidentally, it's the only module that is not giving reliable results, so I figure it will need to be replaced at some stage.

    Good news is that everything else works nicely and the data flows around the modules without any glitches. Especially remarkable is the Ublox C94 M8M, which is working much better than previous tests suggested. I'm going to try and do some long term data logging to greater assess it's performance, but currently it seems to be giving reliable fixes within a total deviation of 40 mm (20mm either sides of centre) about 95% of the time. (Must brush up on some statistical analysis maths).

  • 3D Animations

    TegwynTwmffat☠12/06/2017 at 12:54 0 comments

  • Bearing and Distance Operational

    TegwynTwmffat☠12/03/2017 at 16:52 0 comments

    The Ublox C94 M8P has been configured to provide a heading and distance to my nearest town :

    Obviously I don't want the machine to actually go there - it's just a test to see if I'm getting correct results.

    The software used is by SlashDevin - NeoGPS. Special attention was required to get the baud rate selected properly for all functions of the Ublox to work (19200), most importantly it's ability to get a fix between the Rover and Base station. The base just sits on a pole somewhere and using the two as a pair error correction due to atmospheric anomalies can be achieved.

  • Control Panel Getting Populated

    TegwynTwmffat☠12/01/2017 at 12:53 2 comments

    The PCBs arrived from Elecrow, China, and immediately became populated by a vast array of SMT LEDs, Zero ohm jumpers and some capacitors for the linear voltage regulators. Strangely, at least so far, there are no mistakes in the PCB design!

    The overall design is based on a master and slaves system with the master being and Arduino Due and most of the slaves Arduino Nanos, all communicating through the I2C protocol. The Ublox GPS Rover module (lower right) spits out NMEA satellite data every second to be captured through the serial1 port on a "Pro Micro" (not shown). The data can then be processed into headings and distances and accessed whenever the Master requires it by polling the slave via I2C.

    Some of the components on the board are 3v and others 5v so care has been taken to make sure the I2C bus from the Due to the Nanos goes through a level shifter, which is bolted onto the back of the PCB. The Ublox is 3v and outputs serial directly to the 3v Pro micro, which in turn connects directly to the 3v Due via the I2C bus.

    My I2C code has been vastly improved by turning all the data into characters, which are much easier to manipulate on the 8 bit system than trying to manipulate integers and floats directly. Here's a snippet of the Master code:

    void loop(void) 
      Wire1.beginTransmission(26); // transmit to device #26
      Wire1.write("Important number: ");        // sends 21 bytes
      Wire1.write(url);              // sends one byte  
      Wire1.endTransmission();    // stop transmitting
    void characterCompile()
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////        BME280Temperature
    // This is where the data is compiled into a character ....
      dataString =  initiator + x ;
      int n = dataString.length();
    //  Serial.print("Data string to send:     ");Serial.println(dataString);   
    //  Serial.print("Size of string:  ");Serial.println(n);
      // Builds the url character:
          for (int aa=0;aa<=n;aa++)                                              
              url[aa] = dataString[aa];
      Serial.print("Character data to send:  ");Serial.println(url);

    And here's the Slave code:

    #include <Wire.h>
    long result=0;
    char c[100];
    String y;
    String w;
    String a;
    String b;
    String triggerWord = "Important";
    void setup() {
      Wire.begin(26);                 // join i2c bus with address #8
      Wire.onReceive(receiveEvent);   // register event
      Serial.begin(115200);           // start serial for output
    void loop() 
    // function that executes whenever data is received from master
    // this function is registered as an event, see setup()
    void receiveEvent(int howMany) 
      int i=0;
      while ( Wire.available())
        char c =;     // receive byte as a character
        if (isAlpha(c))           // analyse c for letters
          if (a==triggerWord)
            Serial.print("Trigger word detected!: ");Serial.println(b);
        if (isDigit(c))       // analyse c for numerical digit
          y=y+c;            // string = string + character
        w=y;                  // string w = string y
        if (b==triggerWord)
          Serial.print("Resultant integer: ");Serial.println(result);
        if (b!=triggerWord)
          Serial.println("Nothing detected");

     There's still quite a lot of work to do, for example setting up the GPRS link to a database on the interweb, but nothing too tricky. The only aspect of the project that I have not previous experience is the object recognition ....... That's a challenge to look forward to!

View all 40 project logs

View all instructions

Enjoy this project?



linus wrote 01/08/2018 at 18:41 point

interesting project! I have similar ideas but a bit simpler mechanically, what is your reason for building the wheel/suspension arrangement in such complex manner? does the whole vehicle really need to shift hight? and why do you need the 3rd axis on the cnc-part when you have wheels? my idea is to build something lighter with 2 electric bicycle wheels for most load and 2 smaller swiveling wheels as support.

  Are you sure? yes | no

mark wrote 09/15/2017 at 18:56 point

Hi TegwynTwmffat.  The cost of your project could be justified if you have hectares of leeks.  

An alternative to fire is soil injected steam.  Safer for some fire prone environments.  The downside is the weight of the water.

  Are you sure? yes | no

Galane wrote 08/28/2017 at 06:31 point

You're re-inventing the Sizz-Weeder. That goes back at least to the late 1940's. It mounted to the back of a tractor and used thin flame jets to burn *really close* to the crop plants. For more mature plants and tougher crops like corn, the flames could be run across the crop plants to get the small weeds between them in the row - when the tractor was run fast enough so the flame would barely warm the larger plants.

The Sizz-Weeder seems to have fallen out of use with the rise of chemical herbicides.

  Are you sure? yes | no

K.C. Lee wrote 05/04/2017 at 16:25 point

"I say we take off and nuke the entire site from orbit. It's the only way to be sure."  :)

  Are you sure? yes | no

TegwynTwmffat☠ wrote 05/04/2017 at 16:35 point

Yeah ..... We should colonise Mars ....... But you can bet that some weeds will find a way to stow-away onto the space rocket :(

  Are you sure? yes | no

Emach00 wrote 05/04/2017 at 16:15 point

After watching your video, never before have I become so emotionally invested in the success of another man's leek patch. :)

  Are you sure? yes | no

TegwynTwmffat☠ wrote 05/04/2017 at 16:23 point

He he ....... Yes it's quite a dramatic video. The music is from Terminator Salvation by Danny Elfman.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates