Serial connection issue

I have an arduino leonardo shield connected to raspberry pi. A DC motor shield is connected to the arduino and a pwm servo driver is connected to the arduino as well.
The raspberry pi issue commands to arduino via pyserial and arduino control respective motors.
The issue is, the arduino hangs on 2 occasions 1) on raspberry pi power on 2) after about 1hr of working.
It gives no error, the reading of values from serial monitor stops and goes into an infinite loop.
Sometimes if i refresh the arduino/ reupload the script it works, sometimes it doesnt. Such cases require multiple reboots and refreshes.
Im building a voice controlled robot, but the purpose would be defeated if i'd have to manually rst the arduino once in a while.
There is a possibility that it may be a loose i2c connection, but i changed the wires, tested the continuity and double and triple checked the connections. But the i2c scanner hangs on wire.endTransmission().
Im not sure where to start troubleshooting since there's no errors.
Please help i've been stuck on this of ages.

Hi,
Can you please post your code?
Can you please post a circuit diagram including the connection to the Pi?

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

I can post the code, as for connections, they're shields that I stacked one on top of another,i'd have to dismantle the entire robot to take a pic of it.So, i'll send my code first and if the connections are still required, i'll send it. Thank you for the help.

Arduino Code:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#define SERVO_FREQ 50
#define USMIN  600
#define USMAX  2400

const uint8_t servo_tilt = 0;
const uint8_t servo_pan = 2;
const uint8_t servo_us = 4;

const int E1 = 6;
const int E2 = 11;


const int M1 = 7;
const int M2 = 12;

int URECHO = 3;
int URTRIG = 5;


/////Pan and Tilt///////////////////////////////////////////////

char range_sweep(uint16_t start, uint16_t ends) {
  uint16_t pulselen, deg;
  char stat = 's';
  for (deg = start; deg < ends && get_distance() > 30 && stat != 'x'; deg++) {
    pulselen = map(deg, 0, 300, USMIN, USMAX);
    pwm.writeMicroseconds(servo_pan, pulselen);
    stat = Serial.read();
    delay(20);
  }
  Serial.println(deg);
  for (deg = deg; deg > start && get_distance() > 30 && stat != 'x'; deg--) {
    pulselen = map(deg, 0, 300, USMIN, USMAX);
    pwm.writeMicroseconds(servo_pan, pulselen);
    stat = Serial.read();
    delay(20);
  }
  Serial.println(deg);
  initial();
  return stat;
}

void pan() {
  uint16_t degree = 0;
  char stat = 'p';
  while (degree < 300 && stat != 'x') {
    uint16_t pulselen = map(degree, 0, 300, USMIN, USMAX);
    pwm.writeMicroseconds(servo_pan, pulselen);
    delay(30);
    degree++;
    stat = Serial.read();
  }
  Serial.println(degree);
  initial();

}

void tilt() {
  uint16_t degree = Serial.parseInt();
  uint16_t pulselen = map(degree, 0, 180, USMIN, USMAX);
  pwm.writeMicroseconds(servo_tilt, pulselen);
}

void sense(uint16_t degree) {

  uint16_t pulselen = map(degree, 0, 180, USMIN, USMAX);
  pwm.writeMicroseconds(servo_us, pulselen);
}


////motor////

void stop_motor(void)
{
  Serial.println('x');
  digitalWrite(E1, 0);
  digitalWrite(M1, LOW);
  digitalWrite(E2, 0);
  digitalWrite(M2, LOW);
}

void left(int Speed)
{
  Serial.println('l');
  analogWrite (E1, Speed);
  digitalWrite(M1, HIGH);
  analogWrite (E2, Speed);
  digitalWrite(M2, HIGH);
}


void right (char Speed)
{
  Serial.println('r');
  analogWrite (E1, Speed);
  digitalWrite(M1, LOW);
  analogWrite (E2, Speed);
  digitalWrite(M2, LOW);
}

void advance(char a)
{
  analogWrite (E1, a);
  digitalWrite(M1, LOW);
  analogWrite (E2, a);
  digitalWrite(M2, HIGH);
}
void backward(char a)
{
  Serial.println('b');
  analogWrite (E1, a);
  digitalWrite(M1, HIGH);
  analogWrite (E2, a);
  digitalWrite(M2, LOW);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//US Sensor////////////////////////////////////////////////////////////////////////////////////////////////

unsigned int get_distance()
{
  digitalWrite(URTRIG, LOW);
  digitalWrite(URTRIG, HIGH);
  unsigned int DistanceMeasured = 0;
  unsigned long LowLevelTime = pulseIn(URECHO, LOW) ;

  if (LowLevelTime >= 50000)
  {
    Serial.println("Invalid");
  }

  else
  {
    DistanceMeasured = LowLevelTime / 50;
  }

  return DistanceMeasured;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Search////////////////////////////////////////////////////////////////////////////////////////

void turn_direction(char side) {
  if (side == 'r') {
    right(100);
    delay(2800);
  }
  else {
    left(100);
    delay(2800);
  }
  stop_motor();

  delay(1000);
}

String avoid_obstacle(char side) {

  uint16_t angle = (side == 'r') ? 0 : 180;
  int limit = 0;
  int flag = 0;
  char opposite = (side == 'r') ? 'l' : 'r';
  stop_motor();
  backward(100);
  delay(1000);
  Serial.print("Turning ");
  Serial.println(side);
  turn_direction(side);

  while (get_distance() < 30) {
    limit = 0;
    sense(angle);
    while (get_distance() < 30 && limit < 35) {
      sense(angle);
      advance(50);
      delay(1000);
      limit++;
      sense(100);
      if (get_distance() < 30)
        flag = 1;
    }

    if (flag == 1) {
      advance(50);
      delay(1000);
      stop_motor();
      delay(500);
      turn_direction(side);
      return "continue";
    }

    if (limit >= 35) {
      return "wall";
    }

    advance(50);
    delay(1000);
    stop_motor();
    delay(500);
    turn_direction(opposite);
    return "continue";

  }

}
void search(char side) {
  Serial.print("Starting search");
  String obstacle = "continue";
  char stat = 's';
  while (stat != 'x') {
    Serial.println("Going to opposite wall");
    while (get_distance() > 30 && stat != 'x') {
      advance(70);

      stat = range_sweep(0, 300);
    }

    if (stat != 'x' && obstacle != "wall") {
      backward(100);
      delay(1000);
      stop_motor();

      Serial.print("Turning First ");
      Serial.println(side);
      turn_direction(side);

      Serial.println("Going 4 feet");
      for (int i = 0 ; i < 10 && stat != 'x' ; i++) {
        if (get_distance() < 30) {
          Serial.println("Avoiding Obstacle");
          obstacle = avoid_obstacle(side);

        }
        advance(100);
        delay(1000);
        stat = Serial.read();
      }
      if (obstacle != "wall") {
        Serial.print("Turning second ");
        Serial.println(side);
        turn_direction(side);
      }
      side = (side == 'r') ? 'l' : 'r';
    }
  }
}

void return_home() {
  Serial.println("Returning home");
  char stat = 'h';
  int count = 0;
  unsigned int right_dist = 0;
  unsigned int left_dist = 0;
  char side = 'r';
  advance(70);
  while (stat != 'z') {
    stat = Serial.read();

    if (get_distance() < 30 && stat != 'x') {
      stop_motor();
      sense(0);
      right_dist = get_distance();
      delay(1000);

      sense(180);
      left_dist = get_distance();
      delay(1000);

      sense(100);
      char side = (right_dist > left_dist) ? 'r' : 'l';
      avoid_obstacle(side);
      Serial.println('c');
      delay(1000);
      advance(100);
    }
  }
  stop_motor();
}
void initial() {
  stop_motor();

  uint16_t pulselen = map(150, 0, 300, USMIN, USMAX);
  pwm.writeMicroseconds(servo_pan, pulselen);

  pulselen = map(100, 0, 180, USMIN, USMAX);
  pwm.writeMicroseconds(servo_us, pulselen);

  pulselen = map(50, 0, 180, USMIN, USMAX);
  pwm.writeMicroseconds(servo_tilt, pulselen);

}
void setup()
{
  Serial.begin(115200);

  //motor setup
  for (int i = 3; i < 9; i++)
    pinMode(i, OUTPUT);
  for (int i = 11; i <= 13; i++)
    pinMode(i, OUTPUT);
  digitalWrite(E1, LOW);
  digitalWrite(E2, LOW);
  delay(500);

  //US setup
  pinMode(URTRIG, OUTPUT);
  digitalWrite(URTRIG, HIGH);
  pinMode(URECHO, INPUT);
  delay(500);

  //Pan and Tilt setup
  pwm.begin();
  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(SERVO_FREQ);
  delay(500);
}
void loop()
{
  if (Serial.available()) {
    Serial.println("Serial working");
    char val = Serial.read();
    Serial.println(val);

    switch (val)
    {
      case 'f': advance(70);
        break;

      case 'b': backward(100);
        break;

      case 'l': left(70);
        break;

      case 'r': right (70);
        break;

      case 'p': pan();
        break;

      case 't': tilt();
        break;

      case 's': sense(60);
        break;

      case 'i': initial();
        break;

      case 'x': stop_motor();
        break;

      case 'h': return_home();
        break;

      case 'u': Serial.println(get_distance());
        break;

      case 'q': Serial.println(get_distance());
        sense(0);
        delay(1000);
        unsigned int right_distance = get_distance();
        delay(1000);


        sense(180);
        delay(1000);
        unsigned int left_distance = get_distance();
        delay(1000);

        sense(100);
        Serial.println(right_distance);
        Serial.println(left_distance);

        char side = (right_distance > left_distance) ? 'r' : 'l';
        search(side);
        break;
    }

  }

}

This may or may not be significant , the Leonardo creates its USB port in software and this can result in different assignment of the com port on start up- seen this on connections with a PC

yes, i wrote static usb rules for it, so no matter which port it changes to, it will be references by the same link

Hi,
To add code please click this link;

How have you got the Pi connected to the Arduino?

Tom... :smiley: :+1: :coffee: :australia:

This is the first time im using the forum, thank you for the help. I have connected arduino to raspberry pi 3B+ using a usb cable

I see you are returning Strings from a number of methods.
What is the last debug output you get? The nice thing about using Strings on AVR boards is that it is very difficult to 'crash' the program. So add some more debug output.

Re the i2c connection. It can get into a frozen state. Check out this tutorial on clearing the ic2 buss

This may be one case where you need to either follow the guidelines in Taming Arduino Strings
OR
replace Strings with SafeStrings

As well as some String debugging code, the guidelines for Strings, if you are getting problems, includes passing the result String as reference to be updated by the method
That is
String avoid_obstacle(char side) {
becomes

void avoid_obstacle(char side, String& object) {
  ... 
  object = "wall";
  // etc
}

and called by

Serial.println("Avoiding Obstacle");
avoid_obstacle(side, obstacle);

Another alternative is to replace Strings with SafeStrings.
String obstacle = "continue";
becomes
createSafeString(obstacle, 15, "continue");

and statements like
if (stat != 'x' && obstacle != "wall") {
continue to work
and you pass a SafeString& to your methods to get the results

void avoid_obstacle(char side, SafeString& object) {
  ... 
  object = "wall";
  // etc
}

BUT ... start with adding more debug output to narrow down where the code is not doing what you expect it could just be a logic problem you are triggering.

Other points the tilt() method uses
uint16_t degree = Serial.parseInt();
so it is difficult to see what is going on there. At least check degree for == 0 (error most likely) or for some weird value.

I would be rewriting the Serial handling slightly to add a \n terminator to the commands and reading a line at a time and parsing it. That way you can check what is actually arriving at the unit by echoing it back to the pi.
Arduino Software Solutions has a number example sketches for reading Serial lines of data and parsing.