Active Velocity Control

Hello

Using ACP10 motion control platform I want to control the velocity of an axis on the fly based on another input in the PLC. I can use either absolute or additive moves as long as I am able to adjust the velocity during its path. Please suggest with code examples. Thanks

Hi Mirza @c576210

I think your question may require a bit more detail for the proper answer.
You are saying you want to control the velocity of an axis but you can only use absolute or additive moves?

If you are just trying to control the velocity of an axis the function block MC_BR_MoveCyclicVelocity would be the way to go help GUID 2d57d9a8-a86f-4a8f-a095-0d9ee093ae1d.

If the axis needs to reach a certain position and you need to modify the velocity while it’s moving to its target position you can use the regular MC_MoveAbsolute and keep changing the Velocity input and trigger the Execute input. This will update the instructions for the axis but depending on the frequency of the changes leads to a lot of network traffic and could potentially fail if the frequency is too high.
The MC_MoveAdditive works the same way but it would restart the positioning to the target position every time you trigger Execute.

So maybe you can provide a bit more detail about the application and we can help find the best solution!

1 Like

I am just trying to control the velocity of an axis. I was trying MC_MoveAbsolute. I do keep triggering the MC_MoveVelocity.execute input but it doesn’t make a difference, the velocity stays at what it started at. Is changing the velocity once every couple of seconds too often for this mode? Or maybe I was supposed to keep triggering the MC_MoveABsolute??


I just tried triggering MC_MoveAbsolute.Execute and it didn’t work

I will look in to MC_BR_MoveCyclicVelocity but I hope I can keep it simple

How do I use
GUID 2d57d9a8-a86f-4a8f-a095-0d9ee093ae1d. for this?

A GUID is a help page ID in the offline help. Just press the key combination Ctrl + G in the Help Explorer and then enter the GUID code. This will then jump to the help page.

You can also find the information in the new online help.
https://help.br-automation.com/#/en/4/libraries%2Facp10_mc%2Falphabetische_ubersicht%2Fmc_br_movecyclicvelocity%2Fmc_br_movecyclicvelocity.html

2 Likes

I tried MC_BR_MoveCyclicVelocity as follows and it is not working, I get an error 29206 : The controller is OFF. Please show me what I am doing wrong

fbAxis1MoveCycVel(Axis := ADR(gAxis1), Enable := TRUE, CyclicVelocity := 500);

IF ConditionA THEN
fbAxis1MoveCycVel(Axis := ADR(gAxis1), Enable := TRUE, CyclicVelocity := 1200);
ELSE
fbAxis1MoveCycVel(Axis := ADR(gAxis1), Enable := TRUE, CyclicVelocity := 500);
END_IF;

Hi Mirza,

The MoveCyclicVelocity function block allows you to adjust the velocity of a moving axis cyclically. While it is moving, you can send a new velocity to the drive every PLC cycle and the drive will update the velocity of the motor immediately. This contrasts with a simple MoveVelocity command which is just a one-off command telling the drive to spin the motor until told otherwise. However, all this command does is move the drive. In order to use it, the drive must be powered on and referenced (homed).

The mappMotion Getting Started guide shows you how to use a function block called MpAxisBasic. There is a version of this function block available for ACP10 as well. This function block allows you to power an axis, home it, and the initiate basic movements all-in-one. Since it seems like you’re new to motion control with B&R I recommend adding this block to a project so that you can become familiar with the available commands/parameters/statuses and get your motor moving.

In order to use the MoveCyclicVelocity function block, you’ll have to first power on and home your axis. This can be accomplished with MpAxisBasic, or it can be done with independent PLCopen function blocks (MC_Power and MC_Home). If you want to see a sample program using PLCopen function blocks, open your project and click inside the Logical View. Your Toolbox will then show software-related items. Find Library Samples in the Toolbox and add it to your Logical View. This will allow you to choose various available sample programs. Expand the Motion folder and then the Single Axis folder. You should see three samples available. One in C, one in Structured Text (ST) and one in Ladder (LD). Double click on one of them to add it to your project. These samples do not contain MoveCyclicVelocity, but you can add that function to the program and use it in place of the MoveVelocity function block.

Marcus, Thanks for your followup.

The Power and Homing is already taken care of, the axes are homing and otherwise running fine. It is just the part that I am asking about is not working. The code below is not making a difference in the velocity and it is giving the error 29206: The controller is OFF. If I pulse the Enable signal to force it the PLC is crashing.

fbAxis1MoveCycVel(Axis := ADR(gAxis1), Enable := TRUE, CyclicVelocity := 500);

IF ConditionA THEN
fbAxis1MoveCycVel(Axis := ADR(gAxis1), Enable := TRUE, CyclicVelocity := 1200);
ELSE
fbAxis1MoveCycVel(Axis := ADR(gAxis1), Enable := TRUE, CyclicVelocity := 500);
END_IF;

P.S. I already had the sample library downloaded. It DOESN’T have a sample code for MoveCyclic.

I think you’re probably having issues because that code always calls MoveCyclicVelocity with the Enable set True, even if the axis is powered off. Additionally, you’re calling the function block twice every cycle (once before the IF statement and once during either the IF or ELSE condition). Try something like this instead:

fbAxis1MoveCycVel.Axis := ADR(gAxis1);
fbAxis1MoveCycVel.Direction := mcPOSITIVE_DIR; 
fbAxis1MoveCycVel.Acceleration := 200.0;
fbAxis1MoveCycVel.Deceleration := 200.0;

IF ConditionA THEN
    fbAxis1MoveCycVel.CyclicVelocity := 1200;
ELSE
    fbAxis1MoveCycVel.CyclicVelocity := 500;
END_IF;

fbAxis1MoveCycVel();

This ensures that the function block is only called once per cycle. Additionally, you can use the Watch Window to set the Enable input after the axis is powered on and homed.

It’s a good idea to use a State Machine with your motion control to ensure that nothing is set before you want it to be set. That motion sample does not contain MoveCyclicVelocity, but it does contain the structure you should use when creating your program. If you replace the MoveVelocity block in that program with a MoveCyclicVelocity block, and update all of the related code/parameters, your program will step through each discrete state and trigger the movement only when the axis is ready for movement.

Thanks again. It still gives me the same 29206 error and velocity stays constant.

Forgive me if I’m asking a dumb question, but what’s the status of the axis itself?

29206 implies the axis is not actually powered on B&R Online Help (br-automation.com)

Have you called an MC_Power command yet? From your comments it looks as if that’s the case but that error number is pretty specific to that root cause hence my asking. Perhaps you could share a section of your code for reference?

Thanks Marcus, Patrick, Marcel and Connor

I realized now that the MoveAbsolute and MoveCyclicVelocity are exclusive to each other and Move Absolute takes precedence. I was trying to reach an absolute position but with variable velocity, I guess I cannot so I will have to manage the last leg of the travel with MoveAbsolute.

That makes sense. You can’t use multiple move commands at the same time. If you want to share more about the application, we may be able to suggest a cleaner solution. If you’d prefer not to post that here, you can also reach out to your local B&R office or distribution partner to see if an Application Engineer would be able to help you.

If you want to change the Velocity while an “MoveAbsolute” is acitve, you can override the active movement with an new one with different Parameters. If you want to do it without delay you need two “MoveAbsolute” Instances “MoveAbsolute0” and “MoveAbsolute1”, this behaviour is descriped in AS-Help GUID c9729b12-dab4-48d9-9107-7a88ec4e43b1 ( see Picture at the Bottom of Post). How ever you can also do this with one Instance of “MoveAbsolute” but in this case we lose 1 SPS Cycle as we have to reset the Execute-Flag one cycle to genereate a new positive Edege on the Functionblock.

See Code Example below, in Steps 30…41 the Axis is moved between two Positions 0 and 200.
While the move is active you can change the Velocity “SetVelocity” and the axis will change the Speed with the given Acceleration and Deceleration.

VAR
	MC_Home_0 : MC_Home;
	MC_Power_0 : MC_Power;
	MC_MoveAbsolute_0 : MC_MoveAbsolute;
	SetVelocity : REAL;
	Step : INT;
	Power : BOOL;
END_VAR




PROGRAM _INIT
	(* Insert code here *)
	 
	
	SetVelocity := 10.0; 
	
END_PROGRAM

PROGRAM _CYCLIC

	CASE Step OF 
		
		0: 
			IF Power THEN
				Step := 10; 
			END_IF
			
		10: 
			MC_Power_0.Enable := 1; 
			Step := 11; 
			
		11: 
			IF MC_Power_0.Status = 1 THEN 
				Step := 20;
			END_IF 
				
			
		20: 
			MC_Home_0.HomingMode 	:= mcHOME_DIRECT;
			MC_Home_0.Execute 		:= 1; 
			Step := 21; 
			
		21: 
			IF MC_Home_0.Done = 1 THEN 
				MC_Home_0.Execute 		:= 0; 				
				Step := 30;
			END_IF 
			
		30: 
			
			MC_MoveAbsolute_0.Position			:= 200.0; 
			MC_MoveAbsolute_0.Direction			:= mcPOSITIVE_DIR; 
			MC_MoveAbsolute_0.Velocity 			:= SetVelocity; 
			MC_MoveAbsolute_0.Acceleration		:= 50.0; 
			MC_MoveAbsolute_0.Deceleration		:= 50.0; 
			MC_MoveAbsolute_0.Execute 			:= 1; 
			Step := 31; 
			
		31: 	
			
			MC_MoveAbsolute_0.Execute 	:= 1; 
			IF MC_MoveAbsolute_0.Velocity <> SetVelocity THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
				MC_MoveAbsolute_0.Velocity 	:= SetVelocity; 
			ELSIF MC_MoveAbsolute_0.Done THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
				Step := 40; 	
			END_IF 	
			
		40: 
			
			MC_MoveAbsolute_0.Position			:= 0.0; 
			MC_MoveAbsolute_0.Direction			:= mcPOSITIVE_DIR; 
			MC_MoveAbsolute_0.Velocity 			:= SetVelocity; 
			MC_MoveAbsolute_0.Acceleration		:= 50.0; 
			MC_MoveAbsolute_0.Deceleration		:= 50.0; 
			MC_MoveAbsolute_0.Execute 			:= 1; 
			Step := 41; 
			
		41: 	
			
			MC_MoveAbsolute_0.Execute 	:= 1; 			
			IF MC_MoveAbsolute_0.Velocity <> SetVelocity THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
				MC_MoveAbsolute_0.Velocity 	:= SetVelocity; 
			ELSIF MC_MoveAbsolute_0.Done THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
				Step := 30; 	
			END_IF
			
			
	END_CASE 		

	MC_Power_0(Axis:= ADR(gAxis01));	
	MC_Home_0(Axis:= ADR(gAxis01));
	MC_MoveAbsolute_0(Axis:= ADR(gAxis01));

	
END_PROGRAM

PROGRAM _EXIT
	(* Insert code here *)
	 
END_PROGRAM


image

Thanks, that is awesome. I will try it

Hi Mirza Baig,

if a Post was helpfull to your question, can you mark it please as a Solution, so other Users can faster get the info which helped you most. And see the whole topic as Solved in the overview.

Example:
[About the Ask Questions category]

Hi @michael.bertsch ,

due to the FUB being Edge-sensitive, the loss of 1 PLC Cycle is not inevitable.
The code can basically set the Execute back to False as soon as the MoveAbsolute-FUB started the execution (which can also be seen as a possibility from the Timing Diagram you added)

Full Step 31

		31: 	
			
			IF MC_MoveAbsolute_0.Busy THEN
				MC_MoveAbsolute_0.Execute 	:= 0;
			END_IF
			IF MC_MoveAbsolute_0.Velocity <> SetVelocity THEN 
				MC_MoveAbsolute_0.Execute 	:= 1;
				MC_MoveAbsolute_0.Velocity 	:= SetVelocity;
			ELSIF MC_MoveAbsolute_0.Done THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
				Step := 40; 	
			END_IF 	
1 Like

Hello @michael_w,

this is a good remark to speed up the reaction. Thanks for this post.

But your code allows in some bad timing, the velocity to not beeing updated. If in the cycle the Movement Starts , the SetVelocity is changed, it will not be used, as the code will not correctly add a new Edge.

Example:

	30: 
			SetVelocity := 10.0; 
			
			MC_MoveAbsolute_0.Position			:= 200.0; 
			MC_MoveAbsolute_0.Direction			:= mcPOSITIVE_DIR; 
			MC_MoveAbsolute_0.Velocity 			:= SetVelocity; 
			MC_MoveAbsolute_0.Acceleration		:= 50.0; 
			MC_MoveAbsolute_0.Deceleration		:= 50.0; 
			MC_MoveAbsolute_0.Execute 			:= 1; 
			Step := 31; 
			
			SetVelocity := 5.0; 
		31: 	
			
			IF MC_MoveAbsolute_0.Busy THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
			END_IF

			IF MC_MoveAbsolute_0.Velocity <> SetVelocity THEN 
				MC_MoveAbsolute_0.Execute 	:= 1; 
				MC_MoveAbsolute_0.Velocity 	:= SetVelocity; 
			ELSIF MC_MoveAbsolute_0.Done THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
				Step := 40; 	
			END_IF

Not much difference but now it will generate a correct edge in any case. There is now mostly no
lose of cycle, only if you hit the Velocity-Change to the one cycle we need to reset the Execute.

	30: 
			SetVelocity := 10.0; 

			MC_MoveAbsolute_0.Position			:= 200.0; 
			MC_MoveAbsolute_0.Direction			:= mcPOSITIVE_DIR; 
			MC_MoveAbsolute_0.Velocity 			:= SetVelocity; 
			MC_MoveAbsolute_0.Acceleration		:= 50.0; 
			MC_MoveAbsolute_0.Deceleration		:= 50.0; 
			MC_MoveAbsolute_0.Execute 			:= 1; 
			Step := 31; 
			
			SetVelocity := 5.0; 
		31: 	
			
			IF MC_MoveAbsolute_0.Busy AND MC_MoveAbsolute_0.Execute = 1 THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
			ELSIF MC_MoveAbsolute_0.Velocity <> SetVelocity THEN 
				MC_MoveAbsolute_0.Execute 	:= 1; 
				MC_MoveAbsolute_0.Velocity 	:= SetVelocity; 
			ELSIF MC_MoveAbsolute_0.Done THEN 
				MC_MoveAbsolute_0.Execute 	:= 0; 
				Step := 40; 	
			END_IF
1 Like

Hello @michael.bertsch,
I’m also working on something simular where I want to connect setVelocity to an analog potenciometer to control the speed of servo. I have an old code from 2010 B&R engineer which I am customizing and want to ask you if this is the right way and if it’s gonna work.

(********************* START VELOCITY MOVEMENT ********************)
STATE_MOVE_VELOCITY: (
STATE: Start velocity movement )
MC_MoveVelocity_0.Velocity := Axis[AXIS_INDEX].Parameter.Velocity;
MC_MoveVelocity_0.Acceleration := Axis[AXIS_INDEX].Parameter.Acceleration;
MC_MoveVelocity_0.Deceleration := Axis[AXIS_INDEX].Parameter.Deceleration;
MC_MoveVelocity_0.Direction := Axis[AXIS_INDEX].Parameter.Direction;
MC_MoveVelocity_0.Execute := 1;
(
change of speed on go )
IF MC_MoveVelocity_0.Velocity <> Axis[AXIS_INDEX].Parameter.Velocity THEN
MC_MoveVelocity_0.Execute := 0;

MC_MoveVelocity_0.Velocity := Axis[AXIS_INDEX].Parameter.Velocity;
END_IF;
(
end
)

    IF (Axis[AXIS_INDEX].Command.Halt = TRUE) THEN
        Axis[AXIS_INDEX].Command.Halt := FALSE;
        MC_MoveVelocity_0.Execute := FALSE;
        AxisStep := STATE_HALT;
    ELSIF (MC_MoveVelocity_0.InVelocity = TRUE) THEN
        MC_MoveVelocity_0.Execute := FALSE;
         AxisStep := STATE_READY;
    END_IF
    (* check if error occured *)
    IF ((MC_MoveVelocity_0.Error = TRUE) OR (MC_MoveVelocity_0.CommandAborted = TRUE)) THEN
        MC_MoveVelocity_0.Execute := FALSE;
        AxisStep := STATE_READY;
    END_IF

Hello,
The upper example with MC_MoveAbsolute can be easily replaced with MC_MoveVelocity, they have the same behaviour in updating the Parameters.

As far as i remember, but can’t currently check is that the InVelocity might not be set if you combine it with an Override <> 100%. If this is an possibility in your application you should check this testcase.

But as you want to cyclicaly update the velocity you should not jump out of this step with InVelocity. You only jump out of it if you want to halt.

But if its only the Velocity you need, no Position. And to have a cyclical Update of the Velocity due to the potentiometer. I would recomend to use MC_BR_MoveCyclicVelocity and stay in the State as long as the coupling shall be active. Then you don’t need the new Edges and the Communication to the acopos is prepared for continous Value changes.

Greetings
Michael

1 Like