Conflict between Servo and Serial commands on Arduino Uno with Mega 2560.

Hi,

I’ve been trying to get a project up and running for controlling a remote control car using a netbook and an arduino Uno Mega 2560. It’s been an absolute nightmare as the Serial library seems to be stomping on the Servo memory. Every time I poll for sensors, the servo memory connected to the forward/backward driving motor goes into full speed forward.

Any attempt to use a state variable to update the servo value causes the system to go full speed forward as well (where the full speed corresponds to a zero being written to the servo using c_drive.write(0); )

Is there any way to avoid the system losing control when the sensor data is returned using

for (int i2 = 0;i2 < k_numberOfSensors;i2++)
  {    
    Serial.write(f_processDistance(f_readValue(i2)));
  }  
  Serial.write('~');
}

I’ve tried several methods such as keep a state variable and updating the motor each time, yet it seems likely that it’s a fault with the hardware, seeing as though I have no control over whether the memory for the system is being overwritten.

Attached below is the source code.

#include <Servo.h>

#define k_upperBound 150          // Highest allowed angle for servo motors
#define k_lowerBound 50           // Lowest allowed angle for servo motors

#define k_servoSteerNeutral 100    // Neutral position in relation to servo degrees for direction
#define k_servoSteerRight   70
#define k_servoSteerLeft    130

#define k_servoDriveNeutral  100   // Neutral position in relation to servo degrees for driving
#define k_servoDriveForward  90
#define k_servoDriveBackward 110

#define k_servoDrivePin 9         // Pin on board used for driving
#define k_servoSteerPin 10        // Pin on board used for steering

#define k_smoothingFactor 32      // Constant used in the smoothing function
#define k_calibSlope 2323.66      // Calibration constant for linear regression in
// the conversion function
#define k_calibIntercept 16.8     // Calibration constant for linear regression intercept
// in the conversion function
#define k_calibDelay 5000         // Delay for 'x' microseconds for calibration of sensors.                                 
#define k_numberOfSensors 1       // Number of sensors currently active on the board

Servo c_steer;                    // Servo controller for the steering motor
Servo c_drive;                    // Servo controller for the driving motor
unsigned char m_serialData[129];  // Buffer for incoming serial data
int c_state = 0;                  // Auxiliary state variable

unsigned char m_serialResponse[129];  // Buffer for outgoing serial data.
char m_respond = 0;          // Indicates the data will be flushed serially.

int t_i = 0;
int i_values[k_numberOfSensors];



// ------- PROTOTYPES --------

int f_readValue(int i_num);
double f_convDistance(int i_valueD);
unsigned char f_processDistance(int i_value1);
int limit(int input);


// ------- MAIN PROGRAM ------

void setup()
{
  Serial.begin(9600);
  c_steer.attach(k_servoSteerPin);
  c_steer.write(k_servoSteerNeutral);
  c_drive.attach(k_servoDrivePin);
  c_drive.write(k_servoDriveNeutral);

  for (int i = 0; i < 128; i++)  // Initialize the storage buffer.
  {
    m_serialData[i] = 0; 
  }
}

void loop()
{
  if (Serial.available() > 0)
  {
    for (int i = 0; i <= 3 ;i++)
    {
      m_serialData[i] = Serial.read();
    }

    if ((m_serialData[0] & 0x80) != 0x80)
    {
      // Control it using automated commands
      int in_state = (m_serialData[0]) & 0x03;
      switch (in_state)
      {
      case 0:
        break;
      case 1:
        c_drive.write(k_servoDriveForward);
        break;
      case 2:
        c_drive.write(k_servoDriveBackward);
        break;
      case 3:
        c_drive.write(k_servoDriveNeutral);
        break; 
      }
      in_state = ((m_serialData[0]) & 0x0C) >> 2;
      switch(in_state)
      {
      case 0:
        break;
      case 1:
        c_steer.write(k_servoSteerRight);
        break;
      case 2:
        c_steer.write(k_servoSteerLeft);
        break;
      case 3:
        c_steer.write(k_servoSteerNeutral);
        break; 
      }
    }
     else  // MANUAL CONTROL
    {
       if ((m_serialData[1] & 0x01) == 0x01) { c_steer.write(limit(((signed char)m_serialData[1] >> 1)+k_servoSteerNeutral));}
       if ((m_serialData[2] & 0x01) == 0x01) { c_drive.write(limit(((signed char)m_serialData[2] >> 1)+k_servoDriveNeutral));}
     
    } 
  }

  for (int i2 = 0;i2 < k_numberOfSensors;i2++)
  {    
    Serial.write(f_processDistance(f_readValue(i2)));
  }  
  Serial.write('~');
}










// ----------------------------------------- FUNCTIONS ------------------------------------

int f_readValue(int i_num)
{
  int input;

  switch(i_num)
  {
  case 0:
    input = analogRead(A0);
    break;
  case 1:
    input = analogRead(A1);
    break;
  case 2:
    input = analogRead(A2);
    break;
  case 3:
    input = analogRead(A3);
    break;
  case 4:
    input = analogRead(A4);
    break;
  case 5:
    input = analogRead(A5);
    break;
  case 6:
    input = analogRead(A6);
    break;
  case 7:
    input = analogRead(A7);
    break;
  default:
    input = analogRead(A0);
    break;
  }
  return input;

}

double f_convDistance(int i_valueD)
{
  // For a rough estimate of the distance from the sensor to the object,
  // it will be roughly reverse-regressed linearly. The returned value 
  // is a value in centimeters, based on the previously accumulated data
  // from both the data sheet for the Sharp 2D120X F 01 and from physical
  // data.

  if (i_valueD - k_calibIntercept == 0)
  {
    return 255.0;
  }
  else{  
    return (abs(k_calibSlope / (i_valueD - k_calibIntercept)));
  }

  // In case of demons trying to eat the carpet again....

    return 0.0;
}

unsigned char f_processDistance(int i_value1)
{
  // To simplify the data being sent, the distance is turned from a full
  // "double" to an unsigned character.
  double i_distance = f_convDistance(i_value1);

  if ((i_distance >0)&&(i_distance <=255))
  {
    return (unsigned char)ceil(i_distance); 
  }
  if (i_distance < 0)   
  {
    return 0;

  }
  if (i_distance >255)  return 255;

  // In case of escaping cats of shame...
  return 0;
}


int limit(int input)
{ 
  // To make sure the system operates correctly, all inputs must be
  // bounded values when outputted to the servo.
  int output = 0;
  output = input;
  if (output > k_upperBound) { 
    output = k_upperBound;
  }
  if (output < k_lowerBound) { 
    output = k_lowerBound;
  }
  return output;
}

Don't know if this is related to your problem or not, but you have one line in setup() "m_serialData = 0 "and one line near the beginning of loop() "m_serialData = Serial.read()", and both should be using m_serialData since m_serialData is an array.

Ah sorry,

When the code was copied from the source file, it seems that m_serialData didn't make it. I don't know why. It's still not working though.