Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Micromite vs a ESP32 for a project.
Author | Message | ||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Hi guys. Long post sorry. Been working on a rover project for a while, the long term goal is a lawn mower. The rolling chassis is built, its about the size of a small ride on lawn mower. Apart from the brains, its using a compass module using a I2C interface for direction finding, a home brew motor controller that can be programmed to take whatever format of data I want to use, a RTK GPS module paired with a base station, a RC receiver, and a telemetry link back to a PC. My earlier "brains" was a ESP32 with some software I had written. It worked, but had issues keeping a straight line, more of a banana shaped curve, though always ended up at each waypoint within a few cm. Next step was to write a PC interface so I could monitor the rover, send it new waypoints, etc. Then I took a different path, fell for the spin, bought a flight computer and installed Ardurover, which is coupled with Mission Planner software on the PC. This took about 3 months to get working properly, but still has issues like overshooting the waypoint, is overly complicated, poorly documented and has one hell of a learning curve. I realised this was probably the wrong way to go, I should have stuck with the ESP32 and improved my code. I did think of a solution for the banana lines. I still need to write the PC interface. So back to plan A. For the PC software I fired up JUSTBasic, its got some good graphics functions which I need ( Aerial photo, rover positioned on the map, waypoints displayed and moved with the mouse, etc ). I've got the software to a point where it receives serial telemetry data from a ESP01 ( test chip ), and displays things like the GPS position, direction, battery voltage, etc, etc. I can also send commands back to the chip to do things like stop, go home, new waypoint file, etc. I'm still using the ESP32 as the brains of the rover. Maybe it shouldn't be. I hate the arduino code and IDE. Its fickle. Yesterday I suddenly found it wouldn't compile my code anymore, even old previously working code. Seams all of a sudden I need to put all the functions at the top of the program instead of the bottom or it complains about undeclared variable. I declare all my variables at the top, function at the bottom. For some reason it now compiles bottom to top, and raises a error. "You compiled this just fine a few months ago!" So, what I'm asking is, should I be using a Micromite? The code isnt that busy. Read GPS data every second, parse the data and get the Lat,Long. Read the compas. Do some maths, adjust the motor speeds. Send the telemetry. Any requests coming back? The existing ESP32 code is below. The only real issue is can I interface with the HMC5883 compass module. Probably. What are peoples thoughts on this. Notes on code. I removed the sample GSP data as it points to my house. This code works, it had 4 waypoints and would just drive around a big square in my yard. #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_HMC5883_U.h> float DeclinationAngle=0.17; // Radians. http://www.magnetic-declination.com/ Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345); int DriveMode=0; // 0=Stationary // 1=Turn to face waypoint // 2=Travel to waypoint int StartPos=0; int EndPos=0; int Steer=0; // -10 to 10, left to right float GotFix=0; int BiasLeft=0; int BiasRight=0; double OriginLat=0; double OriginLng=0; double DestLat=0; double DestLng=0; double DestinationAngle=0; String GPSString=""; String GPSSentence=""; String GPSTime=""; double GPSLat=0; double GPSLng=0; float Distance=0; // Distance to next waypoint int WayPoint=0; int WayPointTotal=4; double WayPointLat[100]; double WayPointLng[100]; String NS=""; String EW=""; int GPSFix=0; float TargetBearing=0; // Direction from old to new waypoint int WheelLVal=0; int WheelRVal=0; int WheelRTarget=0; int WheelLTarget=0; int SpeedFactor=0; int Craw=2; int Walk=4; int Run=6; int D=0; int Button1Pin=A6; // Switch int Button2Pin=A0; // Left up down int Button3Pin=A3; // Right up down int ButtonMode=0; // 0=off. 1=Auto. 2=Manual int Button1=0; // Switch int Button2=0; // Left up down int Button3=0; // Right up down #define RX1 26 // GPS Data in from GPS module SimpleRTK2B. #define TX1 25 // Free, Motor controller? #define RX2 32 // Telemetry In #define TX2 33 // Telemetry Out int Drive(int WheelLeft, int WheelRight){ // Right wheel is 64 // Left wheel is 192 // increased number is forward // This was for the original Sabretooth controler, which blew up. int Motor=0; if(WheelLeft>10){WheelLeft=10;} if(WheelRight>10){WheelRight=10;} if(WheelLeft<-10){WheelLeft=-10;} if(WheelRight<-10){WheelRight=-10;} while(WheelLVal!=WheelLeft || WheelRVal!=WheelRight){ if(WheelLVal<WheelLeft){WheelLVal=WheelLVal+1;} if(WheelLVal>WheelLeft){WheelLVal=WheelLVal-1;} if(WheelRVal<WheelRight){WheelRVal=WheelRVal+1;} if(WheelRVal>WheelRight){WheelRVal=WheelRVal-1;} Motor=(WheelRVal*SpeedFactor)+64; Serial1.write(Motor); Motor=(WheelLVal*SpeedFactor)+192; Serial1.write(Motor); delay(50); // Ramping } if(WheelLeft==0 && WheelRight==0){ // All stop Serial1.write(0); } WheelLVal=WheelLeft; WheelRVal=WheelRight; //delay(100); return 0; } int Rotate(int NewBearing){ Drive(0,0); int Bearing=ReadCompas(); Serial2.println("[<TXT>Turning from " + String(Bearing) + " to " + String(NewBearing) + "</TXT>]"); if((Bearing+360)>(NewBearing+360)){ Drive(-10,10); while((Bearing+360)>(NewBearing+360)){ Bearing=ReadCompas(); delay(20); } }else{ Drive(10,-10); while((Bearing+360)<(NewBearing+360)){ Bearing=ReadCompas(); delay(20); } } Drive(0,0); Serial2.println("[<TXT>Turning completed</TXT>]"); return 0; } int ReadCompas(){ sensors_event_t event; mag.getEvent(&event); // Added the +13 and +18 to calibrate the sensor double newheading = atan2(event.magnetic.y+13, event.magnetic.x+18); newheading+=DeclinationAngle; if(newheading < 0){ newheading += 2*PI; } if(newheading > 2*PI){ newheading -= 2*PI; } int B=int(newheading * 180/M_PI); Serial2.println("[<COM>" + String(B) + "</COM>]"); return B; } int GetNewHeading(double La1, double Lo1, double La2, double Lo2){ int X= 360 - ( atan2((La2-La1), (Lo2-Lo1)) * 180 / 3.14159265 ) + 90; if(X>=360){X=X-360;} return X; } float GetDistance(double La1, double Lo1, double La2, double Lo2){ double R = 6378.137; // Radius of earth in KM double dLat = La2 * 3.14159265 / 180 - La1 * 3.14159265 / 180; double dLon = Lo2 * 3.14159265 / 180 - Lo1 * 3.14159265 / 180; double a = sin(dLat/2) * sin(dLat/2) + cos(La1 * 3.14159265 / 180) * cos(La2 * 3.14159265 / 180) * sin(dLon/2) * sin(dLon/2); double c = 2 * atan2(sqrt(a), sqrt(1-a)); double d = R * c * 1000; return d; // meters } void GetLocation(){ while (Serial1.available() > 0){ GPSString+=char(Serial1.read()); } if(GPSString.indexOf("GNGSA")>0){ StartPos=GPSString.indexOf("GGA")+4; EndPos=GPSString.indexOf("GSA")-4; if(EndPos>StartPos){ GPSSentence=GPSString.substring(StartPos,EndPos); GPSTime=GPSSentence.substring(0,GPSSentence.indexOf(",")); GPSSentence=GPSSentence.substring(GPSSentence.indexOf(",")+1,GPSSentence.length()); GPSLat=GPSSentence.substring(0,GPSSentence.indexOf(",")).toDouble(); GPSSentence=GPSSentence.substring(GPSSentence.indexOf(",")+1,GPSSentence.length()); NS=GPSSentence.substring(0,GPSSentence.indexOf(",")); GPSSentence=GPSSentence.substring(GPSSentence.indexOf(",")+1,GPSSentence.length()); GPSLng=GPSSentence.substring(0,GPSSentence.indexOf(",")).toDouble(); GPSSentence=GPSSentence.substring(GPSSentence.indexOf(",")+1,GPSSentence.length()); EW=GPSSentence.substring(0,GPSSentence.indexOf(",")); GPSSentence=GPSSentence.substring(GPSSentence.indexOf(",")+1,GPSSentence.length()); GPSFix=GPSSentence.substring(0,GPSSentence.indexOf(",")).toInt(); double Temp1=floor(GPSLat/100); //Degrees double Temp2=GPSLat-(Temp1*100); //Minutes GPSLat=Temp1 + (Temp2/60); Temp1=floor(GPSLng/100); //Degrees Temp2=GPSLng-(Temp1*100); //Minutes GPSLng=Temp1 + (Temp2/60); } GPSString=""; if(NS=="S"){GPSLat=0-GPSLat;} if(EW=="W"){GPSLng=0-GPSLng;} } return; } void setup() { WayPoint=1; WayPointLat[0]=0; WayPointLng[0]=0; WayPointLat[1]=; WayPointLng[1]=; WayPointLat[2]=; WayPointLng[2]=; WayPointLat[3]=; WayPointLng[3]=; WayPointLat[4]=; WayPointLng[4]=; DestLat=WayPointLat[1]; DestLng=WayPointLng[1]; Serial1.begin(115200, SERIAL_8N1, RX1, TX1); // Setup serial for telemetry Serial2.begin(56700, SERIAL_8N1, RX2, TX2); // Get the starting position. // Make sure we are in the right country at least while the GSP settles down while(GPSLat>-20 && GPSLat<-30 && GPSLng<100 && GPSLng>200 ){ GetLocation(); } WayPointLat[0]=GPSLat; WayPointLng[0]=GPSLng; OriginLat=GPSLat; OriginLng=GPSLng; } void loop() { ButtonMode=1; if(ButtonMode==1){ GetLocation(); int Bearing=ReadCompas(); delay(100); // Hack for testing if(GPSFix==4 && GPSLat<-20 && GPSLat>-30 && GPSLng>100 && GPSLng<200 ){GPSFix=5;} if(GPSFix!=5){ DriveMode=0; } if(GPSFix==5 && DriveMode==0 ){ DriveMode=1;} if(DriveMode==0){ Serial2.print("[<DM>" + String(DriveMode) + "</DM>]"); //Drive mode Drive(0,0); } if(DriveMode==1){ // Turn to face next waypoint Serial2.print("[<DM>" + String(DriveMode) + "</DM>]"); //Drive mode SpeedFactor=Craw; // Slow for turning TargetBearing=GetNewHeading(GPSLat, GPSLng, DestLat, DestLng); if((Bearing+360-5)>(TargetBearing+360) || (Bearing+360+5)<(TargetBearing+360)){ Rotate(TargetBearing); } WheelLVal=0; WheelRVal=0; DriveMode=2; } if(DriveMode==2){ Serial2.print("[<DM>" + String(DriveMode) + "</DM>]"); //Drive mode Distance=GetDistance(GPSLat,GPSLng,DestLat,DestLng); if(Distance>0.5){ if(Distance<3){ // We are getting close. Use a compass to closer Bearing=ReadCompas(); TargetBearing=GetNewHeading(GPSLat, GPSLng, DestLat, DestLng); WheelLTarget=WheelLVal; WheelRTarget=WheelRVal; if(Distance<=1){ SpeedFactor=Craw;} if(Distance>1){SpeedFactor=Walk;} if(Distance>2){SpeedFactor=Run;} if(Bearing+360>TargetBearing+360+10 || Bearing+360<TargetBearing+360-10){ // More that 10 degrees off, stop and rotate. Drive(0,0); SpeedFactor=Craw; Rotate(TargetBearing); Drive(10,10); } if(Bearing+360>TargetBearing+360+5){ // Turn left a bit if(WheelLVal<8 && WheelRVal<15){WheelRTarget=WheelRVal+1;} if(WheelLVal>=8){WheelLTarget=WheelLVal-1;} Drive(WheelLTarget,WheelRTarget); } if(Bearing+360<TargetBearing+360-5){ // Turn right a bit if(WheelRVal<8 && WheelLVal<15){WheelLTarget=WheelLVal+1;} if(WheelRVal>=8){WheelRTarget=WheelRVal-1;} Drive(WheelLTarget,WheelRTarget); } if(Bearing+360>TargetBearing+360-5 && Bearing+360<TargetBearing+360+5){ // Going straight Drive(10,10); } }else{ // Add code to see how far we are off the line } }else{ OriginLat=WayPointLat[WayPoint]; OriginLng=WayPointLng[WayPoint]; WayPoint++; // Increment Waypoint Counter Serial2.print("[<WP>" + String(WayPoint) + "</WP>]"); // Waypoint number if(WayPoint>WayPointTotal){WayPoint=1;} DestLat=WayPointLat[WayPoint]; DestLng=WayPointLng[WayPoint]; DriveMode=1; //Aim to new waypoint if(DestLng==OriginLng){ // Avod a divide by zero error OriginLng=OriginLng+0.0000001} }else{ DestinationAngle=(DestLat-OriginLat)/(DestLng-OriginLng); DestinationAngle=atan(1/DestinationAngle)*(180/3.1426); } DestLat=WayPointLat[WayPoint]; DestLng=WayPointLng[WayPoint]; } } } // End ButtonMode 1 } Glenn Edited 2024-04-28 14:53 by Gizmo The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Adding, I have a spare Pi Pico doing nothing. Loaded up the PicoMite software, dead easy. Unless someone suggests otherwise, I'll give it a go and see if I can use it on the rover. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
morgs67 Regular Member Joined: 10/07/2019 Location: AustraliaPosts: 75 |
the picomite is the current flavour of the month. It is currently very well supported and has many more tricks up its' sleeve. Tony |
||||
phil99 Guru Joined: 11/02/2018 Location: AustraliaPosts: 2135 |
Agree. GPS parsing is all done for you. Edited 2024-04-28 18:08 by phil99 Footnote added 2024-04-28 21:48 by phil99 Perhaps interpolating intermediate waypoints may help keep it on the straight and narrow. The Pico uses decimal degrees rather than minutes and seconds making calculation easier. There are a variety of MATH commands / functions that may help too. The original definition of the metre was 1/10,000,000 of the distance from the pole to the equator. That is also 90 deg. so 1 deg. = 111,111,111 m If the latitudes of the points are 11.1 m apart they are 0.0001 deg. apart. For longitude it is the same at the equator but gets less as you move north or south so a bit of trig. will give the value where you are. |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 4226 |
Hi Gizmo, I have been using GPS in geocaching (and in car navigation), but notice that GPS pure from satellites is 1 meter accurate at best. If you have additional information (like a ground station), only then you become more accurate. I assume you are working with a ground station ? I personally have no idea how the math works when using a ground station, but you must definitely communicate between the 2. Is that why you use a ESP32 (both on the ground station and the rover? Without ground station the position tolerances will be large. Even farmers, with large machines, use a ground station. And they have 10meter wide mowers. I think that is why most automic lawn mowers do not use GPS. Depending the cost price they run a more or less intelligent random algorithm inside a fenced system (ground wire). For fast rover alignment you will need accelerometers, and maybe even a compass. Regards, Volhout Edited 2024-04-28 20:06 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
I'm using a pair of ZED-F9P modules ( about $400 each! ), one as the fixed base station, the other on the rover. The base station sends corrections via a pair of HC-12 modules. The rovers ZED-F9P module does all the maths, and sends the GPS data out another serial port. I see the GPS commands in the PicoMite manual, but the Fix option may not work for me, as the GPS module has several Fix values with different meaning, eg GPS Float, RTK float, RTK Fix. I wait for the Fix to equal 5 before I let the rover move. Thats sub 5cm accuracy. On a clear day the modules can achieve that accuracy fairly easily. The code I have to parse the GPS data into Lat, Long and Fix works fine I use a compass module, it uses I2C, and I'll need to do some research into decoding the data. I found the compass to be fairy accurate, within a few degrees. Its mounted on a PVC mast well away from the motors. If I wanted even better compas readings I can add a third ZED-F9P module to the rover about 1 meter apart from the other one, but they are expensive so I think the compass module will do. Yeah seen the dumb mowers that need a fence wire. No challenge in building one of those . I have a few acres I want this thing to mow and want nice straight lines. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
phil99 Guru Joined: 11/02/2018 Location: AustraliaPosts: 2135 |
Some thoughts on this. The magnetic deviation in much of SE Aus. is 10° to 12° so perhaps the compas starts it out in the wrong direction and the GPS progressively corrects it. It may be worth returning to the ESP32 and experimenting with adding or subtracting 10° to see if that "de-Queensland's" the banana. If it changes the curve at all experiment with different values. Another possibility, if that doesn't get it straight enough is to make use of the high precision of your GPS. Subdivide each run into many waypoints a metre or two apart. Then the bananas will be too small to notice. The intermediate points can be had by interpolating between the start and finish Lat. and Long. points. |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
In my code I had the line... float DeclinationAngle=0.17; // Radians. http://www.magnetic-declination.com/ This was set for my location and used in the code. As mentioned I have a fix for the banana shaped lines. Either see how far I was to the side of the line, or a better option, divide a long waypoint to waypoint section into lots of little sub waypoints. If its just aiming for the next sub way point, it wont drift far off the ideal line. But the code isnt the problem for me, it was just about choice of ESP32 or a Micromite/Picomite option. I really am tired of the Arduino IDE and all its pedantic tantrums. Started translating the C++ code to basic on the picomite last night, have to say its a pleasure to use compared to the arduino IDE process. Tonight I'll plug in the compass I2C module and see if I can get it working on the picomite. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 4226 |
Glenn, This is really nice stuff. The F9 modules, and the technology behind it. Expensive, however, the F9 module itself is only 100 dollar, so a JLC PCB would bering the cost down. I hope to learn a lot from this thread. Keep us up to date. Ublox also have some nice explanations fo the basics behind it on their website. But you are the real pioneer !!! Volhout PicomiteVGA PETSCII ROBOTS |
||||
zeitfest Guru Joined: 31/07/2019 Location: AustraliaPosts: 482 |
The ESP32 is from Expressif I think, I guess they supply the foundation compiler and so on used under the IDE. It would be interesting to try compiling the .ino (slightly altered of course) for a pi pico (eg earlphilhower) and see what happens. The ESP32 and Pico have a lot more resources than a micromite. Most small systems in development seem to have the same problems of bugs, hype and utter BS, you take your pick. |
||||
stanleyella Guru Joined: 25/06/2022 Location: United KingdomPosts: 2127 |
I bought an ESP32 https://www.aliexpress.com/item/1005005761340152.html but don't do arduino c. if only there was basic |
||||
zeitfest Guru Joined: 31/07/2019 Location: AustraliaPosts: 482 |
Google gives quite a few ESP32 Basic interpreters - there is even one in ROM (!) eg (just for interest ) builtin |
||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3150 |
Annex Basic is terrific. PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Thats interesting about the basic interpreter built into the ESP's. OK, got the PicoMite talking to the compass module. That was the only possible hurdle I could see, so its all go ahead for the PicoMite. I'll post my compass test code in a new thread later. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
stanleyella Guru Joined: 25/06/2022 Location: United KingdomPosts: 2127 |
this looks interesting if my board is v2.05 but arduino ide needed it seems. https://www.hackster.io/sl001/a-vga-computer-based-on-esp32-and-fabgl-with-sound-graphics-976894 |
||||
Print this page |