Difference between revisions of "MC-Basic Programs"

From SoftMC-Wiki
Jump to: navigation, search
 
(BackToTop button)
 
(33 intermediate revisions by 3 users not shown)
Line 1: Line 1:
A project is all the software written for an application. The projects in MC-BASIC are multi-tasking. They consist of many tasks running concurrently with, and independently of, each other. The project is stored in multiple files, one file for each task. Tasks are routines that run simultaneously with many other tasks. Projects also include other files such as cam tables and record files. Projects are controlled from the BASIC Moves (BMDS) software. BMDS automatically sets up a separate directory for each project. For detailed information on any commands listed within this section, refer to the <sup>''®</sup> MC Reference Manual.''
+
{{Out-of-date}}
 +
<div id="BackToTop"  class="noprint" style="background-color:; position:fixed; bottom:32px; left:95%; z-index:9999; padding:0; margin:0;">
 +
<span style="color:blue; font-size:8pt; font-face:verdana,sans-serif; border:0.2em outset:#ceebf7; padding:0.1em; font-weight:bolder; -moz-border-radius:8px; ">
 +
[[Image:TOP2.png|50px|link=#top]] </span></div>
  
For clarity, a project is managed by BMDS and conveniently handles a group of logically coupled files (programs, CAM tables, etc.), while the MC deals with separate files (PRG, CAM, etc.). The Motion controller does not keep project files in the Flash and it is not aware of logical coupling of files and programs.
+
= Introduction =
 +
A project is all the software written for an application. The projects in MC-Basic are multitasking. They consist of many tasks running concurrently and independently of each other. The project is stored in multiple files, one file for each task. Tasks are routines that run simultaneously with many other tasks. Projects also include other files such as cam tables and record files. Projects are controlled from the ControlStudio software.
 +
<!-- For detailed information on any commands listed within this section, refer to the Reference Manual. -->
  
= Project Structure =
+
ControlStudio manages projects and handles a group of logically coupled files (programs, cam tables, etc.), while the softMC deals with separate files (PRG, CAM, etc.). The softMC does not keep project files in the flash memory and is not aware of logical coupling of files and programs.
Project files include tasks and cam tables. Each project can contain three types of tasks:
 
  
'''General-purpose task'''
+
ControlStudio automatically sets up a separate directory for each project.
  
An '''optional configuration task''' (Config.Prg) to declare groups, programmable limit switches (PLS), cams, global variables and load of global libraries.
+
= Project Structure =
 +
Project files include tasks and cam tables.  
  
An '''optional autoexec task''' (Autoexec.Prg) to automatically start the application on power-up.
+
Each project can contain three types of tasks:
 +
*'''General-purpose task'''
 +
*An '''optional configuration task''' (Config.Prg) to declare groups, programmable limit switches (PLS), cams, global variables and load of global libraries.
 +
*An '''optional autoexec task''' (Autoexec.Prg) to automatically start the application on power-up.
  
[[Image:Axystems;UserManual-31ProjectStructure.png|caption|600px]]
+
[[Image:Axystems;UserManual-31ProjectStructure.png|caption|400px]]
  
 
= Tasks =
 
= Tasks =
Line 18: Line 26:
  
 
== General Purpose Tasks ==
 
== General Purpose Tasks ==
General-purpose tasks are the work horse of the MC language. They implement the basic logic of your application. The great majority of your programming is implemented with general-purpose tasks. Each general-purpose task is divided into three sections: a task-variable section, a main program, and subroutines. The main program is further divided into three sections: a Start-up section, an OnError section, and an OnEvent section.
+
General-purpose tasks are the workhorse of the softMC language. They implement the basic logic of your application. The great majority of your programming is implemented with general-purpose tasks. Each general-purpose task is divided into three sections: a task-variable section, a main program, and subroutines. The main program is further divided into three sections: a Start-up section, an OnError section, and an OnEvent section.
  
 
[[Image:Axystems;UserManual-321GeneralPurposeTasks.png|caption]]
 
[[Image:Axystems;UserManual-321GeneralPurposeTasks.png|caption]]
Line 39: Line 47:
 
The name of the configuration task is Config.Prg. The configuration task is used for declaration of number of axes, global variables and other constructs, such as cam tables, programmable limit switches (PLS), and group. The key to understanding the configuration task is that all data and constructs shared across tasks must be declared in the configuration task. Refer to the following figure.
 
The name of the configuration task is Config.Prg. The configuration task is used for declaration of number of axes, global variables and other constructs, such as cam tables, programmable limit switches (PLS), and group. The key to understanding the configuration task is that all data and constructs shared across tasks must be declared in the configuration task. Refer to the following figure.
  
[[Image:Axystems;UserManual-322ConfigurationTask.png|caption]]
+
[[Image:Axystems;UserManual-322ConfigurationTask.png|caption|400px]]
  
 
The configuration task can contain a program. Axes can be renamed here.
 
The configuration task can contain a program. Axes can be renamed here.
  
 
== AutoExec Task ==
 
== AutoExec Task ==
The AutoExec task (AutoExec.Prg) is executed once on power up, just after the Configuration Task. Use AutoExec to start power-up logic. For example, you might want to use AutoExec to start a task that sets the outputs to the desired starting values. That way, the outputs are set immediately after the MC boots, usually sooner than the PC.
+
The AutoExec task (AutoExec.Prg) is executed once on power up, just after the Configuration Task. Use AutoExec to start power-up logic. For example, you might want to use AutoExec to start a task that sets the outputs to the desired starting values. That way, the outputs are set immediately after the softMC boots, usually sooner than the PC.
  
 
For safety considerations we do not recommend starting of motion from the AutoExec task. Motion should be started by explicit operator’s request either by I/O or communication link from host PC.
 
For safety considerations we do not recommend starting of motion from the AutoExec task. Motion should be started by explicit operator’s request either by I/O or communication link from host PC.
Line 50: Line 58:
 
Set the AutoExec task to run on power up. To do this, add the keyword Continue'' ''to the Program command. Do not include OnError or OnEvent sections in the AutoExec. Limit the AutoExec task to starting other tasks in the system. Refer to the next figure.
 
Set the AutoExec task to run on power up. To do this, add the keyword Continue'' ''to the Program command. Do not include OnError or OnEvent sections in the AutoExec. Limit the AutoExec task to starting other tasks in the system. Refer to the next figure.
  
[[Image:Axystems;UserManual-323AutoExecTask.png|caption]]
+
[[Image:Axystems;UserManual-323AutoExecTask.png|caption|400px]]
  
 
= Program Declarations =
 
= Program Declarations =
Line 87: Line 95:
 
'''Parentheses are not used in a subroutine if no parameters are passed.'''
 
'''Parentheses are not used in a subroutine if no parameters are passed.'''
  
MC-BASIC automatically checks the type of compliance between the subroutine declaration and the subroutine call. Any type mismatch causes an error during program loading. Automatic casting applies to numeric variables types. For example, suppose MySub is a subroutine that takes a Long parameter. In this case, the following scenario applies:
+
MC-Basic automatically checks the type of compliance between the subroutine declaration and the subroutine call. Any type mismatch causes an error during program loading. Automatic casting applies to numeric variables types. For example, suppose MySub is a subroutine that takes a Long parameter. In this case, the following scenario applies:
 
<pre>
 
<pre>
 
CALL MySub(3.3432)
 
CALL MySub(3.3432)
 
 
'OK: The double value 3.3432 is demoted to the Long value, 3
 
'OK: The double value 3.3432 is demoted to the Long value, 3
 
 
CALL MySub(a)
 
CALL MySub(a)
 
 
'Error: a is a string, there is a type mismatch
 
'Error: a is a string, there is a type mismatch
 
 
Call MySub(3,4)
 
Call MySub(3,4)
 
 
'Error: The number of parameters is not correct
 
'Error: The number of parameters is not correct
 
</pre>
 
</pre>
 +
 
See the Subroutine Example in Appendix A for further details.
 
See the Subroutine Example in Appendix A for further details.
 +
 +
== Subroutines ==
 +
Parameters (either scalar or array) passed to the subroutine are used within the code of the subroutine. The declaration line for the subroutine ('''SUB''<nowiki><name></nowiki>''''') is used to declare names and types of the parameters to pass.
 +
 +
Parameters are passed either by reference or by value (ByVal). The default method is to pass parameters by reference. Whole arrays are passed only by reference. Trying to pass a whole array by value results in a translation error. However, array elements can be passed both by reference and by value. The syntax for a subroutine is:
 +
 +
<nowiki>SUB <</nowiki>''name''<nowiki>> ({<</nowiki>''par_1''<nowiki>>([*])+ as <</nowiki>''type_1''<nowiki>>}…{, <</nowiki>''par_''<nowiki>n>([*])+ as<</nowiki>''type_''n>})
 +
 +
 +
 +
END SUB
 +
 +
<nowiki><</nowiki>''par_l''>: name of array variable
 +
 +
<nowiki><</nowiki>''par_''n>: name of array variable
 +
 +
<nowiki>[*]: dimension of an array without specifying the bounds</nowiki>
 +
 +
<nowiki>+: means one or more [*]</nowiki>
 +
 +
 +
<pre>
 +
SUB<nowiki> CalculateMean(x[*][*] as DOUBLE, TheMean[*] as LONG)</nowiki>
 +
DIM sum as DOUBLE
 +
DIM I as LONG
 +
FOR i = 1 to 100
 +
<nowiki>sum = sum + x[i][1]</nowiki>
 +
NEXT i
 +
<nowiki>TheMean[1] = sum/100</nowiki>
 +
END SUB
 +
 +
SUB PrintMean(ByVal Mean as LONG)
 +
PRINT “Mean Value Is “, Mean
 +
END SUB
 +
CALL CalculateMean(XArray, TheMeanArray) ‘ Pass entire array by reference
 +
CALL<nowiki> PrintMean(TheMeanArray[1]) </nowiki>‘ Pass a single array element by value
 +
</pre>
 +
 +
When a variable is passed by reference (whether the variable is local to the task or global), the address of the variable is passed to the subroutine, which changes the value of the original variable (if the code of the subroutine is written to do this).
 +
 +
When a variable is passed by value (ByVal) a local copy of the value of the variable is passed to the subroutine, and the subroutine cannot change the value of the original variable.
 +
 +
There is no explicit limit on the number of subroutines allowed in a task. All subroutines must be located following the main program and must be contained wholly outside the main program. Subroutines can only be called from within the task where they reside. Subroutines may be recursive (can call itself). Use '''CALL''' to execute a subroutine with the following syntax:
 +
 +
'''CALL'''<nowiki> <subroutine_name>{(<par_1>{, …<par_n>})}</nowiki>
 +
 +
Parentheses are not used in subroutine '''CALL''' if no parameters are passed.
 +
 +
MC-Basic automatically checks the type of compliance between the subroutine declaration and the subroutine call. Any mismatch (in number of parameters or parameters types) causes an error during program loading. Automatic type casting applies only for “by value” long and double parameters.
 +
<pre>
 +
SUB MySub(RefPar as long, byval ValPar as double)
 +
 +
END SUB
 +
CALL MySub(LongVar, “String”) -> type mismatch in second parameter
 +
CALL MySub(LongVar) -> wrong number of parameters
 +
CALL MySub(LongVar, 2) -> a valid type casting for a by-value parameter
 +
CALL MySub(DoubleVar, 2.2) -> invalid type casting for a by-ref parameter
 +
</pre>
 +
 +
== User-Defined Functions ==
 +
MC-Basic allows the definition of user functions to be used in programs in the same manner as using BASIC pre-defined functions. User-defined functions are composed with multiple lines and may be recursive (can call itself). Unlike BASIC system functions, the scope of user-defined functions is limited to the task in which it is defined.
 +
 +
Functions are different from subroutines in one respect. Functions always return a value to the task that called the function. Otherwise, functions and subroutines use the same syntax and follow the same rules of application and behavior.
 +
 +
Because functions return a value, function calls should be treated as expressions. Therefore, function called can be combined within print commands, assignment statements, mathematical operations and conditions of flow control statements. They can also be passed as by-value parameters of system or user-defined functions and subroutines.
 +
<pre>
 +
PRINT<nowiki> <</nowiki>function_name<nowiki>>{(<</nowiki>par_1<nowiki>>{, …<</nowiki>par_n>})}
 +
<nowiki><</nowiki>variable_name<nowiki>> = <</nowiki>function_name<nowiki>>{(<</nowiki>par_1<nowiki>>{, …<</nowiki>par_n>})}
 +
IF<nowiki> <</nowiki>function_name<nowiki>>{(<</nowiki>par_1<nowiki>>{, …<</nowiki>par_n>})} > 10 THEN
 +
? LOG<nowiki>( <</nowiki>function_name<nowiki>>{(<</nowiki>par_1<nowiki>>{, …<</nowiki>par_n>})} )
 +
</pre>
 +
 +
Parentheses are not used in function '''CALL''' if no parameters are passed. Parameters (either scalar or array) passed to the function are used within the code of the function. Declare variable names and types of parameters in the declaration line of the function. Parameters can be passed by reference or by value. The default is by reference.
 +
 +
Arrays can only be passed by reference. Trying to pass a whole array by value results in a translation error. On the other hand, array elements can be passed by reference and by value.
 +
 +
To set up the return value, assign the return value to a virtual local variable with the same name as the function somewhere within the code of the function. This local variable is declared automatically during function declaration and the function uses it to obtain the return value.
 +
 +
There is no explicit limit on the number of functions allowed in a task. All functions must be located following the main program and must be contained wholly outside of the main program.
 +
 +
MC-Basic automatically checks the type of compliance between the function declaration and the function call. Any mismatch (in number of parameters, in parameters and returned value types) causes an error during program loading. Automatic type casting applies only for long and double returned values and “by value” parameters. For example:
 +
<pre>
 +
Function LongReturnFunc(…) As Long
 +
LongReturnFunc = “String” -> type mismatch in returned value
 +
End Function
 +
 +
Function LongReturnFunc(…) As Long
 +
LongReturnFunc = 43.7 -> valid type casting in returned value
 +
End Function
 +
</pre>
 +
 +
A function can be recursive (can call itself). The following example defines a recursive function to calculate the value of ''N'':
 +
<pre>
 +
FUNCTION Factorial (ByVal N As Long) As Double
 +
'By declaring N to be long, this truncates floating point numbers
 +
'to integers
 +
'The function returns a Double value
 +
<nowiki>If N < 3 then </nowiki>'This statement stops the recursion
 +
Factorial = N '0!=0; 1!=1' 2!=2
 +
Else
 +
Factorial=N * Factorial(N-1) 'Recursive statement
 +
End If
 +
END FUNCTION
 +
</pre>
 +
 +
When writing a recursive function, you must have an '''IF''' statement to force the function to return without the recursive call being executed. Otherwise, the function never returns once it is called.
  
 
== Arrays ==
 
== Arrays ==
Line 127: Line 237:
 
<pre>
 
<pre>
 
<nowiki>SUB mean(x[*][*] as DOUBLE, TheMean[*] as LONG)</nowiki>
 
<nowiki>SUB mean(x[*][*] as DOUBLE, TheMean[*] as LONG)</nowiki>
 
 
DIM sum as DOUBLE
 
DIM sum as DOUBLE
 
 
DIM I as LONG
 
DIM I as LONG
 
 
FOR i = 1 to 100
 
FOR i = 1 to 100
 
 
<nowiki>sum = sum + x[i][1]</nowiki>
 
<nowiki>sum = sum + x[i][1]</nowiki>
 
 
NEXT i
 
NEXT i
 
 
<nowiki>TheMean[1] = sum/100</nowiki>
 
<nowiki>TheMean[1] = sum/100</nowiki>
 
 
END SUB
 
END SUB
 
</pre>
 
</pre>
  
= Multi-tasking =
+
= Multitasking =
The MC supports multi-tasking. You can have multiple tasks running independently, sharing a single computer. A task is a section of code that runs in its own context. Microsoft Windows<sup></sup> is a multi-tasking system. If you open Explorer and Word at the same time, they run nearly independently of each another.
+
The softMC supports multitasking. You can have multiple tasks running independently, sharing a single computer. A task is a section of code that runs in its own context. Microsoft Windows<sup></sup> is a multitasking system. If you open Explorer and Word at the same time, they run nearly independently of each another.
  
 
In this case, both Explorer and Word have their own contexts. They share one computer, but run as if the other were not present. There is inter-task communication. If you double-click on a document in the file manager, it launches Word to edit the file you clicked.
 
In this case, both Explorer and Word have their own contexts. They share one computer, but run as if the other were not present. There is inter-task communication. If you double-click on a document in the file manager, it launches Word to edit the file you clicked.
  
With MC-BASIC, you can use different tasks to control different operational modes: one for power up, one for set-up, one for normal operation, and another for when problems occur. Like Windows, each task can run independently of the others, and you can prescribe interactions between tasks.
+
With MC-Basic, you can use different tasks to control different operational modes: one for power up, one for set-up, one for normal operation, and another for when problems occur. Like Windows, each task can run independently of the others, and you can prescribe interactions between tasks.
  
Multi-tasking is used when you want multiple processes to run largely independent of each other. For example, if you are using the MC to interface to the operator, you will usually use a separate task to execute the interface code. Another example is when two parts of a machine are largely independent of each other. There is usually some control required between tasks as one task may start or stop another.
+
Multitasking is used when you want multiple processes to run largely independent of each other. For example, if you are using the softMC to interface to the operator, you will usually use a separate task to execute the interface code. Another example is when two parts of a machine are largely independent of each other. There is usually some control required between tasks as one task may start or stop another.
  
If a machine is simple to control, you should try to keep the entire program in one task (in addition to Config.Prg). If you do need to use multi-tasking, you should keep a highly structured architecture. <s>Kollmorgen</s> recommends that you limit use of the main task for axis and group set up, machine initialization, and controlling the other tasks. Normal machine operation should be programmed in other tasks. For example, Main.Prg might be limited to setting up axes, and then starting Pump.Prg,'' ''Conveyor.Prg'','' and Operator.Prg.
+
If a machine is simple to control, you should try to keep the entire program in one task (in addition to Config.Prg). If you do need to use multitasking, you should keep a highly structured architecture. It is recommended that you limit use of the main task for axis and group set up, machine initialization, and controlling the other tasks. Normal machine operation should be programmed in other tasks. For example, Main.Prg might be limited to setting up axes, and then starting Pump.Prg,'' ''Conveyor.Prg'','' and Operator.Prg.
  
 
Do not split control of an axis or group across tasks. You can put control for multiple axes in one task. Ideally, you should use multiple tasks for machines where different sections operate more or less independently. You can also use tasks to implement different operational modes.
 
Do not split control of an axis or group across tasks. You can put control for multiple axes in one task. Ideally, you should use multiple tasks for machines where different sections operate more or less independently. You can also use tasks to implement different operational modes.
  
Multi-tasking is a powerful tool, but it carries a cost. It is easy to make errors that are difficult to find. When multiple tasks are running concurrently, complex interaction is difficult to understand and recreate. Limit the use of tasks to situations where they are needed.
+
Multitasking is a powerful tool, but it carries a cost. It is easy to make errors that are difficult to find. When multiple tasks are running concurrently, complex interaction is difficult to understand and recreate. Limit the use of tasks to situations where they are needed.
  
Do not create a task as a substitute for an event handler. Events and tasks are not the same. MC-BASIC supports event handlers to respond to realtime events. Events are similar to interrupts in microprocessor systems. They normally run at higher priorities than the programs that contain them. They are ideal for quick responses to realtime events. Add the event handler to an existing task to respond to an event.
+
Do not create a task as a substitute for an event handler. Events and tasks are not the same. MC-Basic supports event handlers to respond to realtime events. Events are similar to interrupts in microprocessor systems. They normally run at higher priorities than the programs that contain them. They are ideal for quick responses to realtime events. Add the event handler to an existing task to respond to an event.
  
 
Do not use tasks in place of subroutines. Remember that when you start a task, the original task continues to run. When you call a subroutine, you expect the calling program to suspend execution until the subroutine is complete. The behavior of tasks where the two routines continue to execute can cause complex problems.
 
Do not use tasks in place of subroutines. Remember that when you start a task, the original task continues to run. When you call a subroutine, you expect the calling program to suspend execution until the subroutine is complete. The behavior of tasks where the two routines continue to execute can cause complex problems.
  
Knowing when to use multi-tasking and when to avoid it requires some experience. If you are new to multi-tasking, you may want to start slow until you are familiar with how it affects program structure. When you start a new project, BASIC Moves creates the main task as part of opening a new project. After that process is complete, you can add a new task to your project by selecting File, New. You can also press the new task button on the BASIC Moves tool bar.
+
Knowing when to use multitasking and when to avoid it requires some experience. If you are new to multitasking, you may want to start slow until you are familiar with how it affects program structure. When you start a new project, ControlStudio creates the main task as part of opening a new project. After that process is complete, you can add a new task to your project by selecting File, New. You can also press the new task button on the ControlStudio tool bar.
  
 
== Loading the Program ==
 
== Loading the Program ==
BASIC Moves automatically loads all tasks in your project when you select Run Project. You can select Run Project by selecting it from the Debug menu, by pressing the F5 key, or by pressing the “Load Task”and “Run Task” buttons on the tool bar. By default, tasks are loaded from the host PC to the MC at a low priority (Priority = 16).
+
ControlStudio automatically loads all tasks in your project when you select Run Project. You can select Run Project by selecting it from the Debug menu, by pressing the F5 key, or by pressing the “Load Task”and “Run Task” buttons on the tool bar. By default, tasks are loaded from the host PC to the softMC at a low priority (Priority = 16).
  
 
When you select Run Task, the project’s main task is started at the lowest priority (Priority = 16). You can change the priority of the main task by selecting View-> Project Manager->Options and then changing the priority in the bottom of the window. If you structure your software so that the main program loads all other tasks, the Run Project button starts your machine.
 
When you select Run Task, the project’s main task is started at the lowest priority (Priority = 16). You can change the priority of the main task by selecting View-> Project Manager->Options and then changing the priority in the bottom of the window. If you structure your software so that the main program loads all other tasks, the Run Project button starts your machine.
  
== Preemptive Multi-tasking & Priority Levels ==
+
== Preemptive Multitasking & Priority Levels ==
 
Because many tasks share one processor, you must carefully design your system so tasks get processing resources when they need them. You do not want the operator interface taking all the resources when you need fast response to a realtime event. The operating system provides system resources based on two criteria: task priority level and time slice.
 
Because many tasks share one processor, you must carefully design your system so tasks get processing resources when they need them. You do not want the operator interface taking all the resources when you need fast response to a realtime event. The operating system provides system resources based on two criteria: task priority level and time slice.
  
When you create a program, you must select the task '''priority level'''. MC-BASIC allows you to specify 16 levels of priority. The task with the highest priority takes all the system resources it can use. In fact, no task of a lower priority receives any resources until all tasks of higher priority relinquish them. Most systems have one main task that runs at a medium priority and perhaps a background task that runs at a low priority, with a few high priority tasks. At every time slice, the MC re-evaluates which task has the highest priority and assigns resources to it.
+
When you create a program, you must select the task '''priority level'''. MC-Basic allows you to specify 16 levels of priority. The task with the highest priority takes all the system resources it can use. In fact, no task of a lower priority receives any resources until all tasks of higher priority relinquish them. Most systems have one main task that runs at a medium priority and perhaps a background task that runs at a low priority, with a few high priority tasks. At every time slice, the softMC reevaluates which task has the highest priority and assigns resources to it.
  
The BASIC Moves terminal window relies on the MC command line task, which runs at priority 2. If you start a task with priority 1, the terminal will not be available until the task is complete or idle. Consequently, you will not be able to communicate with the MC and you may have to power-down the system to recover the terminal window. You can optionally set the priority of a task when you start it. For example:
+
The ControlStudio terminal window relies on the softMC command line task, which runs at priority 2. If you start a task with priority 1, the terminal will not be available until the task is complete or idle. Consequently, you will not be able to communicate with the softMC and you may have to power-down the system to recover the terminal window. You can optionally set the priority of a task when you start it. For example:
  
 
<pre>StartTask Aux.Prg Priority=6</pre>
 
<pre>StartTask Aux.Prg Priority=6</pre>
Line 180: Line 283:
 
The default priority of events is 1 (highest) and the default priority of programs is 16.
 
The default priority of events is 1 (highest) and the default priority of programs is 16.
  
'''Time Slice''' is a method by which the operating system divides up resources when multiple tasks share the same priority level. The MC provides the first task with one time slice, the next time slice goes to the second, the next to the third, and so on. The time slice is currently one millisecond duration. This method is sometimes called round robin scheduling.
+
'''Time Slice''' is a method by which the operating system divides up resources when multiple tasks share the same priority level. The softMC provides the first task with one time slice, the next time slice goes to the second, the next to the third, and so on. The time slice is currently one millisecond duration. This method is sometimes called round robin scheduling.
  
 
== Inter-Task Communications and Control ==
 
== Inter-Task Communications and Control ==
Tasks can control one-another. In fact, any task can start, continue, idle, or kill any other task, regardless of which task has the higher priority. For detailed information on these commands, refer to the <sup>''</sup> MC Reference Manual''.
+
Tasks can control one-another. In fact, any task can start, continue, idle, or kill any other task, regardless of which task has the higher priority. For detailed information on these commands, refer to the Reference Manual.
  
'''StartTask '''starts tasks from the main task. For testing, you can use '''STARTTASK''' from the terminal window. <s>DanaherMotion</s> recommends you do not use '''STARTTASK''' in AutoExec.Prg. The syntax of '''STARTTASK''' is:
+
'''StartTask '''starts tasks from the main task. For testing, you can use '''STARTTASK''' from the terminal window. Do not use '''STARTTASK''' in AutoExec.Prg. The syntax of '''STARTTASK''' is:
  
 
<nowiki>StartTask <</nowiki>''TaskName''<nowiki>> {Priority = <</nowiki>''Level''<nowiki>>}{NumberOfLoops = <</nowiki>''Loop Count''>}
 
<nowiki>StartTask <</nowiki>''TaskName''<nowiki>> {Priority = <</nowiki>''Level''<nowiki>>}{NumberOfLoops = <</nowiki>''Loop Count''>}
Line 199: Line 302:
 
<pre>
 
<pre>
 
StartTask Task1.Prg Priority=8 NumberOfLoops = -1 'Run Task1 forever
 
StartTask Task1.Prg Priority=8 NumberOfLoops = -1 'Run Task1 forever
 
 
StartTask Main.Prg NOL=1 'Run Main once
 
StartTask Main.Prg NOL=1 'Run Main once
 
</pre>
 
</pre>
 +
 
'''IdleTask''' stops the task at the end of the line currently being executed and idles all its events. An idled task can be continued (using '''CONTINUETASK''') or terminated (using '''KILLTASK''').''' IDLETASK''' does not stop motion currently being executed. This is significant because all the events are idled and cannot respond to an axis' motion. Tasks can be idled explicitly by other tasks, but cannot idel itself. This command is issued from a task or the terminal window. The syntax of '''IdleTask''' is:
 
'''IdleTask''' stops the task at the end of the line currently being executed and idles all its events. An idled task can be continued (using '''CONTINUETASK''') or terminated (using '''KILLTASK''').''' IDLETASK''' does not stop motion currently being executed. This is significant because all the events are idled and cannot respond to an axis' motion. Tasks can be idled explicitly by other tasks, but cannot idel itself. This command is issued from a task or the terminal window. The syntax of '''IdleTask''' is:
  
Line 228: Line 331:
  
 
== Monitoring Tasks From the Terminal ==
 
== Monitoring Tasks From the Terminal ==
For detailed information on these commands, refer to the <sup>''</sup> MC Reference Manual''.
+
For detailed information on these commands, refer to the Reference Manual.
  
 
'''TASK.STATUS''' provides the current state of any task. You can query '''TASK.STATE''' from the terminal window. You cannot use '''TASK.STATUS''' from within a program. The syntax for '''TASK.STATUS''' is:
 
'''TASK.STATUS''' provides the current state of any task. You can query '''TASK.STATE''' from the terminal window. You cannot use '''TASK.STATUS''' from within a program. The syntax for '''TASK.STATUS''' is:
Line 244: Line 347:
 
? TaskList
 
? TaskList
 
</pre>
 
</pre>
 +
 
A typical result is:
 
A typical result is:
 
<pre>
 
<pre>
 
TaskName = TASK1.PRG, Status = sstep, Priority=16
 
TaskName = TASK1.PRG, Status = sstep, Priority=16
 
 
TaskName = DO.PRG, Status = suspend, Priority=4
 
TaskName = DO.PRG, Status = suspend, Priority=4
 
</pre>
 
</pre>
  
 
== Relinquishing Resources ==
 
== Relinquishing Resources ==
When tasks of different priorities compete for processor time, the highest priority task always takes all the resources it needs. However, tasks of high priority can relinquish computer resources under some conditions. In these cases, tasks of lower priority run until the high priority tasks again demand the resources. There are three conditions under which a task relinquishes resources: when the task is terminated, when the task is suspended, or when the task is idled. For detailed information on these commands, refer to the <sup>''</sup> MC Reference Manual''.
+
When tasks of different priorities compete for processor time, the highest priority task always takes all the resources it needs. However, tasks of high priority can relinquish computer resources under some conditions. In these cases, tasks of lower priority run until the high priority tasks again demand the resources. There are three conditions under which a task relinquishes resources: when the task is terminated, when the task is suspended, or when the task is idled. For detailed information on these commands, refer to the Reference Manual.
  
 
A '''task terminates''' when it is finished executing. If a task starts with '''NUMBEROFLOOPS''' greater than zero, the task executes the specified number of times and terminates. The task relinquishes all resources. Terminated tasks remain loaded in the system and can be restarted.
 
A '''task terminates''' when it is finished executing. If a task starts with '''NUMBEROFLOOPS''' greater than zero, the task executes the specified number of times and terminates. The task relinquishes all resources. Terminated tasks remain loaded in the system and can be restarted.
Line 272: Line 375:
 
The main program can contain sections which automatically handle events. This reduces the programming effort required to make tasks respond quickly and easily to realtime events. Event handlers begin with '''OnEvent''' and end with '''End OnEvent''' and occur just after the '''Program''' keyword.
 
The main program can contain sections which automatically handle events. This reduces the programming effort required to make tasks respond quickly and easily to realtime events. Event handlers begin with '''OnEvent''' and end with '''End OnEvent''' and occur just after the '''Program''' keyword.
  
After '''OnEvent''' is loaded, turn the event On with '''EventOn''' just after the '''End OnEvent''' keyword (enable immediately). However, you can enable and disable '''OnEvent '''at any time using '''EventOn''' and '''EventOff'''. Multiple '''OnEvents''' can be written sequentially. The MC system can support up to 64 events. The number of '''OnEvent'''(s) in a single task is not restricted, so a task may have from 0 to 64 '''OnEvent'''(s).
+
After '''OnEvent''' is loaded, turn the event On with '''EventOn''' just after the '''End OnEvent''' keyword (enable immediately). However, you can enable and disable '''OnEvent '''at any time using '''EventOn''' and '''EventOff'''. Multiple '''OnEvents''' can be written sequentially. The softMC system can support up to 64 events. The number of '''OnEvent'''(s) in a single task is not restricted, so a task may have from 0 to 64 '''OnEvent'''(s).
  
 
It is important to understand that '''OnEvent'''s are different from ordinary tasks. '''OnEvent'''s are preemptive within the task. That is, an '''OnEvent '''runs until complete and the program execution returns to the main program. While an '''OnEvent''' is executing, it does not release CPU time to the parent task or any other task. In this sense, '''OnEvents '''are similar to interrupt calls. They run to completion before execution returns to the main program. An '''OnEvent''' must have a higher priority than its parent task to ensure that when an event occurs, it interrupts its parent task and runs to completion. The rules are valid for a single process, (that is, the parent task and its events), while events of the respective tasks in the system share the CPU among themselves.
 
It is important to understand that '''OnEvent'''s are different from ordinary tasks. '''OnEvent'''s are preemptive within the task. That is, an '''OnEvent '''runs until complete and the program execution returns to the main program. While an '''OnEvent''' is executing, it does not release CPU time to the parent task or any other task. In this sense, '''OnEvents '''are similar to interrupt calls. They run to completion before execution returns to the main program. An '''OnEvent''' must have a higher priority than its parent task to ensure that when an event occurs, it interrupts its parent task and runs to completion. The rules are valid for a single process, (that is, the parent task and its events), while events of the respective tasks in the system share the CPU among themselves.
Line 294: Line 397:
 
<pre>
 
<pre>
 
OnEvent MOVE_ON_TRIGGER System.Din.1=ON
 
OnEvent MOVE_ON_TRIGGER System.Din.1=ON
 
 
Move X-axis 10000
 
Move X-axis 10000
 
 
End OnEvent
 
End OnEvent
 
</pre>
 
</pre>
 +
 
Normally, event handlers run at a high priority so that once the event occurs, they run to completion. In most cases, this code should be very short as it usually takes all resources until it is complete.  
 
Normally, event handlers run at a high priority so that once the event occurs, they run to completion. In most cases, this code should be very short as it usually takes all resources until it is complete.  
  
Line 305: Line 407:
 
OnEvent System.Din.2 = ON ScanTime = 5
 
OnEvent System.Din.2 = ON ScanTime = 5
 
</pre>
 
</pre>
 +
 
Events can either be controlled from within the task in which they reside, or from the terminal. The main program or any subroutine can issue EventOn (to enable the OnEvent command) or EventOff (to disable it). OnEvents cannot be controlled from other tasks.
 
Events can either be controlled from within the task in which they reside, or from the terminal. The main program or any subroutine can issue EventOn (to enable the OnEvent command) or EventOff (to disable it). OnEvents cannot be controlled from other tasks.
  
Line 326: Line 429:
 
? EventList
 
? EventList
 
</pre>
 
</pre>
 +
 
the result is something like the following line for each task:
 
the result is something like the following line for each task:
  
Line 348: Line 452:
 
You can use '''GoTo '''commands within an '''OnEvent''''' ''block of code. However, because '''OnEvent''' interrupts the main program, you cannot use '''GoTo''' to branch out of the event handler or into the event handler. You cannot place '''OnEvent…End OnEvent '''in the middle of program flow commands (e.g., '''For…Next''',''' If…Then''', etc.). You cannot declare or use local variables inside an '''OnEvent''' block.
 
You can use '''GoTo '''commands within an '''OnEvent''''' ''block of code. However, because '''OnEvent''' interrupts the main program, you cannot use '''GoTo''' to branch out of the event handler or into the event handler. You cannot place '''OnEvent…End OnEvent '''in the middle of program flow commands (e.g., '''For…Next''',''' If…Then''', etc.). You cannot declare or use local variables inside an '''OnEvent''' block.
  
= Setting up Axes =
+
= Semaphores =
In this section, we set up the axes in the system. We will discuss units for position, velocity, and acceleration. We discuss how the MC’s acceleration profile works. We talk about how to set up limits for axes. We conclude with a discussion of a few advanced topics: an overview of SERCOS, simulated axes, and dual-loop position control.
+
Semaphores are the basis for synchronization and mutual exclusion. The difference is that the mutual exclusion semaphore is created as “full” or “1”, while the synchronization semaphore is empty “0”. If the semaphore is used for protecting mutual resources, it is taken before accessing the resource and releases at the end. A synchronization semaphore is given by the producer and taken (consumed) by the consumer.
 
 
== Axis Definition ==
 
The MC is oriented around axes. An axis is a combination of a drive, a motor, and some portions of the MC. The diagram below shows an MC axis:
 
  
[[Image:Axystems;UserManual-361AxisDefinition.png|caption]]
+
{{Note|'''''A semaphore is created as “full.”'''''}}
  
Each axis has a set of properties that are defined by the MC. These properties are used in the calculation of position and velocity commands, monitoring limits, and stores configuration data for the axis. The MC sends commands to the drive and the drive controls the motor. All these components together form an axis of motion.
+
Global semaphore are defined with '''COMMON''' '''SHARED''' in CONFIG.PRG or from the command line. Since a semaphore's purpose is to protect data among tasks, there is no meaning to local semaphores.
  
== Axis Name ==
+
A semaphore is ''given/released'' by '''SEMAPHOREGIVE''' and ''taken/consumed ''by '''SEMAPHORETAKE'''. It is possible to specify a time out of up to 5000 ms. '''SEMAPHORETAKE''' acquires a semaphore and returns before timeout or does not acquire a semaphore and returns after timeout.
The MC automatically sets up all your axes according to their addresses: A1, A2, A3, and so on until A32 ( the maximal number of axes is limited by User Autorization Code by manufacturer ). You access axis properties by preceding the property name with the axis name and a period. For example, each axis has a property, '''VELOCITYFEEDBACK''', which provides the current velocity of that axis. You can query the '''VELOCITYFEEDBACK''' value with the '''?''' command in the BASIC Moves terminal:
 
<pre>
 
? A1.VelocityFeedback
 
</pre>
 
You can rename the axis. It is usually worthwhile to name the axes according to their function. It makes your program easier to understand and to debug. For example, you could enter:
 
<pre>
 
A1.AxisName = ConveyorAxis
 
</pre>
 
Later, you can query the velocity with:
 
<pre>
 
? ConveyorAxis.VelocityFeedback
 
</pre>
 
The axis name may only be changed into the configuration program Config.Prg. You cannot print the axis name at any time.
 
  
== Drive Address ==
+
{{Note| '''''Mutual exclusion semaphores are taken and given by the same task. Synchronization semaphores are given by one task and taken by another task.'''''}}
You must specify the drive address property of the axis. Simulated axes do not have drive addresses and do not require this property to be assigned. This assigns the physical address (dip switch setting on the drive) to the axis defined in the MC. If we wanted to assign the drive with address 5 to axis 1, we type the following command into the terminal window of the BASIC Moves Developer Studio or in our program:
 
<pre>
 
A1.Dadd = 5 ‘ Assign drive address 5 to axis 1
 
</pre>
 
The short form, '''DADD''', of axis property '''DRIVEADDRESS''' is used in the example. '''Axis.DriveAddress''' property should meet to the drive hardware address configuration . Most axis properties and constants have short forms that can speed typing and ease the programming effort. Refer to the ''MC Reference Manual ''for more information.
 
  
== Starting Position ==
+
== Mutual Exclusion Semaphores ==
Before we get started here, you must:
+
Mutual exclusion semaphores lock resources by taking a semaphore. Another task(s) competing for the same resource is blocked until the semaphore is released.
  
'''Install and tune drives'''Follow the process for installing and tuning all drives according to the ''MC Installation Manual''. Run '''MOTIONLINK'''<sup></sup> to select your motor type and tune the axis to your satisfaction.
+
Example of a mutually exclusive semaphore:
 
 
'''Install and check out your MC'''Install and check out your MC according to the ''MC Installation Manual''.
 
 
 
Wire all I/O, connect the fiber-optic ring, and follow the procedures in the ''MC Installation Manual'' to check out the wiring.
 
 
 
'''Install BASIC Moves Development Studio'''Install BASIC Moves Development Studio after reviewing the ''BASIC Moves User’s Manual. ''We use the terminal screen here extensively. Remember, any commands typed in the terminal window are lost when you power down. Enter these commands in your MC program to be recalled at power up.
 
 
 
== BASIC Moves Auto Setup Program ==
 
BMDS automatically generates a setup program each time you open a new project. BMDS first requests information regarding units and preferences for each axis in the system. Then, it generates a program with most of the setup for your application.
 
 
 
The auto setup program has four sections: a short task-variable declaration, an example program which generates simple motion, a SERCOS setup subroutine, and an axis setup subroutine. The variable declaration section provides one or two examples of variable declarations for a task.
 
 
 
The motion program cycles axis A1 10 times. Most of this main program is commented out because this code enables the drive and generates motion commands. Remove the single-quote comment markers for the program to run. These lines are commented out because to ensure that it is safe to operate your machine before executing this program. This includes tuning your axes properly to assure stable motion control. Refer to the ''MC Installation Manual ''for more information.
 
 
 
The third section of the auto setup program is a SERCOS setup subroutine. This subroutine brings up the SERCOS ring in preparation for the drives being enabled. The final section of the auto setup program is the axis setup subroutine. This subroutine loads axis properties for units and limits. Refer to Appendix A for a Sample Nesting Program.
 
 
 
== User Units ==
 
The MC supports user units with one floating-point conversion factor for each of six types of properties: position, velocity, acceleration, jerk, external position, and external velocity.
 
 
 
'''''<nowiki><axis>.</nowiki>''DIRECTION''' is applied as a multiplier to the units conversion factors. The movement factors (''i.e.'', '''POSITIONFACTOR''', '''VELOCITYFACTOR''', '''ACCELERATIONFACTOR''') are only assigned positive values and '''DIRECTION''' determines their sign. '''DIRECTION''' can take one of two values: -1 for forward direction or +1 for reverse direction.
 
 
 
MC units allow you to work in units that are convenient. All unit types are independent, so position units are inches, velocity units are feet/min and acceleration is rpm/second. Units are changed only when the axis is disabled.
 
 
 
== Position Units ==
 
Position units are controlled by '''POSITIONFACTOR''' or '''PFAC'''. The MC internal units are encoder counts for encoder-based systems or 65536 counts per revolution for resolver-based systems. Encoder counts are four times encoder lines. To set up position units, determine how many counts are in one of your selected units. For example, suppose you had this system:
 
 
 
Desired units: inches
 
 
 
Rotary motor (as opposed to linear motor)
 
 
 
2000 line Encoder
 
 
 
3:1 gearbox
 
 
 
5 turn per inch ball screw
 
 
 
Determine '''POSITIONFACTOR''' (number of counts per inch):
 
 
 
1 inch = 5 turns on the screw <nowiki>= 15 turns into the gearbox</nowiki> <nowiki>= 15 * 2000 lines</nowiki> <nowiki>= 15 * 2000 * 4 counts</nowiki> <nowiki>= 120,000 counts</nowiki>
 
 
 
'''POSITIONFACTOR''' is set to the number of counts per inch: 120000.
 
 
<pre>
 
<pre>
A1.PositionFactor = 120000
+
' common shared comMutex as semaphore
 +
' defined in config.prg
 +
Program
 +
Open COM2 BaudRate=9600 Parity=0 DataBits=8 StopBit=1 As #1
 +
While 1
 +
' take semaphore lock serial port
 +
If SemTake(comMutex,5000) = 1 Then
 +
Print #1,”Hello ”;
 +
Print #1,”world”
 +
SemGive(comMutex) ‘unlock serial port
 +
End if
 +
End While
 +
End program
 
</pre>
 
</pre>
For a second example, let’s change the first example from encoder to resolver, change the ball screw and use meters for the units:
 
 
Desired units: meters
 
 
Rotary motor
 
 
Resolver (65536 counts per revolution)
 
 
3:1 gearbox
 
 
2 turn/cm ball screw
 
 
Determine '''POSITIONFACTOR''' (number of counts per meter):
 
 
1 meter = 200 turns on the screw <nowiki>= 600 turns into the gearbox</nowiki> <nowiki>= 600 * 65536 counts</nowiki> <nowiki>= 39,321,600 counts</nowiki>
 
  
'''POSITIONFACTOR''' is set to the number of counts per meter: 39321600. If you use the BASIC Moves auto setup program, provide the motor resolution and number of motor rotations per unit movement and BASIC Moves calculates the math.
+
== Synchronization Semaphores ==
 +
Synchronization semaphores are essential in producer-consumer applications where task A prepares some data, while task B consumes it. In this case, the semaphore may eliminate constant polling for ready data and save considerable CPU resources.
  
== Velocity Units ==
+
Example of Producer:
Velocity units convert MC internal velocity units (counts/mSec) to your units. They are controlled using '''VELOCITYFACTOR''' or '''VFAC'''. Normally, velocity units are either the position units per second or per minute, or they are rpm. If you want velocity units to be your position units per second, set '''VELOCITYFACTOR''' to '''POSITIONFACTOR''' divided by 1000 (to convert milliseconds to seconds):
 
 
<pre>
 
<pre>
A1.VelocityFactor = A1.PositionFactor/1000 ‘ for position units/sec
+
' common shared syncSemaphore as semaphore
</pre>
+
' defined in config.prg
If you want position units per minute, divide by 60000:
+
' common shared globalA as long ' defined in config.prg
<pre>
+
Program
A1.VelocityFactor = A1.PositionFactor/60000 ‘ for position units/min
+
Dim dummy as long
</pre>
+
' Semaphore is created as “full” - flush it before first use
If you want rpm, you must calculate the number of counts per revolution and then divide that by 60000 (to convert milliseconds to minutes):
+
dummy=semTake(syncSemaphore) ' no waiting
 
+
While 1
Desired units: rpm
+
globalA=globalA+1 ' produce some data
 
+
semGive(syncSemaphore)
2000 line Encoder
+
sleep (100)
 
+
End While
You first need to determine the number of counts per inch for each revolution:
+
End program
 
 
1 rev = 2000 lines
 
 
 
<nowiki>= 2000 * 4 counts</nowiki>
 
 
 
<nowiki>= 8000 counts</nowiki>
 
 
 
'''VelocityFactor''' is set to the number of counts per revolution divided by 60000:
 
<pre>
 
A1.VelocityFactor = 8000/60000
 
</pre>
 
 
 
== Acceleration Units ==
 
Acceleration units convert MC internal acceleration units (counts/msec<sup>2</sup>) to your units. They are controlled using '''<nowiki><</nowiki>''axis''>.ACCELERATIONFACTOR''' or '''<nowiki><</nowiki>''axis''>.AFAC'''. Normally, acceleration units are either the velocity units per second or per minute. If you want acceleration units to be your velocity units per second, set '''ACCELERATIONFACTOR''' to '''VELOCITYFACTOR''' divided by 1000 (to convert milliseconds to seconds). Divide by 60000 to set acceleration units to velocity units per minute:
 
 
 
A1.AccelerationFactor = A1.VelocityFactor/1000 ‘Accel units = vel/sec
 
 
 
or
 
 
 
A1.AccelerationFactor = A1.VelocityFactor/60000 ‘Accel units = vel/min
 
 
 
== Jerk Units ==
 
It is also necessary to define the jerk factor, even if you always use the smooth factor. The smooth factor automatically defines the jerk value from the velocity and acceleration values, but it is a value before factors, therefore totally invalid values of jerk (internally) can be computed. At least set Jfac=Afac/1000 and it should work. '''<nowiki><</nowiki>''axis''>.JERKFACTOR'''<nowiki> specifies the conversion factor between your jerk units and the internal units [counts per msec</nowiki><sup>3</sup>]. '''<nowiki><</nowiki>''axis''>.JERKFACTOR''' must contain the conversion factor for both the position dimension and the time dimension.
 
 
 
= Acceleration Profile =
 
The MC provides smooth, controlled acceleration profiles to reduce vibration and wear on the machine, and to allow high acceleration rates. The MC allows you to independently control acceleration and deceleration to further reduce vibration. For detailed information any listed commands, refer to the ''MC Reference Manual''.
 
 
 
'''ACCELERATION''' and '''DECELERATION''' control the acceleration rates. The following lines of code entered at the terminal window (or in your program) change the acceleration rates for Axis A1:
 
<pre>
 
A1.Acceleration = 1000
 
 
 
A1.Deceleration = 1000
 
</pre>
 
Do not enter these commands yet. Acceleration units should be set before these values are entered. You can impose limits which constrain the time during which acceleration and deceleration occurs. The motion includes three major parts: acceleration phase, constant velocity cruise phase, and deceleration phase.
 
 
 
Time-based Acceleration/Deceleration is the motion interface in which the duration of the acceleration/deceleration phases during the movement is defined. These duration times will be used internally to calculate proper motion parameters to meet the time requirements as accurate as possible.
 
 
 
'''''<nowiki><axis/group></nowiki>''.TIMEACCELERATION''' and '''''<nowiki><axis/group></nowiki>''.TIMEDECELERATION''' can be used for time-based definition.
 
 
 
Jerk is the first derivative of acceleration. Fast moves usually generate large amounts of jerk. Having a large amount of jerk in a motion profile can excite machine resonance frequencies and thereby, cause unnecessary wear and noise. Some motion controllers simplify motion profiles by instantaneously changing the acceleration command which implies a very high level of jerk. The MC allows you to limit the amount of jerk in all profiles by using the axis properties '''SMOOTHFACTOR''' or '''JERKFACTOR'''''.''
 
 
 
Specify trapezoidal profiles by setting '''SMOOTHFACTOR''' ('''SMOOTH''') to zero. If you want a smoother acceleration, increase the '''SMOOTHFACTOR''' from 1to a maximum of 100. If '''SMOOTHFACTOR''' is large (greater than 50), it can increase the acceleration time by one or more orders of magnitude.
 
 
 
Using '''<nowiki><</nowiki>''axis''>.ACCELERATION '''and '''<nowiki><</nowiki>''axis''>.JERK '''to limit velocity changes produces acceleration profiles that remove the high frequency components of torque that are present in straight-line acceleration. This minimizes the excitation of machine resonance frequencies which in turn reduces audible noise, vibration, and mechanical wear. For example, the figure below shows a typical MC acceleration profile showing how controlled jerk produces smooth acceleration.
 
 
 
[[Image:Axystems;UserManual-37AccelerationProfiles.png|caption]]
 
 
 
= Position and Velocity =
 
Position and velocity are the key command and feedback signals for each axis. These properties are updated by the MC every SERCOS cycle and may be read at any time. Their properties are double-precision floating point numbers. Velocity Units are discussed above. The four properties which hold these values are:
 
 
 
'''<nowiki><</nowiki>''axis''>.POSITIONCOMMAND''' or '''<nowiki><</nowiki>''axis''>.PCMD<nowiki><</nowiki>''axis''>.POSITIONFEEDBACK''' or '''<nowiki><</nowiki>''axis''>.PFB<nowiki><</nowiki>''axis''>.VELOCITYCOMMAND '''or '''<nowiki><</nowiki>''axis''>.VCMD<nowiki><</nowiki>''axis''>.VELOCITYFEEDBACK''' or '''<nowiki><</nowiki>''axis''>.VFB'''
 
 
 
You can read these properties anytime the SERCOS ring is up.
 
 
 
Position error is defined as the difference between position commanded and position feedback. When an axis is at rest, (i.e., '''ISSETTLED'''), this simple definition of position error is valid. However, when the axis is in motion, the true position error does not equal the instaneous commanded position minus the instantaneous feedback position because there is a time delay of two SERCOS cycle times (2 ms) from when '''MOVE''' is issued until the feedback position is received.
 
 
 
When the MC calculates position error, it automatically accounts for the communication delay. In most circumstances, the two-cycle time delay is correct. However, if microinterpolation is enabled in the drive, the feedback position is delayed an additional one or more cycle times.
 
 
 
To manage position error problems, the MC provides a number of axis and group properties relating to position error. '''''<nowiki><axis></nowiki>''.POSITIONERRORDELAY''' (new in firmware version 3.0), allows you to specify the number of SERCOS cycle times to apply when calculating position error. The default is two.
 
 
 
The MC allows you to set up any axis in your system as a rotary axis. Rotary axes are often used for mechanical mechanisms that repeat after a fixed amount of rotation.
 
 
 
For example, a motor driving a rotating table is often configured as a rotary axis. In this case, the table units are set up as degrees and the units of the axis are set to repeat after 360°. In that way, the position repeats after every rotation of the table, rather than continuing to increase indefinitely. The key to the rotary mode is setting rollover position ('''POSITIONROLLOVER''' or '''PROLLOVER''') correctly and accurately.
 
 
 
Consider this example where the axis drives a rotary table through a 5:3 gearbox:
 
 
 
Desired units: DegreesDesired repeat: 360Gearbox: 5:3Feedback 2000 line encoder
 
 
 
For this example, first set position units to degrees:
 
 
 
1 degree = 1/360 revolution of table
 
 
 
<nowiki>= (5/3) * (1/360) revolution of the motor</nowiki>
 
 
 
<nowiki>= 2000 * (5/3) * (1/360) lines</nowiki>
 
 
 
<nowiki>= 4 * 2000 * (5/3) * (1/360) counts</nowiki>
 
 
 
<nowiki>= </nowiki>40000/1080
 
 
 
After setting these units, you must enable the rotary mode and set the rollover to 360 as follows:
 
<pre>
 
A1.PositionFactor = 40000/1080
 
A1.PositionRollover = 360
 
 
 
A1.PositionRolloverEn = On‘Enable Rotary Motion
 
</pre>
 
In this case, the feedback position is always between 0 and 360. You can still command long moves, say 10,000 degrees. However, when the motor comes to rest, the feedback is read as less than 360.
 
 
 
When using rotary mode in applications where the motor turns continuously in one direction, it is important to take advantage of all available accuracy in the MC. This is because inaccuracy is accumulated over many revolutions of the motor. For example, we could have rounded A1.POSITIONFACTOR in the above example to 37.037, which is accurate to 1 part in 1,000,000. However, after 10,000 revolutions (2000 rpm for just 5 minutes), that 1 part in a 1,000,000 would have accumulated to a few degrees. This means that if the table position is 100 degrees, it might read as 97°. In other words, the table appears to drift.
 
 
 
In the example above, the math is exact until the MC performs the division. Because the MC calculates with double precision (about 14 places of accuracy), you should use MC math when calculating ratios that cannot be represented precisely in decimal notation. In the example, using the full accuracy of the MC (about one part in 1014) the motor would have to travel about 3x1011 revolutions to accumulate one degree of error. That is equivalent to 88 years of continuous rotation at 6000 rpm.
 
 
 
All drives provide interface hardware to accept an external or auxiliary encoder. This encoder is in addition to the primary position feedback device. You will need to set up the SERCOS telegram to support this. External position is frequently used in master-slave operations (gearing and camming) where the system is slaved to an external signal such as a line-operated motor.
 
 
 
The MC provides the external position through the axis property, '''POSITIONEXTERNAL''' or '''PEXT'''. This variable contains the accumulated encoder movement of the drive’s external encoder input. It is updated every SERCOS cycle.
 
 
 
You can access '''PEXT''' two ways: realtime or on a as-needed basis. To access '''PEXT''' on an as-needed based, issue '''IDNVALUE'''. For example:
 
<pre>
 
Dim Shared StorePExt as Double
 
 
 
StorePExt = IDNValue(1, 53, 7)
 
</pre>
 
This gets '''PEXT''' in counts, not user units. You can access '''PEXT''' in realtime by properly configuring the telegram for the axis with the external encoder.
 
 
 
The MC allows you to control the units of the '''POSITIONEXTERNAL''' ('''PEXT'''). This is controlled with '''''<nowiki><axis></nowiki>'''''.'''POSITIONEXTERNALFACTOR''' or '''''<nowiki><axis></nowiki>'''''.'''PEXTFAC'''. The process is identical to setting position units for an encoder. The external position and velocity factors are only effective for cases when the SERCOS telegram is configured to transmit the external encoder.
 
 
 
Do not access '''PEXT''' using '''IDNVALUE '''because the encoder values coming into the drive are subject to rollover. The MC continuously monitors these values and adjusts the value when a rollover is detected. The values accessed via the SERCOS service channel cannot be monitored for rollover. Also, external position units are not in effect.
 
 
 
The MC provides the external velocity through the '''''<nowiki><axis></nowiki>''.VELOCITYEXTERNAL''' or '''''<nowiki><axis></nowiki>''.VEXT'''. This variable contains the accumulated encoder movement per millisecond and is also updated every SERCOS cycle when the SERCOS telegram is configured to transmit the external encoder.
 
 
 
The MC allows you to control the units of '''VELOCITYEXTERNAL''' with '''''<nowiki><axis></nowiki>''.VELOCITYEXTERNALFACTOR''' or '''''<nowiki><axis></nowiki>''.VEXTFAC'''. The process is identical to setting position units except that '''''<nowiki><axis></nowiki>''.VEXTFAC''' can only be input as an encoder signal.
 
 
 
= Limits =
 
This section outlines the many types of limits you can impose on the MC system. These limits help protect the machine from excessive excursions of travel, speed, and torque. There are three types of limits in the system:
 
 
 
MC Generator LimitsMC Realtime LimitsDrive Limits
 
 
 
Limits can be imposed in several ways. First, some limits are imposed by the MC and others by the drive. Limits can be checked in realtime or they can be checked only for subsequent actions.
 
 
 
'''MC Generator''' limits affect subsequent commands to the motion generator. For example, if you change an acceleration limit, this has no effect on the current motion command, but it applies to subsequent motion commands. If the axis is not in a jog or acting as a slave, then '''POSITIONMIN''' and '''POSITIONMAX''' (position limits) are checked only at the beginning of the move.
 
 
 
The MC checks '''realtime limits''' each update cycle. Changes in these limits affect current operations. '''VELOCITYFEEDBACK''' is checked against '''VELOCITYOVERSPEED''' in every SERCOS cycle.
 
 
 
'''Drive limits''' are imposed by the drive. Changes in these limits affect current operations. For example, ILIM limits the peak current that is output by the drive. These limits are imposed independently of the position and velocity commands issued by the controller.
 
 
 
== Position Limits ==
 
There are several limits in the MC related to position:
 
 
 
'''POSITIONMIN''' or''' PMIN'''
 
 
 
'''POSITIONMAX '''or '''PMAX'''
 
 
 
'''POSITIONMIN''' ('''PMIN''')'' ''and '''POSITIONMAX '''('''PMAX''')'' ''place minimum and maximum limits on the position feedback for an axis. Set the limits with:
 
<pre>
 
A1.PositionMin = -10
 
 
 
A1.PositionMax = 200.5
 
</pre>
 
or you can use the short form:
 
<pre>
 
A1.PMin = -10
 
 
 
A1.PMax = 200.5
 
</pre>
 
Position limits must be enabled before they can operate. Limits are enabled with '''POSITIONMINENABLE''' and '''POSITIONMAXENABLE'''. Position Units are discussed above.
 
 
 
Position limits are checked two ways. First, they are checked in the motion generator. If you command a position move beyond the position limits, an error is generated and the move does not start. Second, they are checked each SERCOS update cycle (generally, 2 or 4 ms). If the axis is moving and crosses the position limit, this generates an error.
 
 
 
If the axis has already stopped because the position limits were crossed, the MC does allow you to back out. In other words, you can enter commands that move the axis back within the limits. The axis will move without generating errors.
 
 
 
Position limits are continuously checked only when the drive is in master-slave mode. Some conditions may occasionally result in the motor moving outside '''PMIN''' or '''PMAX''' limits which are not detected by the MC. SERCOS loop instability may also cause position errors.
 
 
 
You can control whether the MC watches either one or both of the limits in position limit. To do this, set '''POSITIONMINENABLE''' and '''POSITIONMAXENABLE''' to either ON or OFF.
 
<pre>
 
A1.PositionMinEnable = ON
 
 
 
A1.PositionMaxEnable = ON
 
</pre>
 
or, you can use the short forms:
 
<pre>
 
A1.PMinEn = ON
 
 
 
A1.PMaxEn = ON
 
</pre>
 
The default state of '''PMINEN '''and '''PMAXEN '''is off. You must enable them to use these limits.
 
 
 
You should limit the maximum position error your system tolerates. You do this by setting '''''<nowiki><axis></nowiki>''.POSITIONERRORMAX''' ('''''<nowiki><axis></nowiki>''.PEMAX''').
 
 
 
Care should be taken to set '''PEMAX''' to a value that matches the needs of the application. When the actual position following error ('''PE''') exceeds '''PEMAX''', motion stops. If the motion is stopped when this condition is detected, the axis is disabled.
 
 
 
During normal operation, occasional occurrences of position error overflow usually indicates a malfunction of the machine, such as a worn or broken part, or a need for lubrication. You should set the maximum position error well outside the boundaries of normal machine operation or nuisance errors occur when the machine is running.
 
 
 
During installation, position error overflow frequently occurs because the system is unstable. In this case, the motor runs away even though zero velocity is commanded. Set '''POSITIONERRORMAX''' to a reasonably small value before powering the system up. For example, you might set it to a few revolutions of the motor (or a few inches or centimeters for linear systems). This way, if the tuning is unstable, the system is less likely to cause a problem. Setting '''PEMAX''' to a very large number prevents the Position Error Overflow error from detecting an unstable system, and consequently, the motor is able to run away.
 
 
 
The proportional position loop is the simplest position loop. The next figure shows a block diagram of a proportional position loop:
 
 
 
[[Image:Axystems;UserManual-391PositionLimit1.png|caption]]
 
 
 
As you can see, the velocity command is proportional to the following error. Large velocity commands need large following error limits. At first, the units of inches/min/mil may seem confusing. The following error for an acceleration with a typical proportional loop is shown in the next figure.
 
 
 
[[Image:Axystems;UserManual-391PositionLimit2.png|caption]]
 
 
 
The good news about 100% feed-forward is that it eliminates steady-state following error. The bad news is that the system overshoots when subjected to acceleration or deceleration. In some cases, this is not an issue because the system may always transition smoothly, or some overshoot is acceptable.
 
 
 
In many cases, 100% feed-forward is not acceptable. In these cases, you can reduce the feed-forward to reduce overshoot. The larger the feed-forward gain, the greater reduction is seen steady-state following error. Most systems can tolerate the overshoot generated by feed-forward gains of 50%.
 
 
 
'''Acceleration feed-forward''' allows the use of 100% velocity feed-forward with no overshoot. Acceleration feed-forward works by adding current equivalent to the torque required to accelerate a fixed load. Acceleration feed-forward effectively cancels the torque generated by the inertia changing speed. This is why this technique is sometimes called inertial feed-forward.
 
 
 
Acceleration feed-forward works only when the inertia load is proportional to the axis acceleration. It does not work with axes that are coupled, such as non-rectangular robots. It also does not work well when the axis inertia varies. However, for most applications, acceleration feed-forward reduces overshoot and following-error significantly.
 
 
 
To use acceleration feed-forward, use '''MOTIONLINK''', or set the acceleration feed-forward scaling constant from the MC. Acceleration feedforward is IDN 348. For an axis A1, the correct line of code is:
 
<pre>
 
WriteIDNValue Drive = A1.DriveAddress IDN=348 Value = 1000
 
 
</pre>
 
</pre>
The valid range for this value is 0 to 2000. The purpose of the acceleration feed forward is to zero the following error during constant acceleration. The automatic design (user gain = 1000) gives good results. Fine-tune this value by applying trapezoidal trajectory and find the user gain that yields the minimum following error during the acceleration and deceleration.
+
Example of Consumer:
  
'''''<nowiki><axis></nowiki>''.POSITIONERRORSETTLE''', defines what level of position error is considered close enough to zero to be settled. For example, you can use:
 
 
<pre>
 
<pre>
A1.PositionErrorSettle = 0.01
+
' common shared syncSemaphore as semaphore
</pre>
+
' defined in config.prg
or you can use the short form:
+
' common shared globalA as long ' defined in config.prg
<pre>
+
Program
A1.PESettle = 0.01
+
While 1
</pre>
+
If SemTake(syncSemaphore,5000) = 1 Then
to specify that the position error must be below 0.01 units to be considered settled.
+
Print "A is "; globalA
 
+
End if
'''POSITIONERRORSETTLE''' is used when the motion controller must determine when an axis is close enough to the final end point of a move to be considered settled. This is commonly used between moves to ensure that the response to the first move is complete before moving to the second. The MC does this automatically through '''STARTTYPE''' when executing '''MOVE '''commands as is discussed in the Single Axis Motion section of this manual. You must set TSETTLE>0 or '''POSITIONERRORSETTLE''' is ignored.
 
 
 
'''TIMESETTLE '''(or '''TSETTLE''') defines the amount of time the position error must be lower than the value of '''PESETTLE''' before the move is considered settled. After the move profile is complete and the position error is less than '''POSTIONERRORSETTLE''', the MC waits '''TIMESETTLE''' milliseconds for settling. If the position error goes above '''POSITIONERRORSETTLE''' during that time, the timer resets.
 
 
 
'''ISSETTLED''' is a logical (TRUE or FALSE) property that indicates if the axis is settled. To be settled, the motion profile must be complete and the position error must be below '''POSITIONERRORSETTLE''' for a period of '''TIMESETTLE''' milliseconds.
 
 
 
'''ISMOVING''' is a property that indicates the state of the motion profiler. The valid range of values is from –1 to 3, with the following meaning:
 
 
 
-1 = element is a slave (gear or cam) unless an incremental move is issued, in which instance the following values are valid:
 
 
 
0 = element is not moving
 
 
 
1 = element is accelerating
 
 
 
2 = element is at constant velocity phase (cruise)
 
 
 
3 = element is deceleratingExample:
 
<pre>
 
While a1.ismoving > 0 ‘wait for profiler to finish
 
 
 
 
End While
 
End While
 +
End program
 
</pre>
 
</pre>
== Axis Velocity Limits ==
 
There are several limits in the MC related to velocity:
 
 
VelocityOverspeed
 
 
VelocityMax
 
 
Acceleration
 
 
Deceleration
 
 
'''VELOCITYOVERSPEED''' defines an absolute motor velocity limit. When this limit is exceeded, an error is generated and the axis is brought to an immediate stop. '''VELOCITYOVERSPEED''' is in MC velocity units and is set any time. It is checked every SERCOS update cycle. For example:
 
<pre>
 
A1.VelocityOverspeed = 4000
 
</pre>
 
'''VELOCITYMAX '''('''VMAX''') sets the maximum speed that the motion generator can command. '''VELOCITYMAX''' is in MC velocity units and is only set from the terminal window or in the configuration file, Config.Prg. It is checked at the beginning of each move. For example:
 
<pre>
 
A1.VelocityMax = 5000
 
</pre>
 
Two limits control acceleration and deceleration which themselves limit the velocity transients on acceleration profiles. These properties may be set from the terminal or in a user task (or any other context). These are '''ACCELERATIONMAX''' and '''DECELERATIONMAX'''.
 
 
'''ACCELERATIONMAX''' is the upper limit for acceleration in motion commands. It is in MC acceleration units. '''ACCELERATIONMAX '''is set up in the BASIC Moves auto-setup program when you start a new project.
 
 
'''DECELERATIONMAX''''' ''is the upper limit for deceleration in motion commands. It is in MC acceleration units. '''DECELERATIONMAX''' is set up in the BASIC Moves auto-setup program when you start a new project.
 
 
= VELOCITY, ACCELERATION AND JERK RATE PARAMETERS =
 
'''Axis.VelocityRate''' defines the axis velocity maximum scaling factor from 0.1 to 100 persents independently of acceleration, deceleration or jerk. '''<nowiki><</nowiki>''axis''>.VelocityRate''' may be modal or nodal.
 
 
'''Axis.AccelerationRate''' defines the axis acceleration maximum scaling factor from 0.1 to 100 persent independently of velocity, deceleration or jerk. '''<nowiki><</nowiki>''axis''>.AccelerationRate''' may be modal or nodal.
 
 
'''Axis.DecelerationRate''' defines the axis deceleration maximum scaling factor from 0.1 to 100 persent independently of velocity, acceleration or jerk. '''<nowiki><</nowiki>''axis''>.DecelerationRate''' may be modal or nodal.
 
 
'''Axis.JerkRate''' defines the axis Jerk maximum scaling factor from 0.1 to 100 persents independently of velocity, acceleration or deceleration. '''<nowiki><</nowiki>''axis''>.JerkRate''' may be modal or nodal.
 
 
For example:
 
<pre>
 
A1.VRate = 50 ‘ VelocityRate 50%
 
 
A1.ARate = 70 ‘ AccelerationRate 70%
 
 
A1.DRate = 80 ‘ AccelerationRate 80%
 
 
A1.JRate = 60 ‘ JerkRate 60%
 
</pre>
 
 
= Verify Settings =
 
Now, you can check the system using the MC '''MOVE''' command. This command is discussed in detail later. For right now, use it to verify some of the settings above. First, enable your drive.
 
 
== Enabling ==
 
Enable the drive with the following commands:
 
<pre>
 
System.Enable = ON
 
 
A1.Enable = ON
 
</pre>
 
After the SERCOS phase is set to 4, the drive can be enabled. This condition is indicated with an “S” on the front of each amplifier. You do this with MC command:
 
<pre>
 
Sercos.Phase = 4.
 
</pre>
 
The code to do this is normally generated in the BASIC Moves auto-setup program which runs each time you start a new project. A decimal point at the bottom-left of the S on the drive display should come on when the drive is enabled. The decimal point may flash under certain conditions.
 
 
You must turn on''' SYSTEM.ENABLE''' ('''SYS.EN''') before turning on any of the drive-enable properties. This is because when '''SYSTEM.ENABLE''' is off, it forces all the axis-enable properties off.
 
 
== Motion Flags ==
 
The next step in preparing a system for motion is turning on the motion flags. There are two motion flags that must be on: the system motion flag and the axis motion flag:
 
<pre>
 
System.Motion = ON
 
 
A1.Motion = ON
 
</pre>
 
== Move ==
 
Now you can perform a move command. For example, enter:
 
<pre>
 
Move A1 1000 VelocityCruise = 10
 
</pre>
 
to move to position 1000 with a velocity of 10. You should see the motor move. Use a hand tachometer or other speed sensing device to verify that the speed settings are correct. Move to various positions using the incremental move (by setting '''Absolute''' to OFF) and verify your position units:
 
<pre>
 
Move 1000 VelocityCruise = 10 Absolute = Off
 
</pre>
 
 
= SERCOS =
 
The MC uses the SERCOS fiber-optic ring network to communicate with the drives. The SERCOS interface ('''SE'''rial '''R'''ealtime '''CO'''mmunication '''S'''ystem) is an internationally recognized specification (IEC 1491), supported by many companies around the world. SERCOS replaces analog connections with digital, high-speed fiber-optic communication. MC supports 2/4/8/16 Mbit/s baud rate speeds. The SERCOS interface is selected because of numerous technical advantages:
 
 
'''Determinism'''SERCOS provides deterministic communication to all drives. The communication method provides complete synchronization between controller and axes, and among all axes.
 
 
'''International Standard'''SERCOS is the only digital communication method for motion control supported by an international body. It is the only standard with motion control products provided by a wide base of companies.
 
 
'''Reduced Wiring Between Drive And Controller'''SERCOS greatly reduces wiring between controller and drives. While analog and PWM amplifiers require 10 to 15 connections-per-drive, SERCOS requires only two fiber-optic cables between the controller and the drive.
 
 
'''Noise'''Because SERCOS is based on fiber optics, electromagnetic noise is greatly reduced. The controller is electrically isolated from drives and feedback devices, as well as from limit switches and other I/O wired through the drives. Most grounding and shielding problems, notorious for the difficulties they cause during installation of analog motion control systems, are eliminated.
 
 
'''Simplifying Replacement'''SERCOS allows you to download configuration parameters for all drives simultaneously via the SERCOS network. You can configure your system to automatically configure the drives after each power up. If a drive needs to be replaced, all re-configuration is automatically done.
 
 
'''Reliable Connections'''SERCOS uses fiber optic connections to eliminate the tens or even hundreds of hard-wired connections between the drives and the controller. This eliminates many possibilities for intermittent or reversed connections.
 
 
'''Access to Drive'''SERCOS provides complete access to drive data. For the drive, you can even record variables realtime in the drive and send the data via SERCOS to your PC using '''MOTIONLINK'''.
 
 
'''Axis Modularity'''SERCOS relies on the drive to connect to most external signals related to an individual drive: feedback device, limit switches, and registration sensors. When an axis is added to a system, most of the wiring associated with the axis connects directly to the drive. This minimizes the changes to system wiring required to support adding or removing drives.
 
 
== Communication Phases ==
 
In SERCOS, one master controller and many drives are connected with the fiber optic cable to form a communication ring.
 
 
[[Image:Axystems;UserManual-3121CommunicationPhases.png|caption]]
 
 
The master attempts to establish communication in a step-by-step process. This process is referred to as bringing up the ring. Each step is defined in SERCOS as a phase. In order to bring up the ring, the system must proceed successfully through five phases (0 through 4). The MC simplifies this process by allowing you to specify at which phase you want the ring. In most cases, you simply need to set the SERCOS property phase to 4. The main exception to this is when configuring telegram Type 7 to include external encoder data, which requires that you first set the phase to 2 and then to 4.
 
 
In phase 0, the master establishes synchronization by passing the '''M'''aster '''S'''ynchronization '''T'''elegram (MST) to the first drive. That drive passes it to the next and so on until it is returned to the master, indicating that the ring is complete. After the master determines that 10 MST telegrams have been passed through the ring, phase 0 is complete.
 
 
In '''phase 1''', the master sends the '''M'''aster '''D'''ata '''T'''elegram (MDT). Each drive is addressed individually and each drive responds with an '''A'''mplifier '''T'''elegram (AT). When all drives have responded, phase 1 is complete.
 
 
In '''phase 2''', all drives are configured through a series of IDNs. First, the communication parameters are sent. Then, the drives are configured for operation.
 
 
Up to this point, all data have been sent via the service channel. In '''phase 3''', the cyclic data channel is established. Configuration is completed and verified.
 
 
'''Phase 4''' is normal SERCOS operation.
 
 
SERCOS.PHASE automatically moves the SERCOS ring through each phase. You can observe this operation by watching the 7-Segment LED display on the drive. The number displayed indicates the current communication phase. When the process is complete, an S (or 5) is displayed, indicating that the ring is up and drives can be operated.
 
 
== Telegrams ==
 
All SERCOS data are organized into data packets called telegrams. Telegrams transport data and also provide protocol support and error checking. SERCOS provides three telegrams, which are issued in order:
 
 
*'''M'''aster '''S'''ynchronization '''T'''elegram (MST)
 
*'''A'''mplifier '''T'''elegram (AT)
 
*'''M'''aster '''D'''ata '''T'''elegram (MDT)
 
 
The first telegram in a communication cycle is the '''M'''aster '''S'''ynchronization '''T'''elegram (MST). The MST, issued by the controller. It provides a single mark in time for all the drives. All feedback and command data are synchronized for all axes via the MST.
 
 
Immediately after the MST is issued, each drive returns feedback and status data in the '''A'''mplifier '''T'''elegram (AT). This includes position and velocity feedback as well as responses to non-cyclic commands.
 
 
The final telegram in the communication cycle is the '''M'''aster '''D'''ata '''T'''elegram (MDT). The controller issues the MDT. It contains information transmitted from the MC, such as signals and position and velocity commands. The service channel sends signals as well as non-cyclic commands.
 
 
== Telegram Types ==
 
SERCOS provides for a variety of telegram types. Different telegram types define different sets of data to be exchanged in the AT and MDT. There are seven standard telegrams in SERCOS. The simplest telegram is Type 0, which defines only the service channel. No data are transferred in the cyclic data. The most complex type is Telegram Type 7, which allows the user to configure which data are in the cyclic data (all telegrams equally support the service channel.) The other telegrams (Types 1 through 6) define different combinations of position, velocity and current in the AT and MDT. The uses only Telegram Types 5 and 7 for data communication.
 
 
Normally, the relies on the SERCOS '''telegram type 5'''. In Telegram Type 5, position and velocity feedback are transmitted by the drive in the AT cyclic data, and position and velocity command are transmitted by the MC in the MDT cyclic data. These four components are the only motion data transmitted in the cyclic data. Telegram type 5 works well unless you need to have the external encoder position brought in with the cyclic data. This is necessary when you want to slave an axis to the external encoder In this case, you need to configure a Type 7 telegram.
 
 
When you need to bring an external encoder position from a drive to the MC in realtime (cyclic data) you must configure a '''telegram type 7''' for the drive. This telegram must contain all the motion data found in telegram type 5 (position and velocity in both the AT and MDT), with the external encoder position added.
 
 
To set up an axis for telegram type 7, you must modify the SERCOSSETUP subroutine, which is generated as part of the BASIC Moves auto setup program. You need to take the following steps:
 
 
Set '''SERCOS.PHASE''' to 0 and set the baud rateSet the axis '''PEXTFAC''' of the axis with external encoderSet the drive addresses ('''DRIVEADDRESS''')Set the axis '''MASTERSOURCE''', '''GEARRATIO''', and slave properties of the slave axisSet Sercos.Phase to 2Configure the axis for Telegram Type 7 using IDN 15Configure the AT for '''VFB''', '''PFB''', and '''PEXT''' (IDNs 40, 51, 53)Configure the MDT for '''VCMD''', '''PCMD''' (IDNs 36, 47)Set '''SERCOS.PHASE''' to 4
 
 
See SERCOS Setup Subroutine in Appendix A for a sample subroutine.
 
 
== Cyclic vs. Non-Cyclic Communication ==
 
SERCOS communicates across the fiber-optic ring with two types of data: cyclic and non-cyclic. Cyclic data are sometimes referred to as real-time, and are updated at a regular rate (SERCOS update rate). The system supports update rates from 1 millisecond. The MC requires that the cyclic data include position and velocity command (transmitted from the controller) and position and velocity feedback (transmitted from the drives.) These data must be updated once each SERCOS update.
 
 
Non-cyclic data are updated irregularly and on a demand basis via the service channel. The service channel is roughly equivalent to a 9600-baud serial link between the drives and the controller, except that it is transferred on the fiber optic cable along side the cyclic data. Using the service channel, you can request data from the drive or set a parameter that resides in the drive. Each drive has I/O points. You can use the service channel to access this I/O or you can use a Telegram type 7 to configure the I/O as cyclic data. The service channel is non-deterministic. Consequently, non-cyclic data transmits considerably slower than cyclic data.
 
 
== IDNs ==
 
SERCOS commands are organized according to an Identification Number or IDN. SERCOS defines hundreds of standard IDNs, which support configuration and operation. Manufacturers provide IDNs specific to their products. IDNs are numbered. Standard IDNs are from 1 to 32767 (although only several hundred are used to date) and manufacturer IDNs are numbered from 32768 to 65535.
 
 
If you are using a drive, you normally use only a few IDNs for special functions (e.g., for querying drive I/O or changing the peak current of a drive).
 
 
SERCOS requires that you define every IDN used on each drive. The system eliminates most of this step because the MC automatically defines all necessary IDNs for drives. This process would otherwise be tedious as there are quite a few IDNs that must be defined.
 
 
Most requests from the service channel are responded to immediately. For example, when you set the digital-to-analog converter (DAC) on the drive, the value is placed in the DAC by the drive immediately upon receipt. The drive acknowledges the command almost as soon as it is received, thereby freeing the service channel for subsequent commands. However, some functions of the drive that are accessed from the service channel require a much longer time for execution. For example, incremental encoder-based systems must be oriented on power up. The wait for verification that the process has completed successfully can take many SERCOS cycles, far too long to tie up the service channel. To support these functions, SERCOS developed procedures.
 
 
With procedures, the master starts a procedure and optionally halts and restarts it. Procedures allow processing in the service channel without blocking other communication. For example, waiting for a registration mark is a procedure. In this case, the motor is turning and the drive is searching for a registration mark. By using a procedure, the service channel remains available for other communication during the search.
 
 
== Position and Velocity Commands ==
 
The MC sends position and velocity commands in the cyclic data, and drives return position and velocity feedback in the cyclic data. This allows you to configure your system as a position or a velocity loop. It also allows you to switch between position and velocity loop on-the-fly. The format of each data type is shown below:
 
 
 
{| style="border-spacing:0;"
 
| style="border-top:0.039cm double #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding:0cm;"| <center>'''Signal'''</center>
 
| style="border-top:0.039cm double #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:none;padding:0cm;"| <center>'''Size'''</center>
 
| style="border-top:0.039cm double #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding:0cm;"| <center>'''Scale'''</center>
 
 
|-
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding:0cm;"| Position Command
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:none;padding:0cm;"| 32 Bit
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding:0cm;"| One count
 
 
|-
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding:0cm;"| Position Feedback
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:none;padding:0cm;"| 32 Bit
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding:0cm;"| One count
 
 
|-
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding:0cm;"| Velocity Command
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:none;padding:0cm;"| 32 Bit
 
| style="border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding:0cm;"| 1/256 count per SERCOS update
 
 
|-
 
| style="border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.039cm double #000000;border-right:none;padding:0cm;"| Velocity Feedback
 
| style="border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.018cm solid #000000;border-right:none;padding:0cm;"| 32 Bit
 
| style="border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding:0cm;"| 1/256 count per SERCOS update
 
 
|}
 
== SERCOS Support ==
 
The MC provides numerous commands within the language to support SERCOS.
 
 
'''Sercos.Baudrate for SERCON 410B:'''
 
 
The SERCOS baud rate is set to 2 (2MBits/sec) or 4 (4MBits/sec). The baud rates of all drives must be the same. To control the baud rate on the drive, find the 10-position DIP switch on top of the drive and set the switches according to the following:
 
 
'''Baud rate Sercos.Baudrate Drive, Switch 6'''2 MBits/sec 2 Off4 MBits/sec 4 On
 
 
'''Sercos.Baudrate for SERCON 816:'''
 
 
The SERCOS baud rate is set to 2 (2 M bits/sec) / 4 (4 M bits/sec) / 8 (8 M bits/sec) or 16 (16 M bits/sec). The baud rates of all drives must be the same. To control the baud rate on the drive, find the 10-position DIP switch on top of the drive and set the switches according to the following:
 
 
'''Baud rate''' '''Sercos.Baudrate''' '''Drive, Switch 6''' '''Drive, Switch 10 '''2 M bits/sec 2 Off Off 4 M bits/sec 4 On Off
 
 
8 M bits/sec 8 Off On
 
 
16 M bits/sec 16 On On
 
 
Remember that DIP Switch-6 and DIP Switch-10 are read by the drive only on power up. If you change DIP switch-6 or DIP Switch-10, you must cycle power on the drive. Some versions of drives exists SERCON816, but in compatible mode – in this case it equals to SERCON 410B. For checking drive sercon version and mode see drive product number.
 
 
For the current SERCON version, query from the terminal with:? System.SERCONversion. It returns:
 
 
*2 For SERCON 410B Version or
 
*16 For SERCON 816 Version
 
 
'''Sercos.CycleTime''' is used to either set or query the SERCOS communications cycle time - rate of updating cyclic data (rate with which to the desired phase of communication (see Cyclic vs. Non-Cyclic Communication). This property is only set in SERCOS communication phases 0, 1, and 2, transferred from the MC to drives during phase 2 and becomes active in phase 3.
 
<pre>
 
sercos.cycletime = 2000
 
 
? sercos.cycletime
 
</pre>
 
'''Sercos.NumberAxes''' is used for querying the actual number of SERCOS drives detected on the ring. This value is generated during communication phase 1, when the SERCOS driver scans the ring for drives (or when the the drive addresses are explicitly set)
 
<pre>
 
? sercos.numberaxes
 
</pre>
 
'''Sercos.Power''' is used to set or query the SERCOS transmission power. The transmission power is governed by the SERCON interface chip and is set to one of six levels. Setting the power level too high drives the fiber-optic receiver into saturation and causes communication errors. This value should not have to change unless a very long cable is being used (>10 meters). Level 6 is the highest power.
 
<pre>
 
Sercos.power = 3
 
 
? sercos.power
 
</pre>
 
'''Sercos.Scan''' indicates to the SERCOS driver whether to scan the ring for drives. If the property is set to a value greater than 0, the ring is scanned during communication phase 1. The scan value indicates the highest drive address for which to scan. For example, if the value is set to 5, the ring is scanned for drives at addresses up to 5.
 
<pre>
 
Sercos.scan = 0 ‘Do not scan the ring
 
 
Sercos.scan = 5 ‘Scan for drives up to address 5
 
</pre>
 
Set '''SERCOS.PHASE''' to the desired phase of communication (see Enabling and Communication Phases). Normally, the command stream outlined in the procedure below is sufficient to bring up the ring. Because it takes time to bring up the SERCOS ring, you may want to speed the process by changing the phase only when it is at some phase other than 4.
 
 
Most IDNs have numeric values. After these IDNs are defined, you can read their values with '''IDNVALUE'''. To do this, you must specify the drive address, IDN, and the IDN element. For example, you can enter:
 
<pre>
 
? IDNValue{5, 104, 7}
 
</pre>
 
This lists the value of IDN 104, element 7, for the drive at address 5. '''IDNVALUE''' is only executed in SERCOS communication phases 3 and 4 as cyclic data, or in phases 2, 3, or 4 via the service channel (some restrictions apply for writing to an IDN). For a complete listing of IDNs supported by the drive, refer to the ''MC Installation Manual''.
 
 
IDNs have numeric values and you can write to most of them with the '''WRITEIDNVALUE''' command. To do this, specify the drive address, IDN and the value. For example, you can enter:
 
<pre>
 
WriteIDNValue Drive = 5 IDN = 104 value=1
 
</pre>
 
which sets the position loop gain (IDN 104) of drive 5 to 1. '''WRITEIDNVALUE''' is executed only in SERCOS communication phases 2, 3 and 4.
 
 
Some IDNs have alpha-numeric string values. After these IDNs are defined, you can read the string values with '''READIDNSTRING'''. Specify the drive address, IDN, and IDN element. For example, you can enter:
 
<pre>
 
? IDNString(5, 104, 7)
 
</pre>
 
'''IDNSTRING''' is used only in SERCOS communication phases 2, 3 and 4.
 
 
Some IDNs have alpha-numeric string values. After these IDNs are defined, you can write new string values to most of them with '''WRITEIDNSTRING'''. Specify the drive address, IDN and the value. For example, you can enter:
 
<pre>
 
WriteIDNString Drive = 5 IDN = 104 Element = 7
 
 
String = IDN String
 
</pre>
 
'''WRITEIDNSTRING''' is executed only in SERCOS communication phases 2, 3 and 4.
 
 
'''IDNState''' returns the state of a specified procedure command from a specified drive. It is used when executing a procedure command to determine progress of that procedure’s execution. Common procedures are 99 (clear faults) and 148 (drive-controlled homing).For example, you can enter:
 
<pre>
 
‘Check how procedure terminated
 
 
<nowiki>If IdnState(a1.dadd, 99) <> 3 Then
 
 
</nowiki> Print “Reset Faults procedure failed”
 
 
End If
 
</pre>
 
''For more information about states of this property, refer to the MC Reference Manual.''
 
 
Use '''MOTIONLINK''' to configure and operate the drive. The parameters are stored in the drive, but not in the controller. So, if you need to replace a drive in the field, you must reconfigure that drive with '''MOTIONLINK'''.
 
 
One benefit of SERCOS is that it allows you to download all drive parameters via the SERCOS link each time you power up. If you need to replace a drive, you do not need to configure it with '''MOTIONLINK'''. This is a significant advantage when maintenance people unfamiliar with the design of the system do drive replacement. For this reason, <s>Danaher Motion</s> recommends that you configure your systems to download all parameters on power up. BASIC Moves provides a utility that reads all pertinent IDNs after the unit is configured and the ring is up and stores them in a task you automatically download each power up.
 
 
= Loops =
 
The system supports three main loop types:
 
 
Standard position loop
 
 
Dual-feedback position loop
 
 
Velocity loop
 
 
The MC sends position and velocity commands each SERCOS update cycle. The operation of the MC is hardly affected by the loop selection because the loop selection is made in the drive.
 
 
== Standard Position Loop ==
 
Position loop is the standard operating mode of the system. For position operation, set the position loop gain to a value greater than zero. Typically, you set up the position loop using '''MOTIONLINK'''. See the ''MC Installation Manual'' for more information.
 
 
== Dual-feedback Position Loop ==
 
Dual-feedback position loop compensates for non-linearity in mechanical systems (inaccuracy from gears, belt drives, or lead screws, or backlash from gears and lead screws). Dual-feedback position loop adds a second feedback sensor (usually a linear encoder) to the system so the load position is directly determined. Unfortunately, the load sensor cannot be the sole feedback sensor in most systems. Relying wholly on the load sensor usually causes machine resonance that severely affects system response. Dual-feedback position loop forms a compromise: uses the load sensor for position feedback (accuracy is critical) and uses the motor sensor for velocity feedback (low compliance required). This is the dual-feedback position loop shown below.
 
 
[[Image:Axystems;UserManual-3132Dual-feedbackPositionLoop.png|caption]]
 
 
The additional hardware for dual-feedback position loop is a second encoder connected to the drive which is running dual-feedback position loop. You configure the drive for dual-feedback position loop operation using '''MOTIONLINK'''. See the ''MC Installation Manual ''for more information. The MC does not close the servo loops and is not directly involved in dual-feedback position loop operation. In a sense, the MC is not aware that the drive is operating in dual-feedback position loop. However, when setting up the feedback system, you must configure your units for the external encoder, not the motor feedback device. In addition, you must also tell the MC to monitor the external encoder for position error. This is done with '''''<nowiki><axis></nowiki>''.FEEDBACK'''. For example:
 
<pre>
 
A1.Feedback = External 'Set the axis feedback to the load
 
</pre>
 
== Velocity Loop ==
 
For some applications, the motor must be under velocity loop control. Maintaining a position is not important. The advantage is that the motor is more responsive (typically 3 to 5 times faster in settling time). When you configure an axis for velocity loop, you more or less fool the drive by setting gains to disable the position loop. You need to set the position loop gain to zero and the feed-forward gain to 100%. This produces the following servo loop:
 
 
[[Image:Axystems;UserManual-3133VelocityLoop.png|caption]]
 
 
Since a lot of position error can accumulate in velocity loop, it is best to configure the system to have such a large maximum position error that it never realistically generates an error.
 
 
= Simulated Axes =
 
A simulated axis is an axis that exists only inside the MC. Simulated axes have most of the functions of physical axes including profile generators, units, position and velocity commands and feedback signals, and limits. However, simulated axes do not include a drive, motor or feedback device.
 
 
An axis can only be configured as a simulated axis during Sercos.Phase 0 or before SERCOS configuration takes place in CONFIG.PRG or AUTOEXEC.PRG. To set up a simulated axis, set the axis property '''SIMULATED''' to ON:
 
<pre>
 
A1.Simulated = ON
 
</pre>
 
This step is inserted in the BASIC Moves auto setup program, in the subroutine, SercosSetup, just after the phase is set to zero. See SERCOS Setup Subroutine in Appendix A for additional details.
 
 
Simulated axes require about the same amount of resources from the MC, as physical axes. As a result, simulated axes are part of the total axis count of the controller. For example, a system with three physical axes and one simulated axis requires a four-axis MC. Simulated axes are used in the MC in the same way as physical axes. They are profiled with '''JOG''' and '''MOVE''', can be geared and cammed, and can act as masters for geared and cammed axes. Variables from simulated axes such as position feedback can be used to generate events. During operation, the feedback position and velocity are set to their respective command values.
 
 
Although most commands and variables for axes work for simulated axes, there are some exceptions. Simulated axes cannot receive SERCOS commands. You cannot set drive variables such as position loop gains in simulated axes.
 
 
The units on a simulated axis are flexible. The simplest way to set the units is to set PFAC=1, which can be thought of as 1 simulated unit (eg, 1 meter, 1 inch). Set '''VFAC '''to PFAC/1000 for units-per-second or set to PFAC/60000 for units-per-minute such as rpm. Set '''AFAC''' to VFAC/1000, such as meters-per-second<sup>2</sup>. Most axis properties do work with simulated axes, including:
 
 
Position properties: command, feedback, finalVelocity properties: command, feedback, cruise, maximumAcceleration and decelerationAcceleration maximum and deceleration maximum
 
 
In addition, you can move, jog, gear, and cam simulated axes. The following axis properties do not work with simulated axes:
 
  
Position error and velocity error (assume to be zero)Velocity OverspeedTuning parametersExternal position and velocity
 
  
[[Category:Axystems:UserManual]]
+
[[Category:MC-Basic|Programs]]

Latest revision as of 09:04, 8 August 2017

IMPORTANT.svgIMPORTANT
This entry is outdated and requires revision.

TOP2.png

Introduction

A project is all the software written for an application. The projects in MC-Basic are multitasking. They consist of many tasks running concurrently and independently of each other. The project is stored in multiple files, one file for each task. Tasks are routines that run simultaneously with many other tasks. Projects also include other files such as cam tables and record files. Projects are controlled from the ControlStudio software.

ControlStudio manages projects and handles a group of logically coupled files (programs, cam tables, etc.), while the softMC deals with separate files (PRG, CAM, etc.). The softMC does not keep project files in the flash memory and is not aware of logical coupling of files and programs.

ControlStudio automatically sets up a separate directory for each project.

Project Structure

Project files include tasks and cam tables.

Each project can contain three types of tasks:

  • General-purpose task
  • An optional configuration task (Config.Prg) to declare groups, programmable limit switches (PLS), cams, global variables and load of global libraries.
  • An optional autoexec task (Autoexec.Prg) to automatically start the application on power-up.

caption

Tasks

The three types of tasks are general-purpose tasks, configuration tasks, and autoexec tasks. Each type of task is outlined below.

General Purpose Tasks

General-purpose tasks are the workhorse of the softMC language. They implement the basic logic of your application. The great majority of your programming is implemented with general-purpose tasks. Each general-purpose task is divided into three sections: a task-variable section, a main program, and subroutines. The main program is further divided into three sections: a Start-up section, an OnError section, and an OnEvent section.

caption

A task-variable definition sectionThe task-variable definition section, where all task variables are declared with the Dim…Shared command.

The main programMost programming is done in the main programming section. The main programming section falls between the Program…End Program keywords. The main program itself has three sub-sections:

The Start-up sectionThe start-up section immediately follows the Program keyword. This is where task execution begins when you start a task.

OnError sectionThe OnError section responds to errors generated by the task, allowing your program to automatically respond to error conditions and (where possible), gracefully recover and restart the machine. There is (at most) one OnError section for each task and it is normally written just before the OnEvent section.

OnEvent sectionThis section contains optional blocks of code that respond to realtime changes, such as a motor position changing or an input switch turning on. The main program can contain code to automatically respond to events. This reduces the effort required to make tasks respond quickly and easily to realtime events.

Event handlers begin with the OnEvent and end with End OnEvent keywords. One OnEvent…End OnEven keyword combination is required for each realtime event. Event handlers must be contained wholly within the main program.

Optional subroutinesEach task can have any number of subroutines. Subroutines are component parts of the task, and consequently, they can only be called from within the task. If you want to call the same subroutine from two tasks, place one copy in each task.

Configuration Task

The name of the configuration task is Config.Prg. The configuration task is used for declaration of number of axes, global variables and other constructs, such as cam tables, programmable limit switches (PLS), and group. The key to understanding the configuration task is that all data and constructs shared across tasks must be declared in the configuration task. Refer to the following figure.

caption

The configuration task can contain a program. Axes can be renamed here.

AutoExec Task

The AutoExec task (AutoExec.Prg) is executed once on power up, just after the Configuration Task. Use AutoExec to start power-up logic. For example, you might want to use AutoExec to start a task that sets the outputs to the desired starting values. That way, the outputs are set immediately after the softMC boots, usually sooner than the PC.

For safety considerations we do not recommend starting of motion from the AutoExec task. Motion should be started by explicit operator’s request either by I/O or communication link from host PC.

Set the AutoExec task to run on power up. To do this, add the keyword Continue to the Program command. Do not include OnError or OnEvent sections in the AutoExec. Limit the AutoExec task to starting other tasks in the system. Refer to the next figure.

caption

Program Declarations

You must declare the start of programs and subroutines. For programs, use the Program…End Program keywords. Use Sub…End Sub keywords for subroutines.

The Program…End Program keywords mark the boundary between the variable declaration section and the main program. Each task must have only one Program keyword and end with the End Program keyword.

Program ‘Standard form of program command

 <code for program>

End Program

The AutoExec task, which must be loaded and run automatically at power-up must have CONTINUE following Program.

You pass parameters (either scalar or array) to the subroutine, which can then be used in the code of the subroutine. In the declaration line for the subroutine (SUB<name>), you declare the variable names and types of the parameters to pass. Parameters are passed either by reference or by value (ByVal). The default method is to pass parameters by reference. Arrays are passed only by reference. When you pass a variable (whether the variable is local to the task or is global) by reference, you pass the address of the variable to the subroutine, which changes the value of the variable (if the code of the subroutine is written to do this). When you pass a variable by value (ByVal) a copy of the value of the local variable is passed to the subroutine. The subroutine cannot change the value of the local variable. The syntax for defining a subroutine is:

SUB <name> ({{ByVal} <p_1> as <type_1> }…{, {ByVal} <p_n> as type_n>})

{ local variable declaration }

{ subroutine code }

END SUB

There is no explicit limit on the number of subroutines allowed in a task. All subroutines must be located following the main program, and must be contained wholly outside the main program. Subroutines can only be called from within the task where they reside. Subroutines may be recursive (call itself).

Use CALL to execute a subroutine:

CALL <subroutine>({<p_1>...<p_n>})

where:

<subroutine> is the name of the subroutine<p_1>...<p_n> are the subroutine parameters

Parentheses are not used in a subroutine if no parameters are passed.

MC-Basic automatically checks the type of compliance between the subroutine declaration and the subroutine call. Any type mismatch causes an error during program loading. Automatic casting applies to numeric variables types. For example, suppose MySub is a subroutine that takes a Long parameter. In this case, the following scenario applies:

CALL MySub(3.3432)
'OK: The double value 3.3432 is demoted to the Long value, 3
CALL MySub(a)
'Error: a is a string, there is a type mismatch
Call MySub(3,4)
'Error: The number of parameters is not correct

See the Subroutine Example in Appendix A for further details.

Subroutines

Parameters (either scalar or array) passed to the subroutine are used within the code of the subroutine. The declaration line for the subroutine (SUB<name>) is used to declare names and types of the parameters to pass.

Parameters are passed either by reference or by value (ByVal). The default method is to pass parameters by reference. Whole arrays are passed only by reference. Trying to pass a whole array by value results in a translation error. However, array elements can be passed both by reference and by value. The syntax for a subroutine is:

SUB <name> ({<par_1>([*])+ as <type_1>}…{, <par_n>([*])+ as<type_n>})

END SUB

<par_l>: name of array variable

<par_n>: name of array variable

[*]: dimension of an array without specifying the bounds

+: means one or more [*]


SUB CalculateMean(x[*][*] as DOUBLE, TheMean[*] as LONG)
DIM sum as DOUBLE
DIM I as LONG
FOR i = 1 to 100
sum = sum + x[i][1]
NEXT i
TheMean[1] = sum/100
END SUB

SUB PrintMean(ByVal Mean as LONG)
PRINT “Mean Value Is “, Mean
END SUB
CALL CalculateMean(XArray, TheMeanArray) ‘ Pass entire array by reference
CALL PrintMean(TheMeanArray[1]) ‘ Pass a single array element by value

When a variable is passed by reference (whether the variable is local to the task or global), the address of the variable is passed to the subroutine, which changes the value of the original variable (if the code of the subroutine is written to do this).

When a variable is passed by value (ByVal) a local copy of the value of the variable is passed to the subroutine, and the subroutine cannot change the value of the original variable.

There is no explicit limit on the number of subroutines allowed in a task. All subroutines must be located following the main program and must be contained wholly outside the main program. Subroutines can only be called from within the task where they reside. Subroutines may be recursive (can call itself). Use CALL to execute a subroutine with the following syntax:

CALL <subroutine_name>{(<par_1>{, …<par_n>})}

Parentheses are not used in subroutine CALL if no parameters are passed.

MC-Basic automatically checks the type of compliance between the subroutine declaration and the subroutine call. Any mismatch (in number of parameters or parameters types) causes an error during program loading. Automatic type casting applies only for “by value” long and double parameters.

SUB MySub(RefPar as long, byval ValPar as double)
…
END SUB
CALL MySub(LongVar, “String”) -> type mismatch in second parameter
CALL MySub(LongVar) -> wrong number of parameters
CALL MySub(LongVar, 2) -> a valid type casting for a by-value parameter
CALL MySub(DoubleVar, 2.2) -> invalid type casting for a by-ref parameter

User-Defined Functions

MC-Basic allows the definition of user functions to be used in programs in the same manner as using BASIC pre-defined functions. User-defined functions are composed with multiple lines and may be recursive (can call itself). Unlike BASIC system functions, the scope of user-defined functions is limited to the task in which it is defined.

Functions are different from subroutines in one respect. Functions always return a value to the task that called the function. Otherwise, functions and subroutines use the same syntax and follow the same rules of application and behavior.

Because functions return a value, function calls should be treated as expressions. Therefore, function called can be combined within print commands, assignment statements, mathematical operations and conditions of flow control statements. They can also be passed as by-value parameters of system or user-defined functions and subroutines.

PRINT <function_name>{(<par_1>{, …<par_n>})}
<variable_name> = <function_name>{(<par_1>{, …<par_n>})}
IF <function_name>{(<par_1>{, …<par_n>})} > 10 THEN
? LOG( <function_name>{(<par_1>{, …<par_n>})} )

Parentheses are not used in function CALL if no parameters are passed. Parameters (either scalar or array) passed to the function are used within the code of the function. Declare variable names and types of parameters in the declaration line of the function. Parameters can be passed by reference or by value. The default is by reference.

Arrays can only be passed by reference. Trying to pass a whole array by value results in a translation error. On the other hand, array elements can be passed by reference and by value.

To set up the return value, assign the return value to a virtual local variable with the same name as the function somewhere within the code of the function. This local variable is declared automatically during function declaration and the function uses it to obtain the return value.

There is no explicit limit on the number of functions allowed in a task. All functions must be located following the main program and must be contained wholly outside of the main program.

MC-Basic automatically checks the type of compliance between the function declaration and the function call. Any mismatch (in number of parameters, in parameters and returned value types) causes an error during program loading. Automatic type casting applies only for long and double returned values and “by value” parameters. For example:

Function LongReturnFunc(…) As Long
LongReturnFunc = “String” -> type mismatch in returned value
End Function

Function LongReturnFunc(…) As Long
LongReturnFunc = 43.7 -> valid type casting in returned value
End Function

A function can be recursive (can call itself). The following example defines a recursive function to calculate the value of N:

FUNCTION Factorial (ByVal N As Long) As Double
'By declaring N to be long, this truncates floating point numbers
'to integers
'The function returns a Double value
If N < 3 then 'This statement stops the recursion
Factorial = N '0!=0; 1!=1' 2!=2
Else
Factorial=N * Factorial(N-1) 'Recursive statement
End If
END FUNCTION

When writing a recursive function, you must have an IF statement to force the function to return without the recursive call being executed. Otherwise, the function never returns once it is called.

Arrays

Arrays can only be passed by reference. If a user tries to pass a whole array by value, the translator gives an error. Array syntax is:

SUB <name> ({<p_1>([*])+ as <type_1>}…{, <p_n>([*])+ as <type_n>})

{ local variable declaration }

{ subroutine code }

END SUB

where

<p_l> : name of array variable

<p_n> : name of array variable

[*] : dimension of array without specifying the bounds

+ : means one or more

Syntax example:

SUB mean(x[*][*] as DOUBLE, TheMean[*] as LONG)
DIM sum as DOUBLE
DIM I as LONG
FOR i = 1 to 100
sum = sum + x[i][1]
NEXT i
TheMean[1] = sum/100
END SUB

Multitasking

The softMC supports multitasking. You can have multiple tasks running independently, sharing a single computer. A task is a section of code that runs in its own context. Microsoft Windows is a multitasking system. If you open Explorer and Word at the same time, they run nearly independently of each another.

In this case, both Explorer and Word have their own contexts. They share one computer, but run as if the other were not present. There is inter-task communication. If you double-click on a document in the file manager, it launches Word to edit the file you clicked.

With MC-Basic, you can use different tasks to control different operational modes: one for power up, one for set-up, one for normal operation, and another for when problems occur. Like Windows, each task can run independently of the others, and you can prescribe interactions between tasks.

Multitasking is used when you want multiple processes to run largely independent of each other. For example, if you are using the softMC to interface to the operator, you will usually use a separate task to execute the interface code. Another example is when two parts of a machine are largely independent of each other. There is usually some control required between tasks as one task may start or stop another.

If a machine is simple to control, you should try to keep the entire program in one task (in addition to Config.Prg). If you do need to use multitasking, you should keep a highly structured architecture. It is recommended that you limit use of the main task for axis and group set up, machine initialization, and controlling the other tasks. Normal machine operation should be programmed in other tasks. For example, Main.Prg might be limited to setting up axes, and then starting Pump.Prg, Conveyor.Prg, and Operator.Prg.

Do not split control of an axis or group across tasks. You can put control for multiple axes in one task. Ideally, you should use multiple tasks for machines where different sections operate more or less independently. You can also use tasks to implement different operational modes.

Multitasking is a powerful tool, but it carries a cost. It is easy to make errors that are difficult to find. When multiple tasks are running concurrently, complex interaction is difficult to understand and recreate. Limit the use of tasks to situations where they are needed.

Do not create a task as a substitute for an event handler. Events and tasks are not the same. MC-Basic supports event handlers to respond to realtime events. Events are similar to interrupts in microprocessor systems. They normally run at higher priorities than the programs that contain them. They are ideal for quick responses to realtime events. Add the event handler to an existing task to respond to an event.

Do not use tasks in place of subroutines. Remember that when you start a task, the original task continues to run. When you call a subroutine, you expect the calling program to suspend execution until the subroutine is complete. The behavior of tasks where the two routines continue to execute can cause complex problems.

Knowing when to use multitasking and when to avoid it requires some experience. If you are new to multitasking, you may want to start slow until you are familiar with how it affects program structure. When you start a new project, ControlStudio creates the main task as part of opening a new project. After that process is complete, you can add a new task to your project by selecting File, New. You can also press the new task button on the ControlStudio tool bar.

Loading the Program

ControlStudio automatically loads all tasks in your project when you select Run Project. You can select Run Project by selecting it from the Debug menu, by pressing the F5 key, or by pressing the “Load Task”and “Run Task” buttons on the tool bar. By default, tasks are loaded from the host PC to the softMC at a low priority (Priority = 16).

When you select Run Task, the project’s main task is started at the lowest priority (Priority = 16). You can change the priority of the main task by selecting View-> Project Manager->Options and then changing the priority in the bottom of the window. If you structure your software so that the main program loads all other tasks, the Run Project button starts your machine.

Preemptive Multitasking & Priority Levels

Because many tasks share one processor, you must carefully design your system so tasks get processing resources when they need them. You do not want the operator interface taking all the resources when you need fast response to a realtime event. The operating system provides system resources based on two criteria: task priority level and time slice.

When you create a program, you must select the task priority level. MC-Basic allows you to specify 16 levels of priority. The task with the highest priority takes all the system resources it can use. In fact, no task of a lower priority receives any resources until all tasks of higher priority relinquish them. Most systems have one main task that runs at a medium priority and perhaps a background task that runs at a low priority, with a few high priority tasks. At every time slice, the softMC reevaluates which task has the highest priority and assigns resources to it.

The ControlStudio terminal window relies on the softMC command line task, which runs at priority 2. If you start a task with priority 1, the terminal will not be available until the task is complete or idle. Consequently, you will not be able to communicate with the softMC and you may have to power-down the system to recover the terminal window. You can optionally set the priority of a task when you start it. For example:

StartTask Aux.Prg Priority=6

The default priority of events is 1 (highest) and the default priority of programs is 16.

Time Slice is a method by which the operating system divides up resources when multiple tasks share the same priority level. The softMC provides the first task with one time slice, the next time slice goes to the second, the next to the third, and so on. The time slice is currently one millisecond duration. This method is sometimes called round robin scheduling.

Inter-Task Communications and Control

Tasks can control one-another. In fact, any task can start, continue, idle, or kill any other task, regardless of which task has the higher priority. For detailed information on these commands, refer to the Reference Manual.

StartTask starts tasks from the main task. For testing, you can use STARTTASK from the terminal window. Do not use STARTTASK in AutoExec.Prg. The syntax of STARTTASK is:

StartTask <TaskName> {Priority = <Level>}{NumberOfLoops = <Loop Count>}

NOTE-Info.svgNOTE
NOL is a short form for NumberOfLoops.

where:

<Level> is a long with value between 1 and 16. If <Level> is not entered, it defaults to 16, the lowest priority. Priority = 1 is the highest priority.

<Loop Count> is either -1 (indicating unlimited number of loops) or between 1 and 32768 indicating the number of times the task is executed. If <Loop Count> is not entered, it defaults to 1.

For example:

StartTask Task1.Prg Priority=8 NumberOfLoops = -1 'Run Task1 forever
StartTask Main.Prg NOL=1 'Run Main once

IdleTask stops the task at the end of the line currently being executed and idles all its events. An idled task can be continued (using CONTINUETASK) or terminated (using KILLTASK). IDLETASK does not stop motion currently being executed. This is significant because all the events are idled and cannot respond to an axis' motion. Tasks can be idled explicitly by other tasks, but cannot idel itself. This command is issued from a task or the terminal window. The syntax of IdleTask is:

IdleTask <TaskName>

For example:

IdleTask TASK1.PRG

Tasks that have been idled with IDLETASK are restarted only with CONTINUETASK. The command continues an idled task from the point at which it was stopped, or continues task execution after a break point has been reached. It is frequently used to restart tasks from the ONERROR error handler. If a run time error has occured, CONTINUETASK retries the line which caused the error. The error must be corrected before the task continues. This command is issued from any task or the terminal window. The syntax of ContinueTask is:

ContinueTask <TaskName>

For example:

ContinueTask TASK1.PRG

KillTask aborts the execution of a task. The program pointer is left on the line at which the task was stopped. The first action of KILLTASK is to kill and delete all events associated with the task. This is done to ensure that no event initiates an action after KILLTASK was executed. KILLTASK is issued from the terminal window. The syntax of the KillTask is:

KillTask <TaskName>

For example:

KillTask TASK1.PRG

Monitoring Tasks From the Terminal

For detailed information on these commands, refer to the Reference Manual.

TASK.STATUS provides the current state of any task. You can query TASK.STATE from the terminal window. You cannot use TASK.STATUS from within a program. The syntax for TASK.STATUS is:

? <TaskName>.Status

For example:

? TASK1.PRG.Status

TASKLIST returns the state and priority of all tasks loaded in the system. You can query TASKLIST only from the terminal window.

For example, if you type:

? TaskList

A typical result is:

TaskName = TASK1.PRG, Status = sstep, Priority=16
TaskName = DO.PRG, Status = suspend, Priority=4

Relinquishing Resources

When tasks of different priorities compete for processor time, the highest priority task always takes all the resources it needs. However, tasks of high priority can relinquish computer resources under some conditions. In these cases, tasks of lower priority run until the high priority tasks again demand the resources. There are three conditions under which a task relinquishes resources: when the task is terminated, when the task is suspended, or when the task is idled. For detailed information on these commands, refer to the Reference Manual.

A task terminates when it is finished executing. If a task starts with NUMBEROFLOOPS greater than zero, the task executes the specified number of times and terminates. The task relinquishes all resources. Terminated tasks remain loaded in the system and can be restarted.

One task can terminate another task by issuing KILLTASK. A task relinquishes all resources after the kill command. Killed tasks remain in the system and can be restarted.

Tasks relinquish processing resources temporarily when they are suspended. A task is suspended when it is waiting for a resource or is delayed. Suspended tasks still monitor events as long as the event priority is higher than the task priority. Never run a task at a higher priority level than any of its events.

Use SLEEP to delay a task for a specific period of time. This command can only be issued from within the task. One task cannot issue a SLEEP for another task. SLEEP causes the task to relinquish resources until the sleep time has expired.

Idled tasks relinquish resources. In this case, resources are relinquished until another task revokes the idle by issuing a CONTINUETASK.

Delete Task/Library deletes a file from the Flash Disk. Only filesnot loaded into RAM can be deleted.Files that are protected by a password may not be deleted. For example:

Delete FILE1.PRG

Event Handler

The main program can contain sections which automatically handle events. This reduces the programming effort required to make tasks respond quickly and easily to realtime events. Event handlers begin with OnEvent and end with End OnEvent and occur just after the Program keyword.

After OnEvent is loaded, turn the event On with EventOn just after the End OnEvent keyword (enable immediately). However, you can enable and disable OnEvent at any time using EventOn and EventOff. Multiple OnEvents can be written sequentially. The softMC system can support up to 64 events. The number of OnEvent(s) in a single task is not restricted, so a task may have from 0 to 64 OnEvent(s).

It is important to understand that OnEvents are different from ordinary tasks. OnEvents are preemptive within the task. That is, an OnEvent runs until complete and the program execution returns to the main program. While an OnEvent is executing, it does not release CPU time to the parent task or any other task. In this sense, OnEvents are similar to interrupt calls. They run to completion before execution returns to the main program. An OnEvent must have a higher priority than its parent task to ensure that when an event occurs, it interrupts its parent task and runs to completion. The rules are valid for a single process, (that is, the parent task and its events), while events of the respective tasks in the system share the CPU among themselves.

OnEvent

The syntax of OnEvent is:

OnEvent [EventName] [Condition] {Priority=EventPriority}{ScanTime=time}

where

EventName is any legal name that is otherwise not used in the task.

Condition is any logical expression such as System.Dout.1 = 1. The event fires on transitions of the condition from false to true.

Priority is an integer from 1 (highest) to 16 (lowest). If not entered, priority defaults to 1. The priority should always be higher than the priority of the task or the event never runs.

Time is an integer indicating the number of cycles between each scan. Time defaults to 1.

In this example, an event is set up to move axis "X-axis" to 10000 counts each time an input goes high:

OnEvent MOVE_ON_TRIGGER System.Din.1=ON
Move X-axis 10000
End OnEvent

Normally, event handlers run at a high priority so that once the event occurs, they run to completion. In most cases, this code should be very short as it usually takes all resources until it is complete.

ScanTime is in cycles of the SERCOS update rate. This is normally 2 or 4 milliseconds. Setting ScanTime to 5 configures the system to check the event condition every 10 or 20 milliseconds, depending on your update rate. For example:

OnEvent System.Din.2 = ON ScanTime = 5

Events can either be controlled from within the task in which they reside, or from the terminal. The main program or any subroutine can issue EventOn (to enable the OnEvent command) or EventOff (to disable it). OnEvents cannot be controlled from other tasks.

EventOn

EventOn enables OnEvent. The syntax of EventOn is:

EventOn [Event Name]

EventOn must come after the definition of the OnEvent.

EventOff

EventOff disables OnEvent. The syntax of EventOff is:

EventOff [Event Name]

Refer to the MC Reference Manual for information additional information about OnEvent, EventOn, and EventOff.

EventList

EventList provides a complete list of all events in all tasks with their name, the task name, the priority, whether the event is armed, and current status. EventList is valid only from the terminal window. For example:

? EventList

the result is something like the following line for each task:

Name = IOEvent Owner=Task1 Edge=1 Status=1 Scan=1 Priority=5 Action = Stop

where:

edge=1 indicates the event is armed (that is, the condition is false so that the condition becoming true will fire the OnEvent)

status=1 means the event is enabled

EventDelete

Deletes the specified event. The event does not respond to the specified condition until the task is executed again and the event is enabled.

EventDelete EVENT1

Events at Start-up

Events are normally triggered by the OnEvent condition changing from false to true. So a single transition in the condition is required to run OnEvent. One exception to this is start-up. At start-up, if the condition is true, OnEvent executes once, even if there has not been a transition.

Program Flow and OnEvent

You can use GoTo commands within an OnEvent block of code. However, because OnEvent interrupts the main program, you cannot use GoTo to branch out of the event handler or into the event handler. You cannot place OnEvent…End OnEvent in the middle of program flow commands (e.g., For…Next, If…Then, etc.). You cannot declare or use local variables inside an OnEvent block.

Semaphores

Semaphores are the basis for synchronization and mutual exclusion. The difference is that the mutual exclusion semaphore is created as “full” or “1”, while the synchronization semaphore is empty “0”. If the semaphore is used for protecting mutual resources, it is taken before accessing the resource and releases at the end. A synchronization semaphore is given by the producer and taken (consumed) by the consumer.

NOTE-Info.svgNOTE
A semaphore is created as “full.”

Global semaphore are defined with COMMON SHARED in CONFIG.PRG or from the command line. Since a semaphore's purpose is to protect data among tasks, there is no meaning to local semaphores.

A semaphore is given/released by SEMAPHOREGIVE and taken/consumed by SEMAPHORETAKE. It is possible to specify a time out of up to 5000 ms. SEMAPHORETAKE acquires a semaphore and returns before timeout or does not acquire a semaphore and returns after timeout.

NOTE-Info.svgNOTE
Mutual exclusion semaphores are taken and given by the same task. Synchronization semaphores are given by one task and taken by another task.

Mutual Exclusion Semaphores

Mutual exclusion semaphores lock resources by taking a semaphore. Another task(s) competing for the same resource is blocked until the semaphore is released.

Example of a mutually exclusive semaphore:

' common shared comMutex as semaphore
' defined in config.prg
Program
Open COM2 BaudRate=9600 Parity=0 DataBits=8 StopBit=1 As #1
While 1
' take semaphore lock serial port
If SemTake(comMutex,5000) = 1 Then
Print #1,”Hello ”;
Print #1,”world”
SemGive(comMutex) ‘unlock serial port
End if
End While
End program

Synchronization Semaphores

Synchronization semaphores are essential in producer-consumer applications where task A prepares some data, while task B consumes it. In this case, the semaphore may eliminate constant polling for ready data and save considerable CPU resources.

Example of Producer:

' common shared syncSemaphore as semaphore
' defined in config.prg
' common shared globalA as long ' defined in config.prg
Program
Dim dummy as long
' Semaphore is created as “full” - flush it before first use
dummy=semTake(syncSemaphore) ' no waiting
While 1
globalA=globalA+1 ' produce some data
semGive(syncSemaphore)
sleep (100)
End While
End program

Example of Consumer:

' common shared syncSemaphore as semaphore
' defined in config.prg
' common shared globalA as long ' defined in config.prg
Program
While 1
If SemTake(syncSemaphore,5000) = 1 Then
Print "A is "; globalA
End if
End While
End program