Rover Mowing Success

To All,

Just dropping everyone a line to say thank you for all the help you have given me over the last two years. In particular I would like to thank @Yuri_Rage who always seemed to pick up my questions and offer superb helpful advice.
I can now mow my paddocks with superb repeatability!
Please see short video below.

Cheers,

Martin

9 Likes

Wow, looks like you’ve got it beautifully tuned!
Do you have a build thread somewhere with details?

Thanks @rhauff, it has taken a long time to get this far and to be honest I could not have done it without the help of the members here.
I don’t have a build log as such, but happy to share photos of the story. Not sure where I would post them.
Cheers,
Martin

Looks great! It’s always exciting to see autonomous systems in action.

1 Like

Very cool!

Was there a build thread for this?

What vehicle is that???

Very nice!! Love the puller! Need more pics please.

Joshua, Hi,

It is my own design from fabricated HDPE 12mm sheet.
Here are some pictures of the design and build.













6 Likes

Wow! Very nicely done!

Nice! Thanks for the detail pics-

You can tell you work with plastics as a day job!

How do you like the ampflow motors (what size)? Are those planetary reductions (ratio)?

its very tidy, it looks like a retail product.

@binfordw I have been building water, waste and fuel tanks for the marine industry for 30 years so have a good understanding of what you can do with PE.
The Ampflow motors have been excellent other than two snapped shafts on the gearboxes. These have both been on the rear right when towing from the rear tow ball. The stepped shoulder has been machined with no radius hence it fractures with a lot of weight on it. I will be changing/trying their larger diameter shaft motors with chain driven reduction on the next version. The gearbox is the 1:32 version with the part number E30-400-24-PR32.

2 Likes

@rhauff I used the Quick Tune lua script and have not had to change anything since doing that. It seemed to work perfectly.

2 Likes

Glad the script worked for you. Sometimes with slower vehicles or those with non-linear throttle/steering response, it’s a little touch and go. The fact that the script produced such good results is another testament to your build quality, in my opinion. Nice work!

1 Like

Very nice. Seems you might be running into an interesting side effect I’ve discovered with highly accurate mowing patterns; the mower eventually starts forming trenches from repeated mowing.
It would be nice to be able to quickly offset the pattern by perhaps a random amount.

Missions are fairly human readable text files that are easily manipulated. A simple Python script or even Excel sheet could do the offset for you.

If you are not comfortable manipulating the waypoint text file you can also offset the outside polygon and refill the waypoint pattern inside the polygon and then just add a lane on which ever side is not covered.

1 Like

The real slick solution would be to come up with software that could manipulate the whole grid at any angle you wanted contained within your perimeter polygon. My guess is that someone has already done it, because mathematically it isn’t that difficult and there are a lot of smart people out there.

Here is another easy way to move waypoints that I learned from @ktrussell at MowStock. I never knew that you can just select a group of waypoints and drag them around.

@marblecreek @jason_miller @Swebre2023

2 Likes

I do see MP has the ability to drag points around but it’s not real exact.
I threw together a “Nudge” plugin to allow for more precise movements. It’s a work in progress. Right click in the planner and there should be a new “Nudge” menu item.

Here’s the source, put it in your plugins folder and give it a try. Let me know if it is useful or how it can be improved. Next up is a reversing pattern plugin.

I tried uploading the .cs file but it’s not allowed. Here it is in the raw:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MissionPlanner.Utilities;
using MissionPlanner.Controls;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;
using MissionPlanner;
using System.Drawing;
// Mission Planner Nudge plugin. Work in progress.
// adds a Nudge right click option in the planner.
// Use at your own risk. 
namespace Shortcuts
{
    public class Plugin : MissionPlanner.Plugin.Plugin
    {
        ToolStripMenuItem but;
        MissionPlanner.Controls.MyDataGridView commands;
        public override string Name
        {
            get { return "Waypoint Nudge Plugin"; }
        }

        public override string Version
        {
            get { return "0.10"; }
        }

        public override string Author
        {
            get { return "John Harlow"; }
        }

        public override bool Init()
        {
            return true;
        }

        public override bool Loaded()
        {
            but = new ToolStripMenuItem("Nudge");
            but.Click += but_Click;
            ToolStripItemCollection col = Host.FPMenuMap.Items;
            col.Insert(0, but);
            commands = Host.MainForm.FlightPlanner.Controls.Find("Commands", true).FirstOrDefault() as MissionPlanner.Controls.MyDataGridView;
            return true;
        }

        public override bool Loop()
        {
            return true;
        }

        public override bool Exit()
        {
            return true;
        }

        void but_Click(object sender, EventArgs e)
        {
            Form form;
            form = new Form();
            form.AutoScaleMode = AutoScaleMode.Font;
            SizeF dialogUnits;
            dialogUnits = form.AutoScaleDimensions;
            form.FormBorderStyle = FormBorderStyle.FixedDialog;
            form.MinimizeBox = false;
            form.MaximizeBox = false;
            form.Text = "Enter nudge offset (Meters)";
            form.ClientSize = new Size(200, 100);
            form.StartPosition = FormStartPosition.CenterScreen;
            System.Windows.Forms.Label lblPromptX;
            lblPromptX = new System.Windows.Forms.Label();
            lblPromptX.Parent = form;
            lblPromptX.AutoSize = true;
            lblPromptX.Left = 50;
            lblPromptX.Top = 20;
            lblPromptX.Text = "Nudge X";
            System.Windows.Forms.Label lblPromptY;
            lblPromptY = new System.Windows.Forms.Label();
            lblPromptY.Parent = form;
            lblPromptY.AutoSize = true;
            lblPromptY.Left = 50;
            lblPromptY.Top = 40;
            lblPromptY.Text = "Nudge Y";

            System.Windows.Forms.TextBox edInput;
            edInput = new System.Windows.Forms.TextBox();
            edInput.Parent = form;
            edInput.Left = lblPromptX.Left + 50;
            edInput.Top = lblPromptX.Top;
            edInput.Width = 30;
            edInput.Text = "0.0";
            edInput.SelectAll();

            System.Windows.Forms.TextBox edInput2;
            edInput2 = new System.Windows.Forms.TextBox();
            edInput2.Parent = form;
            edInput2.Left = lblPromptY.Left + 50;
            edInput2.Top = lblPromptY.Top;
            edInput2.Width = 30;
            edInput2.Text = "0.0";
            edInput2.SelectAll();
            int buttonTop = 60;
            Size buttonSize = new Size(50 * (int)dialogUnits.Width / 6, 14 * (int)dialogUnits.Height / 6);
            System.Windows.Forms.Button bbOk = new System.Windows.Forms.Button();
            bbOk.Parent = form;
            bbOk.Text = "OK";
            bbOk.DialogResult = DialogResult.OK;
            form.AcceptButton = bbOk;
            bbOk.Location = new Point(40, buttonTop);
            bbOk.Size = buttonSize;
            System.Windows.Forms.Button bbCancel = new System.Windows.Forms.Button();
            bbCancel.Parent = form;
            bbCancel.Text = "Cancel";
            bbCancel.DialogResult = DialogResult.Cancel;
            form.CancelButton = bbCancel;
            bbCancel.Location = new Point(120, buttonTop);
            bbCancel.Size = buttonSize;

            if (form.ShowDialog() == DialogResult.OK)
            {
                double lat_trans = Double.Parse(edInput2.Text);
                double lon_trans = Double.Parse(edInput.Text);
                double earth_radius = 6378.137;
                double m_lat = (1 / ((2 * Math.PI / 360) * earth_radius)) / 1000;
                double m_long = (1 / ((2 * Math.PI / 360) * earth_radius)) / 1000; // # 1 meter in degree
                // iterate through the waypoints
                foreach (DataGridViewRow row in commands.Rows)
                {
                    if (row.Cells[0].Value.ToString() == MAVLink.MAV_CMD.WAYPOINT.ToString())
                    {
                        double lat = Double.Parse(row.Cells[5].Value.ToString());
                        double lon = Double.Parse(row.Cells[6].Value.ToString());
                        // Calculate top, which is lat_translation_meters above
                        double lat_new = lat + (lat_trans * m_lat);
                        // Calculate right, which is long_translation_meters right
                        double lon_new = lon + (lon_trans * m_long) / Math.Cos(lat * (Math.PI / 180));
                        row.Cells[5].Value = lat_new.ToString();
                        row.Cells[6].Value = lon_new.ToString();
                    }
                }
                // redraw the map
                Host.MainForm.FlightPlanner.writeKML();
            }
        }
    }
}
1 Like