Go Down

Topic: Conflict between Servo and Serial commands on Arduino Uno with Mega 2560. (Read 935 times) previous topic - next topic

Kaikydelan

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 = 0;
 }
}

void loop()
{
 if (Serial.available() > 0)
 {
   for (int i = 0; i <= 3 ;i++)
   {
     m_serialData = 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;
}



jraskell

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.

Kaikydelan

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.

Go Up