Yuri's Mower Updates

I upgraded the Cube Orange on my zero-turn mower from an early 4.1.0-dev build to 4.1.0-beta1 today, and so far, so good! Kudos to the Dev team for their hard work - lots of great updates and improvements.

I was finally able to ditch the magnetometer completely! With the dev build, I had to leave a single compass enabled or I’d continuously recieve “Bad Compass Health” warnings, regardless of the selected yaw source for EKF3 and successful GPS yaw setup. Now I’m running 100% with GPS yaw, and it’s tracking straighter than ever.

I’m also glad I discovered the deprecation of EK3_MAG_CAL (which I now have set to 2, never). Instead, EK3_SRC1_YAW must be set to 2 or 3 (I’m using 2 with all compasses disabled/unused). Thanks to @ktrussell and @rmackay9 for their discussion on that subject and update of the wiki.

I’ve mentioned this in another thread and some private messages, but I think the following settings are also worty of note:
GPS_DRV_OPTIONS=1 (forces offboard communication between moving base and rover)
GPS_RATE_MS=100 (fastest update rate - a must for GPS yaw)

Once GPS_DRV_OPTIONS is set to 1, you must wire the GPS boards for direct communication with one another. On my ArduSimple simpleRTK2B setup (with MAVLink RTCM3 injection), I have TX2 from one board wired directly to RX2 on the other, and vice versa (the green and white wires in the attached picture). I also have IOREF jumpered to 3v3 to provide a 3.3V reference for serial communication (red wires).

I’ve mentioned before that I always leave GPS_AUTO_CONFIG enabled, else the boot hangs at “EKF3 waiting for GPS configuration.” So far, that is also the case with the beta update. I don’t think the GPS_SAVE_CFG option performs a complete save of the uBlox configuration, thus requiring re-configuration on power-up. I’d like to see if I can perform an offboard uBlox config via uCenter, save it, and then disable the onboard auto config at boot time. It’s a minor annoyance, since the boot sequence isn’t really all that cumbersome one way or the other.

Lastly, the beta build updated the Lua script API, and ahrs:prearm_healthy has been renamed to ahrs:healthy (probably among other things). Thankfully it affected only a single line in a script I run, and it was an easy fix.

I will try and stay a little more involved here, at least during the summer season when mowers seem to be a hot topic. I’ll also provide some more YouTube video updates this summer as I gain more experience with the new settings and continue to test and tune.


Thanks for this and glad that GPS-for-yaw is working out. I’ve added the issue re GPS_SAVE_CFG not really saving all UBlox F9 data to the Rover-4.1 issues list so we can investigate it further.

1 Like

can I get a tlog showing this issue? or a LOG_DISARMED=1 bin log

@rmackay9 @tridge - thanks for adding to the issues list!

I plan to test the following sometime this week (hopefully the weather clears up a bit around here!):

GPS_DRV_OPTIONS=0 - Randy was surprised that I was unable to get RTCM3 injects to successfully pass through the flight controller rather than using the crossover serial connection between moving base and rover. Frankly, I only tested that on the dev build from last year, so I owe it to you to test both methods with the beta build.

GPS_AUTO_CONFIG=0 after a boot cycle using GPS_SAVE_CFG=1.

GPS_AUTO_CONFIG=0 after using uCenter to configure the uBlox modules independently.

I’ll provide logs for each along with a follow up post with anything I discover.

I’d also like to explore the configuration mentioned by @jolivart from ArduSimple where GPS1 is disabled, and GPS2 is the sole GPS source using RELPOSNED messages. I’ll need to get a little creative there in providing RTCM3 to the moving base, since I typically use MAVLink injection, which is impossible with that config.

1 Like

Hello Yuri,
In the setup I introduced, you can also provide RTCM from the fixed base station to the moving base.
You need to:

  1. Connect the simpleRTK2Blite (the small board that acts as a moving base ) JST-GH connector to another free port in your flight controller
  2. Setup your flight controller to forward RTCM corrections to the simpleRTK2Blite.
    Make sure that the baudrate is set at 460’800bps.

Best regards,


I had a chance to do a little mowing this evening and tested all three obstacle avoidance modes (fences only, no proximity sensor enabled).

The Dijkstra algorithm worked without rebooting - I simply set OA_TYPE=2 with fences enabled, and the mower planned paths around fences as expected.

BendyRuler was slightly trickier to enable. Setting OA_TYPE=1 or OA_TYPE=3 without rebooting did not enable the additional parameters, even after a refresh and resulted in the mower holding position when AUTO mode was selected. A simple reboot cleared that up, and I was able to use the BendyRuler algorithm and new BendyRuler+Djikstra feature as well.

The mower tended to give fences a wide berth in all modes, even with the margins set fairly tight. I think with a smaller OA_BR_LOOKAHEAD value, perhaps I can get it to cling a little tighter to the fence boundaries. I also intend to try smaller fence radii with an increased OA_MARGIN_MAX to see if perhaps that will result in tighter avoidance paths. However, I’m not sure it’s smart to set a fence radius smaller than 2m with a machine that’s 1.5m wide.

The new BendyRuler+Dijkstra feature seems very promising and tended to produce the cleanest/shortest path around any given obstacle.

I rarely encountered a fence breach (only upon deceleration with an awkward/impractical series of waypoints intended to challenge the system), which is fantastic, and for most applications, the rather wide berth around obstacles would likely be welcome. For mowing, I prefer to keep the margins small so I can quickly plan a mowing pattern without the need to fine tune individual waypoints around known trees/shrubs/etc and still leave as little as possible for manual trimming later.

I used the following parameters for the Dijkstra algorithm:

For BendyRuler, same settings as above except:

And finally, BendyRuler+Dijkstra:

I should be able to provide the logs requested above this weekend.

1 Like

I did a little testing today, and here’s what I have so far:

While I have no reason to distrust @ktrussell, I verified his findings that the UART2 pins on simpleRTK2B boards are indeed labeled backwards. TX2 is actually RX2 and vice versa. Good catch!

@tridge, I sent you a Google Drive folder link to some .bin logs showing the following scenarios. Feel free to share them with @rmackay9 (I don’t have his email address).

For all of the following test configurations, the mower was between some trees and my garage, so full EKF3 alignment might look a little slow as a result of a less than ideal satellite view. I fully power cycled the flight controller between each test.

I first booted using my usual configuration, set GPS_SAVE_CFG=1, and rebooted to ensure that the flight controller saved the GPS config data to each board. I included a log file with that configuration though it may have a later timestamp than the actual boot/save just prior to disabling GPS_AUTO_CONFIG.

After that, I set GPS_AUTO_CONFIG=0 and rebooted. The boot sequence did not hang like it did in the dev build, and I got valid GPS2_RAW.yaw output after a short period, but I got a continual “Unhealthy GPS Signal” message no matter what I did. The log should reflect that.

I was able to get a valid GPS2_RAW.yaw calculation with GPS_DRV_OPTIONS=0 and the UART2 crossover connection physically removed. However, GPS2 frequently dropped to a simple 3D Fix briefly, and occasionally caused “Unhealthy GPS Signal” messages. I didn’t observe any significant time where GPS2_RAW.yaw reverted to 65535 once an RTK fix was first obtained, but based on my observation so far, I think the flight controller struggles to keep up with the RTCM3 message traffic throughput.

In short, I’m sticking with the successful configuration I described initially, but there’s definite progress with the beta1 build!

1 Like

This evening I tightened up the steering tuning and got really aggressive with the NAVL1 values while playing with BendyRuler.

I’m not sure if the following parameter values are truly optimized or if I have some errors of cancellation masking one another, but the screenshot shows some REALLY good results, including a fairly tight margin around a 1.5m circular exclusion fence around my front yard tree.




Thanks very much for testing this. I’m surprised you found that Dijkstra’s didn’t require a reboot it really should unless it was already enabled - I’ll have a peek.

I’ll leave @tridge to discuss the GPS-for-yaw and GPS_SAVE_CFG questions.

Setting tighter OA_BR_LOOKAHEAD will definitely help with reducing how far away the Rover diverts! I would suggest experimenting with that.
Some suggestions though: For fences, Dijkstra’s is probably the best because it plots a definite shortest path around the fence towards your destination. Dijkstra’s does not work with physical obstacles (only fences). BendyRuler will work too, but it won’t promise you the “best” path. BendyRuler is best kept for proximity avoidance (from lidar/rangefinder etc).
So BendyRuler+Djikstra feature will smartly do all this for you without giving you any headaches, however if you do not have any proximity sesnors present, then this mode is simply equal to using Dijkstra’s only and won’t give you any better results.

1 Like

So far, BendyRuler works best for my use case, as shown in the graphic. Between my first post regarding avoidance and the screenshot, I tightened the lookahead value down from 5 to 3, and the fence was shrunk from 2m to 1.5m, which makes for a pretty acceptable mowing margin, as shown.

However, I need to revisit Dijkstra’s algorithm with the aggressive NAVL1 parameters. I’ll mow the exact same path depicted above, changing only the OA_TYPE, and post screenshots of that later today. My front lawn is extremely well groomed at this point after testing the same path repeatedly!

EDIT: Here’s the Dijkstra screenshot. It leaves a long unmowed strip ahead of the tree. I think using a short lookahead value with BendyRuler is the way to go in this scenario.


To Ardusimple’s credit, they do disclose that TX2 and RX2 are connected to UART2 RX and UART2 TX respectively in more than one place in their documentation. For example under “Arduino Rails” at simpleRTK2B hookup guide - ArduSimple, it states:

  • TX2: XBee UART TX (this pin is also connected to ZED-F9P UART2 RX).
  • RX2: XBee UART RX (this pin is also connected to ZED-F9P UART2 TX).

The bold accent is mine. They don’t make a big point of it, so it is a gotcha!

I am very happy to see this testing of the avoidance features. I have a very strong need for this to work around 3 power poles in one of my pastures as well as oak trees along my drive. Once I get my mower back rolling well, I will be trying this out. Thanks for paving the way.

And Yuri, your pivot turns are awesome and in general, the tracking is excellent.

For what it is worth…
Thursday evening, I captured on video the setup process I have used to get GPS for Yaw working with all RTCM3 connections external to the flight controller on the F9P UART2. I have just uploaded it to YouTube at https://youtu.be/A1QbHG6SBUk.

I’m sure you development guys chuckle as I try to somewhat reverse engineer what the software is doing. I should just look at the code!

1 Like

@ktrussell makes perfect sense regarding the simpleRTK2B boards - the labels are oriented to the intended XBee pins rather than the F9Ps. Definitely a gotcha for those using any external source for RTCM3 on UART2.

Much appreciate the compliment on the turns/tracking! I actually tweaked the servo tracking a little today using your tape-on-the-wheel method. I increased the pivot turn rate (now 41°/s) and played just a bit more with the ATC_STR parameters and NAVL1 tuning. Other than slightly faster pivots, I ended up very close to the parameters in my earlier post here - I don’t know that I can do much better at this point.

I mowed two more patterns this afternoon with geofenced trees. Once I had the fences placed correctly, the mower did a great job avoiding them. In fact, the only time I even bumped one was during the Dijkstra test above, where the mower got a little TOO efficient with the shortest path planning and nudged the deck against the tree on the closest point of approach. Every time I use BendyRuler, I get very predictable/desirable results.

I’ll take a look at your video for sure - there’s plenty to learn! You’re not the only one who thinks the dev team gets a laugh - I feel pretty ignorant at times, particularly when tuning parameters I barely grasp!

I posted my own short video update today as well (https://www.youtube.com/watch?v=2mk8fhbTN3Y). I didn’t go into much detail - just a short preview of things to come. I might just have enough time tomorrow to knock out a more detailed video of either the Lua stuff or fence exclusion.


Awesome results! Those pivot turns are spot on. Do you have the locations of your GPSes referenced to the point about which your mower pivots in a pivot turn or to some other origin?

The antennas are on the uprights for the roll bar, which is very close to the pivot axis, so the only GPS offsets are on the Y axis, left and right of center.

In my last video linked above, there’s a great profile shot at 1:33 where you can see how close the antennas are to the rear wheel centerline.

1 Like

There’s an AVOID_OPTIONS parameters that could help:

0:Vehicle will return to its original waypoint trajectory
1:Reset the origin of the waypoint to the present location

So it might help to change this parameter to 0…

@rmackay9, OA_OPTIONS=0 was set that way for both screenshots posted. Along with a very short NAVL1_PERIOD, the BendyRuler algorithm corrects back to the line pretty aggressively, as I want it to.

Dijkstra’s stays much closer to the fence at the closest point of approach, but it begins to diverge much earlier (I think as soon as it detects that the intended path intersects a fence), leaving an unmowed strip ahead of the tree.

1 Like


Ah, I see what you’re saying. Yes, Dijkstra’s creates a path that is the shortest path around the fence. It’s not designed to make the shortest diversion which is probably what you want. This is an interesting difference that I’ve never considered…

1 Like