Windows <-> Mega 2560 serial problems

Hey everyone,
I recently bought an Arduino Mega 2560 I was going to use as a servo/motor control board for a robotics project I was working on. I wanted to be able to send messages back and forth from a PC to the arduino through the FTDI USBSERIAL chip.

I wrote two programs, one in C# that sends a formatted message to the arduino.

<Various usings>

namespace ArduinoTalker
{
    interface ByteSerializable
    <Snip>

    class SerialHeader : ByteSerializable
    {
        static int size = 3 * sizeof(byte);

        byte packetNum;
        byte dataSize;
        byte checksum;

        <Snip>
    }

    class ServoControl : ByteSerializable
    {
        public enum Cmds
        {
            SET_POS = 0,
            GET_POS = 1
        };

        static int size = 3;

        byte _cmd;
        short _pos;
        <Snip>
    }

    class Program
    {
        static byte packetIdx = 1;
        static SerialPort port = null;

        static void SerialSend(ByteSerializable data)
        {
            byte[] inBuf;
            SerialHeader sh = new SerialHeader();
            sh.PacketNum    = packetIdx++;
            sh.DataSize     = (byte)data.Size;
            sh.Checksum     = 0;

            inBuf = new byte[sh.Size];

            try
            {
                /* Write the info header to the port */
                port.Write(sh.Pack(), 0, sh.Size);

                /* Write the data to the port */
                port.Write(data.Pack(), 0, data.Size);

                port.ReadTimeout = 1000;
                port.Read(inBuf, 0, sh.Size);

                System.Console.WriteLine("Got ACK from Arduino!\n");
            }
            catch (Exception E)
            {
                System.Console.WriteLine("SerialSend: Failed to send data: {0}\n", E.ToString());
            }
        }

        static void SerialInit(string Port, int baudRate)
        {
            if (port == null)
            {
                try
                {
                    port = new SerialPort(Port, baudRate);

                    port.Open();
                }
                catch (Exception E)
                {
                    System.Console.WriteLine("SerialInit: Error opening port: {0}\n",E.ToString());
                }
            }
        }

        static void Main(string[] args)
        {
            string userInput;
            ServoControl servo = new ServoControl();

            SerialInit("COM4", 9600);

            while (true)
            {
                System.Console.WriteLine("What to do?\n"+
                                         "  1) Set servo Position\n"+
                                         "  2) Get Servo Position\n"+
                                         "  3) Quit");
                userInput  = System.Console.ReadLine();

                switch (Convert.ToInt32(userInput))
                {
                    case 1:
                        servo.Cmd = (byte)ServoControl.Cmds.SET_POS;

                        System.Console.WriteLine("Enter the position 0<x<170");
                        servo.Pos = Convert.ToInt16(System.Console.ReadLine());

                        SerialSend(servo);
                    break;

                    case 2:
                    break;

                    case 3:
                        System.Console.WriteLine("Bai!");
                        port.Close();
                        return;
                    break;
                }
            }
            
        }
    }
}

This program just opens COM4 and asks the user to input a servo position and then sends it to the Arduino using my little protocol. The protocol for now is really simple: Every chunk of data is preceded by a 3 byte header, that tells the size of the packet. Then the data is transmitted.

Then I wrote the following program that runs on the Arduino that simply sits there and listens for data and sets the servo’s position appropriately.

#include <Servo.h>

typedef struct ServoControl
{
  byte Cmd;
  short Pos;
}ServoControl;

typedef struct SerialHeader
{
  byte packetNum;
  byte dataSize;
  byte checksum;
} SerialHeader;

Servo myServo;

void setup()
{
  Serial.begin(9600);
  myServo.attach(9);
  myServo.write(85);
  pinMode(13,OUTPUT);
}

char SerialReadMsg(char *buf, char numBytes)
{
  char i = 0;
  SerialHeader hdr;
  
  digitalWrite(13,HIGH);

  memset(&hdr,0,sizeof(hdr));  
  while(Serial.available() < sizeof(hdr));
  
  for(i = 0; i<sizeof(hdr); i++)
  {
    ((byte*)&hdr)[i] = Serial.read();
  }
  
  while(Serial.available() < hdr.dataSize);
  for(i = 0; i<hdr.dataSize; i++)
  {
    buf[i] = Serial.read();
  }
 
   /* Send ACK back to PC */
   hdr.dataSize = -1;
   Serial.write((byte*)&hdr,sizeof(hdr));

  digitalWrite(13,LOW);
  
  return i;
}

void loop()
{
  ServoControl params;
  SerialReadMsg((char*)&params,sizeof(params));
  
  myServo.write(params.Pos);
}

This code works… but only for a short while. After a few messages I get a C# exception that says the device has stopped working, or the Read for the ACK times out.

Once this happens, even the programmer can’t talk to the Arduino. If I try to download a program I get “Binary sketch size: 3552 bytes (of a 32256 byte maximum)
avrdude: stk500_getsync(): not in sync: resp=0x00
avrdude: stk500_disable(): protocol error, expect=0x14, resp=0x51”

If i Unplug the arduino, and then plug it back in (USB that is) Everything seems to return to normal, and I can repeat the process. Am I doing something fundamentally wrong, or is there a problem with the FTDI driver on windows 7?

Edit: I also have an Arduino UNO SMD that I ran the same program on, with exactly the same problems.

OK another update: I've been messing around with debugging it, and in the process of adding some LED's to the system as feedback states (I don't have a Serial -> USB converter to use one of the extra serial connections on the MEGA) I accidentally wired my servo to the WRONG pin. I didn't notice this at first; so I started off a test that just sent a new message in the format i described before to the Mega & 5Hz (200Ms delays). There was not a single failure over 1000 samples. I couldn't believe this at first, and then i noticed that the servo wasnt moving and found my wiring error. I started the test again, and let it run for a bit, then plugged the servo into the correct PWM pin, and almost immediately the board failed exactly as it did before. Removed the servo and rebooted the Mega, and it works fine. So there's something happening with the PWM output. I'm sifting through the PWM library now, but if anyone has any ideas they'd still be greatly appreciated.

-Gerald

Update 3: I tried an external power supply. Measued 9.4V on the external power plug. Checked all other voltages on the board, and everything seems OK. Serial comms still get all hokey if the servo is connected. I guess the next thing to do is try another servo... This thread has 20 reads so far... i was hoping someone would have seen something similar.... I can't be the only person who'se seen this problem :(

Shameless bump. No one has experimented with this or seen the problem?

sigh Yet another shameless bump.

I still haven't found the issue myself. I'm going to buy a usb/serial converter next and try one of the other serial connections on the Mega... :(

Sorry, I haven’t experienced that exact problem.

But have you measured the 5v output on the Arudino when you’re running the servo to see if its dropping? If it is, maybe try an external 5v supply to power the Arudino?

Im supplying external power with a 8.6V 2A wall wart through the barrel jack. I did watch the voltage on my scope and it didn't drop. My scope is kind of old though, so I could have missed it, but I'm fairly confident that's not the issue (at least not with that external PS)

Hey everyone! I finally found the problem. It turns out that it WAS a power problem, but not a current related one. What was happening that my little servo was actually causing a 1.1V drop in the 5v line at it's extremeties. This happens even with an external 9.8V 2A power supply (via the barrel jack). I solved the problem by putting a couple of capacitors between 5V and Ground to stabilize the voltage a bit. It worked. I used two 10uF and that seemed to be enough. There's still a little bit of drop, so i'm gonna go out and get some bigger caps, but it works flawlessly now.

Thanks -Gerald