cancel
Showing results for 
Search instead for 
Did you mean: 

EVAL-KIT-ROBOT-1

DBrag.1
Associate II

Hi,

i would like use the speed mode FW with modbus, it is possible? For to do this i should change the source code or i can put the parameter (rpm) in a specific register?

@Enrico Poli​ 

1 ACCEPTED SOLUTION

Accepted Solutions
Enrico Poli
ST Employee

Hi @DBrag.1​ 

For obtaining this operation mode you need to follow few steps:

  1. Open the MCWB project provided with the source code (STSW-ROBOT-1) and configure the speed control algorithm instead of the positioning
  2. Click on the "generate" button
  3. Select "Update" targeting you preferred IDE and selecting LL library
  4. At the end of code-generation process, open the IDE project file
  5. In the stm32f0xx_mc_it.c file, replace the automatically generated EXTI0_1_IRQHandler function with the custom one available in the USER CODE 1 section. (in between /* USER CODE BEGIN 1 */ and /* USER CODE END 1 */ lines)

This is more or less the same procedure described in the User Manual of the software for software customization.

Now you need to map somehow the MODBUS API with the MotorControl API. This is performed in two files:

  • mb_api.c: it maps holding registers, coils and direct inputs with specific commands (e.g. getting the target position from the holding registers)
  • main.c: in the infinite loop the state machine manages the command's execution

In the mb_api.c you could add the following functions converting holding registers' content into parameters for the speed command:

// Read target speed (rpm) from Holding Reg #0
int16_t getFinalSpeed()
{
  return (int16_t)usRegHoldingBuf[0];
}
 
//Read speed ramp duration (ms) from Holding Reg #2
uint16_t getRampDuration_ms()
{
  return usRegHoldingBuf[2];
}

In the main.c you should remove the code managing the position initialization:

  setZeroReached(0); // Slave indicate that the alignment is not completed
    
  LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-on LED
  MC_StartMotor1();
  while(MC_GetAlignmentStatusMotor1() != TC_ALIGNMENT_COMPLETED) 
  {
    if (MC_GetOccurredFaultsMotor1() != 0)
    {
      MC_AcknowledgeFaultMotor1();
      LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-off LED
      HAL_Delay(500);
      MC_StartMotor1();
      LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-on LED
      HAL_Delay(500);
    }
  } //  PAUSE THE MAIN LOOP UNTIL THE ENCODER IS ALIGNED
  
  HAL_Delay(100);
  setZeroReached(1);
  
  LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-off LED

and modify the state machine as following:

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
    if (MC_GetOccurredFaultsMotor1() != 0)
    {
      LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-on LED
      setMovementCompleted(1); // Slave indicate that the movement is aborted
      clearCommand();
      MC_AcknowledgeFaultMotor1();
      comState = idle;
    }
    else
    {
      LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-off LED
    }
    
    switch (comState) {
    case idle:
      {
        if(getNewCommand()) // If new command arrived
        {
          int16_t speed = getFinalSpeed();
          if (speed == 0)
          {
            MC_StopMotor1();
          }
          else
          {
            MC_ProgramSpeedRampMotor1( speed, getRampDuration_ms() );
            MC_StartMotor1();
          }
          comState = commandExecuted;
        }
      }
      break;
      
    case commandReceived:
      {
        if (isMovementComplete()) // If the movement has been completed
        {
          setMovementCompleted(1); // Slave indicate that the movement is completed
          comState = commandExecuted;
        }
      }
      break;
      
    case commandExecuted:
      {
        clearCommand();
        comState = idle;
      }
      break;
      
    }
 
/* ---------------------- DEMO ----------------------- */
//    if (isMovementComplete())
//    {
//      if (fTargetPos == 0)
//      {
//        fTargetPos = ((float)(3*360) * (float)(M_PI)) / 180.0f;
//      }
//      else
//      {
//        fTargetPos = 0;
//      }
//      MC_ProgramPositionCommandMotor1(fTargetPos, 1);
//    }
/* --------------------------------------------------- */
    
  }
  /* USER CODE END 3 */
}

This is just an example. You can play with the MODBUS API and state machine in different ways in order to find the solution fitting your needs.

View solution in original post

2 REPLIES 2
Enrico Poli
ST Employee

Hi @DBrag.1​ 

For obtaining this operation mode you need to follow few steps:

  1. Open the MCWB project provided with the source code (STSW-ROBOT-1) and configure the speed control algorithm instead of the positioning
  2. Click on the "generate" button
  3. Select "Update" targeting you preferred IDE and selecting LL library
  4. At the end of code-generation process, open the IDE project file
  5. In the stm32f0xx_mc_it.c file, replace the automatically generated EXTI0_1_IRQHandler function with the custom one available in the USER CODE 1 section. (in between /* USER CODE BEGIN 1 */ and /* USER CODE END 1 */ lines)

This is more or less the same procedure described in the User Manual of the software for software customization.

Now you need to map somehow the MODBUS API with the MotorControl API. This is performed in two files:

  • mb_api.c: it maps holding registers, coils and direct inputs with specific commands (e.g. getting the target position from the holding registers)
  • main.c: in the infinite loop the state machine manages the command's execution

In the mb_api.c you could add the following functions converting holding registers' content into parameters for the speed command:

// Read target speed (rpm) from Holding Reg #0
int16_t getFinalSpeed()
{
  return (int16_t)usRegHoldingBuf[0];
}
 
//Read speed ramp duration (ms) from Holding Reg #2
uint16_t getRampDuration_ms()
{
  return usRegHoldingBuf[2];
}

In the main.c you should remove the code managing the position initialization:

  setZeroReached(0); // Slave indicate that the alignment is not completed
    
  LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-on LED
  MC_StartMotor1();
  while(MC_GetAlignmentStatusMotor1() != TC_ALIGNMENT_COMPLETED) 
  {
    if (MC_GetOccurredFaultsMotor1() != 0)
    {
      MC_AcknowledgeFaultMotor1();
      LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-off LED
      HAL_Delay(500);
      MC_StartMotor1();
      LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-on LED
      HAL_Delay(500);
    }
  } //  PAUSE THE MAIN LOOP UNTIL THE ENCODER IS ALIGNED
  
  HAL_Delay(100);
  setZeroReached(1);
  
  LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-off LED

and modify the state machine as following:

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
    if (MC_GetOccurredFaultsMotor1() != 0)
    {
      LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-on LED
      setMovementCompleted(1); // Slave indicate that the movement is aborted
      clearCommand();
      MC_AcknowledgeFaultMotor1();
      comState = idle;
    }
    else
    {
      LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin); // Turn-off LED
    }
    
    switch (comState) {
    case idle:
      {
        if(getNewCommand()) // If new command arrived
        {
          int16_t speed = getFinalSpeed();
          if (speed == 0)
          {
            MC_StopMotor1();
          }
          else
          {
            MC_ProgramSpeedRampMotor1( speed, getRampDuration_ms() );
            MC_StartMotor1();
          }
          comState = commandExecuted;
        }
      }
      break;
      
    case commandReceived:
      {
        if (isMovementComplete()) // If the movement has been completed
        {
          setMovementCompleted(1); // Slave indicate that the movement is completed
          comState = commandExecuted;
        }
      }
      break;
      
    case commandExecuted:
      {
        clearCommand();
        comState = idle;
      }
      break;
      
    }
 
/* ---------------------- DEMO ----------------------- */
//    if (isMovementComplete())
//    {
//      if (fTargetPos == 0)
//      {
//        fTargetPos = ((float)(3*360) * (float)(M_PI)) / 180.0f;
//      }
//      else
//      {
//        fTargetPos = 0;
//      }
//      MC_ProgramPositionCommandMotor1(fTargetPos, 1);
//    }
/* --------------------------------------------------- */
    
  }
  /* USER CODE END 3 */
}

This is just an example. You can play with the MODBUS API and state machine in different ways in order to find the solution fitting your needs.

CPutt.1
Associate III

Hello,

Thanks for the help.

I have configured Speed Control Successfully.

I have a doubt, I am unable to achieve continous rotation for lower speed using speed control.

For example, the motor works continously for the Minimum speed of 1.5 Hz which is too fast for my application.

If the speed is less than 1.5 Hz(90 RPM), the motor achieves speed by delaying its rotation. I wanted to achieve continous rotation for lesser speed.

Is there a Controller setting to be changed to achieve minimum RPM like maximum RPM?

Regards,

Chandan