Jaycar-Electronics / WiFi-Rover

Control a Metal 4WD Car with phone operated WebApp, using the multitouch API
1 stars 6 forks source link

Can this work with XC4411 Uno with WIFI as per system diagram #3

Closed JimmyBarrel closed 4 years ago

JimmyBarrel commented 4 years ago

I purchased all the hardware, not the Mega (I have the XC4411 as per the system diagram). However I get a compile error against the use of Serial3. Is there any code to have this work on the Uno clone?

L-m-b commented 4 years ago

Having the same issues on the original project board, it also has errors with the af_motor library (I am on Linux so it was a pain to get going, but I managed). The ESP8266 rover-server project file went onto the board fine, switched the dips over to Arduino programming mode again and it won't upload as i originally had issues with. Tried switching the dips around to allow Arduino and esp to talk, still no luck with the serial3 error. Supposedly 'serial' itself was meant to communicate between Esp and Arduino based on the documentation.

might be just an issue with IDE compiling it, might be something done wrong on Jaycar's side.

L-m-b commented 4 years ago

It's possible the IDE board that they say to use in the documentation is wrong entirely, but i'm gonna try testing it to compile.

L-m-b commented 4 years ago

HEY, i found that the boards that you add to the arduino ide program don't work at all, but the mega/mega2560 options work, (about 5th from top of default board profile) try compiling to the uno with that, i have yet to test if it works on my board, could be a few others that work. Edit: i did a test compile, not an upload, i will test soon when i can get a micro-usb cable

JimmyBarrel commented 4 years ago

I have found the solution to this problem. The Arduino Mega has three physical serial ports and the Arduino Uno has only one.

To utilise this with the Uno a software serial is needed for communication with the ESP8266. Also, some changes to how the serial event is handled must be implemented.

The following code compiles (and appears to work).

#include <AFMotor.h>
#include <SoftwareSerial.h>

SoftwareSerial esp8266(0, 1); // RX | TX

AF_DCMotor frontLeft(1);
AF_DCMotor rearLeft(2);
AF_DCMotor rearRight(3);
AF_DCMotor frontRight(4);

char serialBuffer[256] = {0};
short idx; // serial index;

// ---------------------------------------------
// Traditional arduino functions
// ---------------------------------------------
void setup()
{
  // put your setup code here, to run once:

  Serial.begin(115200);  // to the computer ( if connected)
  Serial.println("Startup");
  esp8266.begin(115200); // to the ESP8266
  esp8266.println("OK"); // tell ESP to start up

  frontLeft.run(RELEASE);
  frontRight.run(RELEASE);
  rearRight.run(RELEASE);
  rearLeft.run(RELEASE);
}

void loop()
{
  // put your main code here, to run repeatedly:
  delay(100); // we can delay as the serial events cause the movemment
  //Serial.println("Loop");
  if (esp8266.available()) {
    serialEvent();
  }
}

// -------------------------------------------
// This function will be called when there's serial data
// -------------------------------------------
void serialEvent()
{
  //Serial.println("In serial event3");

  while (esp8266.available())
  {

    char data = esp8266.read();
    //Serial.println(data);

    if (data == '\n')
    { //begin processing data

      serialBuffer[idx] = '\0'; //finalise String

      processSerialData();

      idx = 0; //restart the buffer
    }
    else
    {

      //add it to the buffer and increment the index
      serialBuffer[idx] = data;
      idx++;
    }
  }
}

// ------------------------------------------------------
// Private functions
// -----------------

// it is generally better to make sure that both the left
// and right motors use the same algorithm for speed and power
// so we should put them into their own functions
// that when we change it once, it will change it for both. 
int getPower(int reading){
  //atoi can -1; or reading can be 100; for "center"
  if (reading < 0 || reading == 100)
    return 0;
  else
    return 255; // we like max power, you could also use some value of reading.
}

int getDirection(int reading){
  if (reading < 100)
    return BACKWARD; 
  else 
    return FORWARD; //adafruit constants, isn't nice but ok
}

// -------------------------------------------
// Set Left side motors, either direction
// -------------------------------------------
void setLeft(int reading)
{
  int power = getPower(reading);
  int direction = getDirection(reading);

  frontLeft.setSpeed(power);
  frontLeft.run(direction);

  rearLeft.setSpeed(power);
  rearLeft.run(direction);
}

// -------------------------------------------
// Set Right side motors, depending on position
// -------------------------------------------
void setRight(int reading)
{
  int power = getPower(reading);
  int direction = getDirection(reading);

  frontRight.setSpeed(power);
  frontRight.run(direction);

  rearRight.setSpeed(power);
  rearRight.run(direction);
}

//---------------------------------------------
// extract information from serial and run motors
//---------------------------------------------
void processSerialData()
{
  //send info to computer.
  Serial.println("processing:");
  Serial.println(serialBuffer);

  if (serialBuffer[0] == '%')
  {
    return; //we can receive comments and do nothing with them.
  }

  //this gets a "pointer" to where ':' is in the string
  char *sep = strchr(serialBuffer, ':');

  //if we have a pointer:
  if (sep != 0)
  {

    *sep = 0; //change ':' into NULL; terminating the string.

    // now, serialBuffer as a string will only be up until the
    // original ':' character, as we've nulled the string at this
    // point.
    short leftMotor = atoi(serialBuffer);

    // thankfully, we still have that pointer; we can
    // increment it THEN send to atoi ( precrement );
    // which will get the next segment of data:
    // the pointer up until the original NULL char; (see 10 lines up)
    // for the next segment, until the original NULL char.

    short rightMotor = atoi(++sep);

    Serial.print("setting left to ");
    Serial.println(leftMotor, DEC);

    Serial.print("setting right to ");
    Serial.println(rightMotor, DEC);

    setLeft(leftMotor);
    setRight(rightMotor);
  }
  else
  {
    //send information to the computer, because we have a bug
    Serial.println("Sep is:");
    Serial.println((int)sep, HEX);
    Serial.println((int)*sep, HEX);
    Serial.println(*sep);
  }
}
JimmyBarrel commented 4 years ago

After much trial and error I have determined that even though you can get this to work on the Uno wifi it isn't a great solution. The Arduino has 1 hard serial and then my code above used an additional soft serial - but both hit the same pins on the ESP8266. This impacts the ability to communicate with a PC serial and the the Arduino-ESP communications. The Mega wifi on the other hard allows switching between serial ports between the Arduino and the ESP - thus enabling two ways communications between the two AND communication with your PC. All in all a better experience with the Mega over the Uno.

Jaycar-Electronics commented 4 years ago

Sorry for the late response guys.

Yes, Mega is preferred due to the extra serial ports.

You can theoretically get it to work if you change Serial3 -> Serial but you won't get any debug information on the Arduino IDE; The serial port will only connect between the UNO and the ESP. much like how Jimmy Barrel pointed out.

Also thanks for pointing out the error in the system diagram. I've fixed this here: https://github.com/Jaycar-Electronics/WiFi-Rover/commit/7b66e364124e52176e0ce3d0eaa13de55a392f53

I'll close the ticket as the solution does exist but it's not ideal. People interested in such can read the information above. ( @JimmyBarrel I've edited your comment because you mentioned "Mega" when you were meant to say "Uno" and also included syntax. )