Speed up Maestro with servo op and sharp IR as input?

Hi, my first post and by the way the Maestro’s are great.

Right, I have built an autonomous R2D2 with 2 Maestros (12 and 24) running over USB from WinXP. They are used for his numerous sensors, radars etc. I need to speed up one of his sweeping IR radars which is a Sharp IR sensor mounted on a servo that rotates back and forth.

When you set the servo to sweep from side to side, and read the sharp ir at the same time the input reading rate is very slow (about 5hz).

I use c# and the code is very simple with the main bits being:

TrySetTarget(Channel, iPosition); //to move the servo back on forth called from a timer.

Then I call this to get the servo’s current position for the X value on the radar, and again on the IP channel to get the sharp IR reading for the Y value:

Pololu.Usc.ServoStatus S;
S = GetServoStatus();
pos = int.Parse(S[Channel].position.ToString());

5hz (or readings) max per 180 degree of servo sweep is pretty poor. If you slow the servo right down with a speed of about 5 the rate rises to about 10hz, but thats it. On their own it’s more like 50hz.

Any ideas? can I speed up the USB baud rate? or am I missing something?

Many thanks for any help

Julian

Hello.

You should be able to read the sensor a lot faster than 5 Hz.

Could you post the code for GetServoStatus(), and the entire bit of code that calls it? You must have a loop or timer or something that calls it repeatedly, but the code you posted only calls it once.

Another thing I noticed is that this line is needlessly complicated:

This should work, the “(int)” cast it probably not even necessary:

Also, if you have any other threads or timers running, they could be interfering with the code that reads the sensor, so you should tell us what’s going on in your program. How much of your CPU is being used when the program runs?

–David

Hi thanks for you response.

There is a lot going on as you can imagine, including web cam motion detection, speech recognition, motors etc all on their own threads with a central core watching all of them but I can and have switched them all off except for this loop…

This is the timer loop (LastServoPos is just to compare if the servo is moving or not and I couldn’t get your getIsMoving fuction to work - or some name like that)

private void timerIR_SensorTick(object sender, EventArgs e)
        {
            if (LastServoPos == 0) //startup val
                PMF.MoveServo(5, 1000);

            if (LastServoPos == PMF.GetServoPosition(5)) //no change in pos so change direction
            {
                if (PMF.GetServoPosition(5) > 7999)
                    PMF.MoveServo(5, 1000);
                else
                    PMF.MoveServo(5, 2000);
            }
            LastServoPos = PMF.GetServoPosition(5); //now get current servo pos (X value)
            int Lastx = (LastServoPos - 4000) / 7; //scale to fit output screen (600px) later
            int RRF = PMF.GetServoPosition(1); //Read the Y value to plot proximity
            txtLog.Text += Lastx.ToString() + "-" + RRF.ToString() + "\r\n"; //record / show on screen. Still slow with this remmed out.
            
        }

      public int GetServoPosition(byte Channel)
        {
            int pos = 0;
            Pololu.Usc.ServoStatus[] S;
            S = GetServoStatus();
            pos = (int)S[Channel].position;
            return pos;
        }

Don’t worry about the esarlier sloppy casting to an int it shouldn’t have a significant effect, I was just being lazy - although I will change it and test it just in case. The issue seems to be that if you call the getservopos for just a servo, it’s fast, if you call it to just the sharp sensor it’s fast (maybe 250hz) but if you call either then a servo is moving it’s dead slow (10hz or less).

I’ve hacked the code about loads of times and this seems to be what slows it down. As a test, if you set a servo in motion at a slow speed of say 50 and read the position, it will not read fatser than about 10 readings per full swing even if your timer has an interval of 1 (or 1000th of a second)?

No issues with CPU as the loop is the only thing running for this test and utilisation is less than 20% for the whole computer and rises to about 60% with R2D2 fully active.

Many Thanks

oops forgot…to add this…

public Pololu.Usc.ServoStatus[] GetServoStatus()
        //public Pololu.Usc.ServoStatus[] GetServoStatus(out Pololu.Usc.ServoStatus[] srvStatus)
        {
            Pololu.Usc.ServoStatus[] srvStatus;
            using (Usc device = connectToDevice())  // Find a device and temporarily connect.
            {
                device.getVariables(out srvStatus);

                // device.Dispose() is called automatically when the "using" block ends,
                // allowing other functions and processes to use the device.
            }
        
            return srvStatus;
        }

From the code you posted, it looks like you are potentially opening a new handle to the Maestro and then disposing of it 5 times every time the timer executes. I suspect that connectToDevice() is the bottle neck in your program, but you could use a profiler to see for sure. Try just opening just one handle every time the timer ticks, or just keep a handle open all the time (and dispose of it when the device gets disconnected).

–David

Hi,

I didn’t really look at the pololu example code to much but your right it does seem silly to keep creating the device connection and then dumping it. I’ll change it and then update the forum with the results for others.

Many Thanks

Hi again,

I stripped it rightback and kept a single connection to the device open. The frequency has now risen from about 10hz to 25hz, so quite a bit better, but it seems 25hz for a single servo position read in a loop is the limit for the maestro?

I connect to the device initially on load and then stay active while I run the timer below. Under the timer I have:

private void timerServo2_Tick(object sender, EventArgs e)
{
txtLog.Text += PMF.GetServoPosition(1) + “\r\n”; //Chan 1 is a sharp IR sensor.
}

public ushort GetServoPosition(byte Channel)
{
ushort pos = 0;
device_maestro.getVariables(out S);
pos = S[Channel].position;
return pos;
}

I then tested the timer and interestingly the Windows Forms timer with it’s interval set to 1 or 1000th or a second does not tick that fast even with a simple i++; it would seem that it can’t tick faster that about 75hz-100hz even though you can set the interval to 1!. You have to use an unmanaged API or stopwatch class to get access to a faster timer. I wonder how many people know that.

Many Thanks

I’m glad you were able to improve the performance. I tested the Maestro Control Center on my computer and it reads the status of the Maestro about every 60 ms (16.7 Hz). I looked at the signals on the USB data lines and the actual transfer of the servo data (168 bytes, 7 bytes per channel) takes a little over a millisecond, but of course that doesn’t count any overhead from the operating system. I’m running Windows 7 and a 24-channel Maestro.

You mentioned you have a webcam. It uses USB, right? I wonder if the traffic from the webcam might crowd out the Maestro traffic to some extent. Could you try removing the webcam and any other USB devices and see if the numbers change?

If you haven’t seen this article about timers yet, you should check it out: Comparing the Timer Classes in the .NET Framework Class Library.

–David