[Parameter Adjustment Magic] PID Parameter Adjustment Using VOFA+Upper Unit (with lower unit code)

Time:2024-4-23

1. What is VOFA+?

Simply speaking, VOFA+ is a super serial assistant, in addition to realize the serial data sending and receiving of the general serial assistant, it can also realize the data plotting (including histogram, FFT chart), control editing, image display and other functions. Using VOFA+, it can bring convenience to our usual debugging such as PID parameterization, and also can make its own upper computer that meets its own requirements, which brings convenience to embedded development.

This is the official website of VOFA+VOFA+ | VOFA+

2. How to use VOFA+ to debug PIDs

2.1 VOFA+ component

Before you officially start using VOFA+, it’s a good idea to spend ten minutes or so putting theDocumentation on the official websiteRead through it and familiarize yourself with the basics.

If you just want to use VOFA+ to plot data, you can just use a waveform control, but if you want to use VOFA+ as a long term parameterization assistant, you’d better set up the control. Below is the control I set up for debugging the speed and position loops of a DC motor. It consists of a waveform, six parameter adjustment boxes, and two target value adjustment boxes.

[Parameter Adjustment Magic] PID Parameter Adjustment Using VOFA+Upper Unit (with lower unit code)

After setting up the control we need to write a command for the parameterization control, here is an example using P for the speed ring. Come to the command interface, add a new command and rename it Spe_P, send it as P2=%.2f!, where %.2f will be replaced by the value in the control in the actual send (see the official website for details), and the exclamation mark is my customized command terminator.

[Parameter Adjustment Magic] PID Parameter Adjustment Using VOFA+Upper Unit (with lower unit code)

Then just bind the command to the control

[Parameter Adjustment Magic] PID Parameter Adjustment Using VOFA+Upper Unit (with lower unit code)

This allows you to send the appropriate command each time you move the control

[Parameter Adjustment Magic] PID Parameter Adjustment Using VOFA+Upper Unit (with lower unit code)

Repeat the above steps to set up all the commands and then the VOFA+ part is complete. I have also adjusted the maximum and minimum value of the parameter control, the number of decimal places, the step value and the send after the mouse pops up instead of while moving, etc., you can adjust according to your own needs!

[Parameter Adjustment Magic] PID Parameter Adjustment Using VOFA+Upper Unit (with lower unit code)

Remember to save the controls and commands when you’re done editing, or the software will get stuck and all that stuff will be gone!

[Parameter Adjustment Magic] PID Parameter Adjustment Using VOFA+Upper Unit (with lower unit code)

2.2 STM32 section

On the STM32 side, we have to parse the data sent by the VOFA+ host computer and assign its data to the appropriate variables.

I’m using a serial interrupt for reception here, but of course you can also use DMA for reception.

First we have to set up the serial port on the CubeMax and turn on the serial interrupt, then turn on the serial interrupt before the while of main

uint8_t RxBuffer[1];//serial port receive buffer
uint16_t RxLine = 0;//instruction length
uint8_t DataBuff[200];//instruction content

HAL_UART_Receive_IT(&huart2,(uint8_t *)RxBuffer,1);//Enable serial port interrupt, I use serial port2

The next step is to write the serial port interrupt function

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
    if(UartHandle->Instance==USART2)//If it is serial port 2
    {
        RxLine++; //For each data received, enter callback data length plus 1
        DataBuff[RxLine-1]=RxBuffer[0]; // save each received data to the cache array
        if(RxBuffer[0]==0x21) //Receive the end flag bit, this data can be customized, according to the actual needs, here is only for example use, not necessarily 0x21
        {
            printf("RXLen=%d\r\n",RxLine);
            for(int i=0;i<RxLine;i++)
                printf("UART DataBuff[%d] = %c\r\n",i,DataBuff[i]);
            USART_PID_Adjust(1);//Data parsing and parameter assignment function
            memset(DataBuff,0,sizeof(DataBuff)); // clear the cache array
            RxLine=0; //clear receive length
        }
        RxBuffer[0]=0;
        HAL_UART_Receive_IT(&huart2, (uint8_t *)RxBuffer, 1); //Every time you receive a data, turn on the serial port interrupt to receive, otherwise you will only receive one data and stop receiving.
    }
}

Here is a note, we set in VOFA+ to send as ASCII code, so if an exclamation mark “!” is sent, then the STM32 will receive the ASCII code of the exclamation mark. , what the STM32 receives will be the ASCII code of the exclamation mark, which is 0x21 in hexadecimal. if the number 0 is sent, then the received data is 48 in decimal and 0x72 in hexadecimal.

Next, we have to extract the data from the instruction

/*
 * :: Parsing out the data in the DataBuff
 * :: Returning parsed data
 */
float Get_Data(void)
{
    uint8_t data_Start_Num = 0; // Record where the data bits begin
    uint8_t data_End_Num = 0; // Record where the data bits end
    uint8_t data_Num = 0; // record the number of data bits
    uint8_t minus_Flag = 0; // Determine if the number is negative.
    float data_return = 0; // Parse the returned data
    for(uint8_t i=0;i<200;i++) // find the position of the equal sign and exclamation point
    {
        if(DataBuff[i] == '=') data_Start_Num = i + 1; // the +1 is positioned directly to the data start bit
        if(DataBuff[i] == '!')
        {
            data_End_Num = i - 1;
            break;
        }
    }
    if(DataBuff[data_Start_Num] == '-') // if negative
    {
        data_Start_Num += 1; // shift back one bit to data bit
        minus_Flag = 1; // Negative number flag
    }
    data_Num = data_End_Num - data_Start_Num + 1;
    if(data_Num == 4) // data total 4 bits
    {
        data_return = (DataBuff[data_Start_Num]-48)  + (DataBuff[data_Start_Num+2]-48)*0.1f +
                (DataBuff[data_Start_Num+3]-48)*0.01f;
    }
    else if(data_Num == 5) // 5 bits of data
    {
        data_return = (DataBuff[data_Start_Num]-48)*10 + (DataBuff[data_Start_Num+1]-48) + (DataBuff[data_Start_Num+3]-48)*0.1f +
                (DataBuff[data_Start_Num+4]-48)*0.01f;
    }
    else if(data_Num == 6) // 6 bits of data
    {
        data_return = (DataBuff[data_Start_Num]-48)*100 + (DataBuff[data_Start_Num+1]-48)*10 + (DataBuff[data_Start_Num+2]-48) +
                (DataBuff[data_Start_Num+4]-48)*0.1f + (DataBuff[data_Start_Num+5]-48)*0.01f;
    }
    if(minus_Flag == 1)  data_return = -data_return;
//    printf("data=%.2f\r\n",data_return);
    return data_return;
}

Finally, assign the parsed value to the PID parameter variable.

/*
 * :: PID parameterization based on serial port information
 */
void USART_PID_Adjust(uint8_t Motor_n)
{
    float data_Get = Get_Data(); // store received data
//    printf("data=%.2f\r\n",data_Get);
    if(Motor_n == 1)//left motor
    {
        if(DataBuff[0]=='P' &&DataBuff [1]=='1') // Position loop P
            pid_l_position.kp = data_Get;
        Else if (DataBuff [0] = = 'I' && DataBuff [1] = = '1') // position loop I
            pid_l_position.ki = data_Get;
        Else if (DataBuff [0] = = 'D' && DataBuff [1] = = '1') // position loop D
            pid_l_position.kd = data_Get;
        Else if (DataBuff [0] = = 'P' && DataBuff [1] = = '2') // speed ring P
            pid_l_speed.kp = data_Get;
        Else if (DataBuff [0] = = 'I' && DataBuff [1] = = '2') // speed ring I
            pid_l_speed.ki = data_Get;
        Else if (DataBuff [0] = = 'D' && DataBuff [1] = = '2') // D speed ring
            pid_l_speed.kd = data_Get;
        Else if ((DataBuff [0] = = 'S' && DataBuff [1] = = 'p') && DataBuff [2] = = 'e') // target speed
            L_Target_Speed = data_Get;
        else if((DataBuff[0]=='P' && DataBuff[1]=='o') && DataBuff[2]=='s') //Target position
            L_Target_Position = data_Get;
    }
    else if(Motor_n == 0) // right motor
    {
        if(DataBuff[0]=='P' &&DataBuff [1]=='1') // Position loop P
            pid_r_position.kp = data_Get;
        Else if (DataBuff [0] = = 'I' && DataBuff [1] = = '1') // position loop I
            pid_r_position.ki = data_Get;
        Else if (DataBuff [0] = = 'D' && DataBuff [1] = = '1') // position loop D
            pid_r_position.kd = data_Get;
        Else if (DataBuff [0] = = 'P' && DataBuff [1] = = '2') // speed ring P
            pid_r_speed.kp = data_Get;
        Else if (DataBuff [0] = = 'I' && DataBuff [1] = = '2') // speed ring I
            pid_r_speed.ki = data_Get;
        Else if (DataBuff [0] = = 'D' && DataBuff [1] = = '2') // D speed ring
            pid_r_speed.kd = data_Get;
        Else if ((DataBuff [0] = = 'S' && DataBuff [1] = = 'p') && DataBuff [2] = = 'e') // target speed
            R_Target_Speed = data_Get;
        else if((DataBuff[0]=='P' && DataBuff[1]=='o') && DataBuff[2]=='s') //Target position
            R_Target_Position = data_Get;
    }
}

Here, the serial port debugging part is all done, the PID part and the timer part will not be repeated.

2.2 Commencement of parameterization

After the code is written, open the serial port, you can adjust the PID parameters and the target speed of the motor in real time, when the PID adjustment is completed and then write the parameters into the code.

It is important to note that the data must be sent in strict accordance with the format of the data engine, otherwise the software will not be able to parse the data for drawing. If you want to check the format, just move the mouse to the black question mark on the data engine.

[Parameter Adjustment Magic] PID Parameter Adjustment Using VOFA+Upper Unit (with lower unit code)

This is much more enjoyable than the original process of looking at waveforms → changing parameters → burning code → looking at waveforms

If you plug in a Bluetooth module in the car and the computer respectively, you can realize the car running while tuning, directly transformed into a remote remote control car, it’s fun.

3. Other

VOFA + simple to use, but a little too simple, part of the experience is not very good (such as can not adjust the size of the control, save the file is not very convenient, etc.), so if you have the ability to learn, we recommend that you write your own QT/PyQT on the machine.

Recommended Today

[Unity] Download and Installation

Download the Unity Hub Installer Method 1 Go to the official website download page Unity Hub It is a must install software to use Unity, this software helps us to manage Unity software version and Unity project. Enter the URL in your browserunity.com/cn/download Go to the download page. Then clickDownload for Windows① maybeDownload other versions②, […]