AutoKart

Evening all

For some years now I have been trying to get into robotics as I have always wanted to build an autobot. Was recently shown some automated lawn mowers which are contained inside a wired perimeter and wander around constantly and haphazardly. Couldn't help but think that a digital system could do the job much more cheaply (a decent sized auto mower can cost in excess of £10,000), more efficiently and more quickly.

From what I've read, the Arduino would be the ideal solution for this.

However, I'm a complete newcomer to robotics and the C family of languages, and when I sat down and drew this out, the project seemed quite daunting:

  1. Get (or build) some kind of small ATV capable of maintaining a reasonable straight line over reasonably rough terrain.
  2. Use an electric motor attached to a PWM to control speed.
  3. Another motor to control steering
  4. GPS system (inaccurate, I know, but this can be improved on)
  5. Google maps integration if poss

Whilst doing some reading on GPS, I've come across AOG (https://agopengps.jimdosite.com/) which seems to offer everything I need in one package. This guys has built a full automation system for tractors and it seems to tick all the boxes:

  1. Has relay controls so that you can turn motors on and off
  2. Motor control via PWM
  3. Simple GPS integration
  4. Full google maps integration so that you can draw a polygon around a field in google maps and import that into his software, thereby defining boundaries
  5. Autosteer

The problem I am having is that the help files and youtube videos, whilst good, all relate to different iterations of the software and I'm getting lost.

Is anyone here able to help?

Project design (right now)

  1. Chassis: a modified electric scooter
  2. Microprocessor: Arduino Uno (got a MEGA 2560 as a backup because I've already blown about £100 of boards experimenting with voltage)
  3. Both a Cytron MD10C motor controller and HN motor controller shield
  4. 12VDC UPS battery (22ah, plenty of juice)
  5. Car windscreen wiper motor (12VDC) to drive the steering

I've attached a basic schematic and the code for the autosteer which I am trying to get working first, but I cannot get the motor to run.

Just trying to bend my head around the code and , looking at this section:

//////////////////// *********** Motor drive connections **************888
//Connect ground only for cytron, Connect Ground and +5v for IBT2

//Dir1 for Cytron Dir, Both L and R enable for IBT2
#define DIR1_RL_ENABLE 4 //PD4

//PWM1 for Cytron PWM, Left PWM for IBT2
#define PWM1_LPWM 3 //PD3

//Not Connected for Cytron, Right PWM for IBT2
#define PWM2_RPWM 9 //D9

//--------------------------- Switch Input Pins ------------------------
#define STEERSW_PIN 6 //PD6
#define WORKSW_PIN 7 //PD7
#define REMOTE_PIN 8 //PB0

Does "PD" refer to Pin (digital?). I have attached PWM on the MC10C to Digital Pin ~3 and DIR to DP4. Can anything verify if this is correct?

Would really appreciate a couple of pointers, I have been banging my head off this for weeks!

Cheers :slight_smile:

AutosteerPCBv2.ino (24.5 KB)

Need to read up how to post your code , the details you have provided are a bit basic.

Oh right, any chance of a bit of guidance?

Should I have copied and pasted the whole sketch into my post?

bluerabbot:
Does "PD" refer to Pin (digital?).

The IO pins on the microcontroller are grouped into ports, each of which is identified with a letter (i.e., port A, port B, port C). Each individual pin of the port is controlled by writing a 1 or 0 to a bit of that port. PD4 is shorthand for bit 4 of port D. The code for working with pins by reading writing at the register level is not very beginner friendly. The required code also may be different from one microcontroller architecture to another, meaning that this style of low level code is not portable. For these reasons, Arduino uses a system of arbitrarily assigning numbers to each pin to identify them in your code.

When you are using the standard IO functions of the Arduino API (e.g., pinMode(), digitalWrite(), digitalRead()), you need to use the Arduino pin numbers. For this reason, it's generally not useful to use the port/bit way of referring to IO pins in the Arduino world.

If you take a look at the pin mapping on the Uno:

You can see that Arduino pin 4 is indeed mapped to PD4. However, if you check the pin mapping for the Mega:

you can see that Arduino pin 4 is mapped to PG5. Generally, we don't care about that. We just need to know that if I have digitalWrite(4, HIGH) in my code, it's going to set the state of the pin marked 4 on the Arduino board to HIGH, regardless of which Arduino board I happen to be using.

Pert, thank you for your time explaining this and answering my question.

Having had a good look at those pin mappings, I can see some differences with the UNO board I have (unless I am being totally daft: mine goes

[digital]
0 TX
1 RX
2
3 ~
4
5~
(etc - pin 13)
14 GND
15 AREF
16 SDA
17 SCL

The opposite bank is a little different too.

So what you are telling me is that I cannot assume that the pinouts in someone else's code will correspond to the board I have, even though it's given the same version name (UNO in this case, bought from a random supplier on eBay). Sounds like the first thing I should do is to modify the code to reflect my own board pinouts, is that about right, or am I way off?

Awkward question and I have the feeling that the answer is going to be awfully complicated and not a simple job of packet sniffing.... Is there an "easy" way of tracing what data is being transmitted from what pin? Can one "sniff" a pin?

Thanks again for your time. :slight_smile:

bluerabbot:
Having had a good look at those pin mappings, I can see some differences with the UNO board I have (unless I am being totally daft: mine goes

There are no differences. The pin mapping diagram is showing which Arduino pin numbers relate to which pins on the ATmega328P microcontroller on your Uno. If you were to follow the little conductive traces on the PCB between the headers on your Uno board and the pins on the ATmega328P on the board, you would find they match perfectly. The diagram has absolutely nothing to do with the order of the pins on the headers of your Uno.

bluerabbot:
So what you are telling me is that I cannot assume that the pinouts in someone else's code will correspond to the board I have, even though it's given the same version name (UNO in this case, bought from a random supplier on eBay). Sounds like the first thing I should do is to modify the code to reflect my own board pinouts, is that about right, or am I way off?

You're completely misunderstanding what I wrote. You asked what the things in the comments like PD4, etc. mean so I told you. But please forget all about it and ignore those comments in the code. This is not anything a beginner needs to know. All you need to know is that if you write something like digitalWrite(4, HIGH) in your code, then the pin on your Uno that has a "4" written next to it on the circuit board is going to go HIGH. You can have confidence of that, no matter which Arduino board you're using.

bluerabbot:
Can one "sniff" a pin?

At a very simple level, like when running the basic Blink sketch, you could connect a digital multimeter or an LED to the pin to see whether it is HIGH or LOW. A cheap digital multimeter is certainly a worthwhile investment. I recommend the ones you get on eBay for <$4 with free shipping from China that usually have "830D" in the model number. Whatever you do, don't get the slightly cheaper ones that usually have "830B" in the model number that look almost the same but don't have a buzzer for the continuity tester function. You can identify the buzzer feature by a symbol that looks something like: *))) above the diode symbol on the selector dial.
https://www.ebay.com/itm/174033620660

In some cases (such as when the pin is being used to transmit data), the pin may be switching from HIGH to LOW, etc. extremely quickly and a multimeter can't react that quickly. An LED would only appear to be more or less bright. In this case, a logic analyzer or an oscilloscope would be needed to measure the pulses on the pin. Those can be useful troubleshooting tools, but are not something a beginner would have any use for. You just need to understand how to write the correct code in your sketch and you can be reasonably sure that that pin on your Arduino board will be doing exactly what the code is telling it to do.

bluerabbot:
Couldn't help but think that a digital system could do the job much more cheaply (a decent sized auto mower can cost in excess of £10,000), more efficiently and more quickly.

This is until you start asking yourself question such as "how does the robot know where it is, in which direction it's pointing, and where it has to go?" and "how do I make sure the thing is safe, so I don't mow my pet tortoise or have the thing damage itself?"

Pert: ok, sorry for totally missing your point, it was late at night when I was trying to digest it.

You’re right, I need to keep this simple at this stage and just ensure the pins are mapped correctly.

WRT testing output, a multimeter makes absolute sense. Appreciate what you’re saying about the limitations and I’ve seen plenty of vids of people applying an oscilloscope to exactly this, but this is beyond me at present. Yes, it makes sense that I should focus on the code.

As fortune has it, I tried my arm and contacted the developer directly, asked for some guidance and he’s responded so I’m hoping he will point out where I’m going wrong.

Thank you again for your time.

wvmarle:

  1. GPS / RTK = 1CM accuracy
  2. Compass
  3. Software (AOG was written for exactly this)
  4. Object detection / avoidance

I’m only stuck on some basic points understanding the electronics and code. I’ve already built the rover and can operate it manually, steering, GPS, etc are all in place. I’m just struggling with the electronics and code required to automate it and someone has already provided the code for this. Just trying to understand why it’s not doing what it should (and already is doing perfectly for a bunch of people),

Why be so negative?

Have a look at AgOpenGPS (AOG) sometime, all of your questions are answered fully. I’m just trying to adapt this man’s work to my own project.

bluerabbot:

  1. GPS / RTK = 1CM accuracy

In the real world we're happy to get 1-2m accuracy (even when you get the numbers at 1 cm precision). Anything better than that requires local beacons.

What’s wrong with local “beacons”? I’ll probably get two Emlid Reach RS+ RTK GNSS units.

Anyway, this isn’t my problem. I’m an IT engineer by trade, been working in the telecoms industry at the ISP level for about twenty years so I do know a thing or two about comms.

I’m just new to arduinos and so I came here to ask a couple of questions about an arduino project.

Nothing wrong with them as such.
Just that you have to install them at a fixed location (and provide power there), and it's much more expensive than just using GPS. Pozyx is one such solution.

Ello, I’m back :slight_smile:

Having immersed myself is little but arduino vids and tutorials over the past couple of weeks, things are starting to make sense.

Got the steering sorted out using the MD10C and I’m now looking at the compass which I have working...

But...

Please can anyone explain how to use multiple tabs / sketches? I’ve tried the intuitive route of creating a new tab and putting the compass sketch into that, but when I try to compile it, it throws ‘redefinition of ‘void setup ()’

I think I can see what’s happening here, but I’m not sure. Am I right in thinking there should only be one ‘void setup’ used for the whole sketch, regardless of the number of tabs? That would make some sense were it not for the fact that I have looked at other sketches with many tabs and they all seem to start void setup () {

Can anyone offer any pointers?

TIA :slight_smile:

Tabs are useful for organizing related blocks of code. For example, you might put a little LCD screen on your robot. The user interface graphics and menu code will usually grow to be about the same size as the rest of your code. So it makes it easier to work on if you put all the display code in one tab.

But the compiler doesn't care. It all gets smashed together before compilation, so you can't have two functions with the same name. Use setupDisplay() for example, and call that from setup().

Ok fantastic, thanks for that.

That’s what I was trying to work out: whether each module / shield needed its own tab and whether these were then executed / called individually, or if it all ran as one script. Makes sense now, I’ll ensure all values are unique too.

MorganS:
Use setupDisplay() for example, and call that from setup().

After being hit by an IDE bug that cost me a long time I now avoid using "setup" and "loop" as part of function names. So for me it's initDisplay().

Hello again

I'm still on this and learning slowly, but steadily.

Gave up on trying to get AOG working, well I think it is doing what it should, but it's not as suitable for my purposes as I had thought, so I have started from scratch and tried to simplify things. It's still pretty much the same project, but in simple terms I am trying to:

  1. Program two motors (drive and steering) according to specific instructions (go forward x metres, then u-turn)
  2. Attach a compass so that it knows which way it is heading.
  3. Attach a GPS so that it knows where it is (optional for now)

I have each of the devices working individually, using a cytron motor controller for the motors, GY-NEO6MV2 GPS, and a GY-271 compass. When I fire up the appropriate sketch for each device (and serial monitor for the latter two) all looks good.

Old question, but how do I combine these sketches?

Just trying to get the motors and compass working together for now, so I have renamed the void loop and setup loop uniquely and the script compiles without error, but when I upload it, only the motors work and there is no output from the compass.

Can anyone see what I am missing?

#include "CytronMotorDriver.h"


// Configure the motor driver.
CytronMD motor(PWM_DIR, 3, 4);  // PWM = Pin 3, DIR = Pin 4.


// The setup routine runs once when you press reset.
void setup() {
  
}


// The loop routine runs over and over again forever.
void loop() {
  motor.setSpeed(32);  // Run forward at 50% speed.
  delay(1000);
  
  motor.setSpeed(16);  // Run forward at full speed.
  delay(1000);

  motor.setSpeed(0);    // Stop.
  delay(1000);

  motor.setSpeed(-32);  // Run backward at 50% speed.
  delay(1000);
  
  motor.setSpeed(-16);  // Run backward at full speed.
  delay(1000);

  motor.setSpeed(0);    // Stop.
  delay(1000);
}

#include <Wire.h> //I2C Arduino Library

#define addr 0x0D //I2C Address for The HMC5883

void setup1() {

  Serial.begin(9600);
  Wire.begin();


  Wire.beginTransmission(addr); //start talking
  Wire.write(0x0B); // Tell the HMC5883 to Continuously Measure
  Wire.write(0x01); // Set the Register
  Wire.endTransmission();
  Wire.beginTransmission(addr); //start talking
  Wire.write(0x09); // Tell the HMC5883 to Continuously Measure
  Wire.write(0x1D); // Set the Register
  Wire.endTransmission();
}

void loop1() {

  int x, y, z; //triple axis data

  //Tell the HMC what regist to begin writing data into


  Wire.beginTransmission(addr);
  Wire.write(0x00); //start with register 3.
  Wire.endTransmission();

  //Read the data.. 2 bytes for each axis.. 6 total bytes
  Wire.requestFrom(addr, 6);
  if (6 <= Wire.available()) {
    x = Wire.read(); //MSB  x
    x |= Wire.read() << 8; //LSB  x
    z = Wire.read(); //MSB  z
    z |= Wire.read() << 8; //LSB z
    y = Wire.read(); //MSB y
    y |= Wire.read() << 8; //LSB y
  }

  // Show Values
  Serial.print("X Value: ");
  Serial.println(x);
  Serial.print("Y Value: ");
  Serial.println(y);
  Serial.print("Z Value: ");
  Serial.println(z);
  Serial.println();

  delay(500);
}

You have to call setup1() from setup().

You also have to call loop1() from loop().

I notice you have a lot of delays. This will make it very difficult to merge these cleanly. Loop() has 6 seconds worth of delays. But loop1() is trying to do something every 0.5 seconds.

Not quite sure how I do that, but I'll run with your information and try to make sense of things. Thanks for the pointer.

The compass will be polling every 0.5 secs.