Micro Serial Servo Controller Throughput

Are there specifications for how frequently you can update the SSC?

When I update the controller (in Mini SS II mode) at a 50Hz rate, the green LED flashes but the servo output does not change. The same code at a slower rate works OK.

I can use a slower rate but I’d like to know the limitations.

Is the code and/or schematic available for download somewhere?

Thanks,

Amos Szpiro

Hello,

We don’t really have a spec. for that, but the servo controller should handle updates as quickly as you can send them, which can be faster than 50 Hz. Are you sure all the commands are getting there that quickly? It’s also possible that the servo isn’t capable of responding at 50 Hz in a way that you could really verify.

The schematic and firmware are not available, though a schematic is available in the user’s guide of the old kit version. It’s not the exact same, but it’s pretty similar. I think the main difference is that the servo outputs are swapped a bit to match the PCB layout.

- Jan

Hi Jan,

The relevant code (running on Orangutan X2) is shown below. Although the SteeringCmd is not necessarily updated at 50Hz, the buffer is sent out by the PCINT3 interrupt (last routine) which runs at 50Hz. So, it’s not a question of servo response. When I do BIT the SteeringCmd stays constant for a second. It takes about 6 msec to get the buffer across at 9600 baud so there should be 14 msec left for the controller to act before the next buffer comes across. There must be a limit on the update rate, especially at the lower baud rates.

Thanks

void USART_Init()
{
  /* Set baud rate */
  UBRR0 = (unsigned int)UBRR;
  /* Enable transmitter */
  UCSR0B |= (1<<TXEN0);
  /* Set frame format: 8data, 1 stop bit */
  UCSR0C = (3<<UCSZ00);
  indexUART = countUART = 0;
}

void SendUARTBytes(unsigned char num)
{
  while (UARTBusy)
  {
    ;
  }
  indexUART = 0;
  countUART = num;
  UARTBusy = true;
  UCSR0B |= (1<<UDRIE0);
}

#pragma vector=USART0_UDRE_vect
__interrupt void USART0_UDRE_Interrupt()
{
#pragma diag_suppress=Pa082
  if (indexUART < countUART)
#pragma diag_default=Pa082
  {
    UARTBusy = true;
    UDR0 = buffUART[indexUART];
    indexUART++;
  }
  else
  {
    UCSR0B &= ~(1<<UDRIE0);
    UARTBusy = false;
  }
}

#pragma vector=PCINT3_vect
__interrupt void PCINT3_Interrupt()
{
  PCMSK3 &= ~(1<<PCINT26);
  PORTD  &= ~(1<<PD2);
  __enable_interrupt();
  ConvertGyro();
  if (!BIT)
  {
    ComputeSteering();
  }
  if (++N50 == 25)
  {
    N50 = 0;
    LCount++;
    Do2HZ = true;
  }
  if (PCINT0_width < 35 && LCount > 2)
  {
    DoMotors = false;
  }
  buffUART[STEERING_SETTING] = SERVO_MID + SteeringCmd;
  SendUARTBytes(6);
  Do50HZ = true;
}

Your code looks like quite a mess. I didn’t look at it too much, but it seems like you have several potentially overlapping interrupts that possibly have long delays in them. If you’re looking at some internal state of your program and saying it’s not changing for a second, it’s not really indicative of anything to do with the servo controller. If you want to test the servo controller, you can just make a loop that sends a bunch of commands one after another.

Do you have an oscilloscope or other means of looking at the serial data you’re sending?

- Jan

Jan,

If you didn’t look at it, how do you know it’s a mess?

I’d be glad to take lessons from you on real-time programming, but for now I just asked you about the limitations of your servo controller!

If you don’t know the answer just say so!

I’m not sure what tone you’re intending, but your last post sounds quite unreasonable.

I did look at your code; that’s why I saw that it was a mess and didn’t look at it too much. Perhaps you have a good reason for it to look the way it does, but I don’t think it’s reasonable to expect others to be able to follow it. How long do you think someone should spend trying to unravel what you posted?

I already answered your servo controller limitation question in my first reply: the servo controller should be able to handle commands as quickly as you can send them. I’m still not sure why you think there must be some other limit.

- Jan

Hi Jan,

I’m sorry for the tone.

I sent the code to give you an idea of how I send the data across, e.g. that I send 6 bytes at a time. It is unreasonable of me to expect anyone to easily decipher the code for an interrupt-driven system. You can rest assured, however, that interrupts over-running their time slot is upper most in my mind.

I think that the controller has a limit because:

  1. When I run it at 10Hz it works like a charm, at 50Hz the green light flashes but the commands go out at ‘neutral’ (1500 msec).

  2. The UART is running without a handshake and it seems that I can overun the cpu in the controller if all it does is service the UART.

  3. Every system has limits. In this case perhaps the slow (9600 baud) allows for breathing space, but still there must be a limit.

After saying all this, I could still be wrong. For the last two weeks I’ve been fixing timing problems with my code, and I’m sure that there are more bugs crawling in there. That’s why I asked whether I can look at the firmware of the Servo Controller, so that I can convince myself that the problem is in my code.

Thanks,

The slow serial rate indeed gives the servo controller time to do everything else faster than the commands come in. The pulse edges themselves are made in response to a single timer interrupt; everything else is basically a loop that reads the UART and schedules the timer interrupts. The only buffer used is the microcontroller’s two-byte hardware buffer, and any buffer overrun should trigger a fatal error, so I’m fairly confident that a buffer overrun is not happening on the servo controller side.

If you’re not convinced, it should be pretty easy to write a quick loop that would just sit there sending commands to the servo controller as fast as the data rate will allow. If the servo controller fails that test, it should be easy for us to follow and reproduce that test here.

- Jan

Hi Jan,

You are right.
At 9600 baud the SSC keeps up with the fastest valid data. I tested it with the code shown below.

Something interesting to note:
The SSC is a 50Hz sampler; I assume that it produces the normal RC rate. If you send signals equal to or faster than 50Hz they could be aliased or disappear altogether. It seems that the rate of signals sent to the SSC should be no greater than 25Hz. This is a raw thought that is worth pondering.

#include <ioavr.h>
#include <inavr.h>
#include "..\spi-wrappers\SPI.h"

#define BAUD_RATE 9600
#define UBRR ((F_CPU / 16 / BAUD_RATE) - 1)

unsigned char buffUART[21]  = {
        0xff, 1, 127,
        0xff, 0, 127, 
        0xff, 1, 127,
        0xff, 0, 191,
        0xff, 1, 127,
        0xff, 0, 127,
        0xff, 0, 127 
       }; 

int main( void )
{
  int i;
  UBRR0 = (unsigned int)UBRR;
  UCSR0B |= (1<<TXEN0);
  UCSR0C = (3<<UCSZ00);
   
  while(1)
  {
    for (i = 0; i < 21; i++)
    {
      while (!(UCSR0A & (1<<UDRE0)))
      {
        ;
      }
      UDR0 = buffUART[i];
    }
    delay_ms(1);
  }  
  return 0;
}

If you sent alternating ±60 degree positions at around 100 Hz, it’s likely the output would correspond to just one of those extremes and occasionally switch. However, the servo would never have had a chance of keeping up with that, anyway. If you want to look at it from a sampling perspective, I think the 25Hz limit you mention is only on the frequency component of what is in your data, not on the command rate itself. You should be able to send commands at 100 Hz describing a 2 Hz oscillation, and the servo will execute that motion correctly.

- Jan