Best motor update speed

  1. 7 years ago

    jpearman

    26 Sep 2011 Moderator, ROBOTC Tech Support, V5 Beta Moderator Los Angeles 8888
    Edited 2 years ago by jpearman

    Update (2016): Just to note that this thread was created back in 2011, it's still relavant but note that references to things like master firmware versions are now very out of date.

    Not much going on this afternoon so time to do something I have been meaning to post for a while. The following gets a bit technical but is not intended to confuse anyone, it’s specific to RobotC running on the cortex, EasyC and/or PIC may be completely different. My analysis of how the cortex works is an opinion based on observations and may be in fact inaccurate.

    So I pose the question “How often do motors need to be updated?

    The reason for asking is that I keep seeing students writing code that follows this basic format.

    task main()
    {
        while( true ) {
            motor[ port2 ] = vexRT[ ch2 ];
        }
    }

    Now this is not incorrect code, however, if we examine what is happening, the value of joystick channel 2 is constantly being written to the array motor which is controlling the motor speed. A quick test shows this loop can run at least 80000 times in one second taking valuable time from other tasks. An improvement is to add a delay at the end of the loop such as wait1Msec( 10 ) which would put the task into a waiting state for 10mS, the question is what the optimum value for this delay. To try and determine this a little background information in the internal workings of the cortex needs to be considered.

    The cortex contains two microcontrollers. The first is an NXP LPC2458, this handles the USB communication (including VEXnet WiFI) and motor control. This processor runs the VEX master code which is currently at version 3.16, this same code is running for both the EasyC and RobotC development environments. The second microcontroller is an STM32F103VDH6 from STMicroelectronics which uses an ARM 32-bit Cortex-M3 core, this is presumably where the cortex gets it’s name from. The user code we write runs on this microcontroller, in the case of RobotC the virtual machine firmware is first loaded followed by the small user programs. The STM32 controls the digital and analog IO, the UARTs and (perhaps, although not proven either way) the I2C interface when it arrives. The two microcontrollers have at least two paths of communication between them. The first path is an asynchronous serial interface, this is used to transfer the firmware and is probably the path used for RobotC debugging. The second path is an SPI interface and is used to communicate the joystick positions and motor speeds between the two processors (as I said before, this is a complete guess but seems reasonable). The SPI communication takes place every 15mS as far as I can tell without more detailed investigation.

    The second piece of background information to be considered is the way in which motor ports 2 through 9 interface to the motors (ports 1 and 10 use an H-Bridge to directly control the motors). This interface is the well known RC pulse width modulation control where a pulse that is nominally 1.5mS in length is sent approximately every 20mS. In the cortex the PWM pulse is sent every 18mS (although it drops to every 8mS in some modes as of V2.81 firmware) and varies in length from 1mS for full reverse speed to 2mS for full forward speed.

    So what happens when we write the line of code?

    motor[ port2 ] = 127;

    First of all the value 127 is written into an internal variable holding the speed for the motor connected to port2. Next, at some point in the future, the SPI communications task sends the speed for the motor to the LPC2458 microcontroller. Finally the LPC2458 converts this speed value into the pulse length that represents it (in the case of 127 it would be 2mS).

    To see this happening in practice, some test code was written to monitor where the SPI messages were being sent and allow this to be captured on an oscilloscope along with the motor PWM signal and a trigger showing when a new motor speed was requested. The following screen shot shows a worse case condition where there is a large delay between requesting a new motor position and the next SPI message, and also a delay between the SPI message and the next PWM pulse being sent to the motor. It can be seen that there is a 28mS delay from request to motor control.

    motor_ctl_long_delay.jpg

    The next screen shot show a much more favorable situation where there is little delay between request, SPI message and PWM pulse. Although this is not the theoretical best case the delay has dropped to around 6.5mS.

    motor_ctl_short_delay.jpg

    Based on this information I leave it to the reader to determine a reasonable update rate for motors.

    Test code used

    #pragma config(Sensor, dgtl1,  out1,                sensorDigitalOut)
    #pragma config(Sensor, dgtl4,  out2,                sensorDigitalOut)
    #pragma config(Motor,  port2,           motorA,        tmotorNormal, openLoop)
    //*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//
    
    // task to monitor SPI message count and toggle io line
    // for each message
    task task1()
    {
        int oldspi, newspi;
        
        while( true )
            {
            // digi out low
            SensorValue[ out2 ] = 0;
    
            // did we send/receive another message to the motor controller
            newspi = nIfiSPIMsgCounts;
            if( oldspi != newspi )
                SensorValue[ out2 ] = 1;    
    
            // note for next time arount
            oldspi = newspi;
            
            // next task
            EndTimeSlice();            
            }
    }
    
    task main()
    {
        StartTask( task1 );
        
        while( true )
            {
            // motor full forward
            SensorValue[ out1 ] = 1;
            motor[ motorA ] = 127;
            wait1Msec( 50 );
        
            // motor full reverse
            SensorValue[ out1 ] = 0;
            motor[ motorA ] = -127;
            wait1Msec( 50 );
            }
    }
 

or Sign Up to reply!