BRAND.00 / IRC5 + OMNICORE · RAPID
The structured, Pascal-like language that programs ABB industrial robots.
ABB introduced RAPID in 1994 with the S4 controller, and it is still the language of the IRC5 and OmniCore controllers. It is structured and strongly typed, closer to Pascal than to BASIC. A program is built from modules, execution starts at a routine called main, and data is declared apart from the instructions that use it. A single Move line says everything about a motion: where to go, how fast, how close to pass the point, and with which tool.
ABB is one of the four big industrial robot makers, with FANUC, KUKA and Yaskawa. For a programmer, what sets it apart is RobotStudio, whose virtual controller runs the same RobotWare as the real cabinet, and the way RAPID, the controller (IRC5 or OmniCore) and the SafeMove safety option are designed to work together.
The IRB name runs from the 1974 IRB 6 to today's IRB 1010 and the OmniCore generation. A RAPID program written for an S4 reads almost the same on OmniCore.
IRC5 (2004) is still in a great many cells, and ABB has announced its phase-out from June 2026. OmniCore runs the same language on RobotWare 7.
RobotStudio is ABB's offline programming and simulation tool. Its virtual controller runs the RobotWare of the real robot, so you can check code, reach and cycle time before the cell exists.
Compact pick-and-place, machine tending
Arc welding, material handling
Welding, dispensing, assembly
Handling, palletising, machine tending
Spot welding and heavy handling
Heavy handling, for example car bodies in the body shop
Dual-arm small-parts assembly
14 axes · 38 kg total · IP30
Bench-top precision assembly
7 axes · 9.5 kg · 0.02 mm repeatability
Cobot for material handling and machine tending
IP54 · power and force limiting
Industrial-speed cobot: slows and stops as a person comes close
Up to 5 m/s TCP · 0.01 mm repeatability · SafeMove + safety laser scanner · now phased out
Payloads and reaches are the values ABB publishes on its product pages and datasheets. The usable workspace is smaller than the reach circle: there is a dead zone close to the base, and at full stretch the wrist cannot reach every orientation. Read the payload diagram as well as the payload figure, because a gripper whose centre of gravity sits far from the flange takes a large share of the rating.
| Feature | IRC5 (legacy fleet) | OmniCore (current) |
|---|---|---|
| Generation | Launched 2004 · phase-out from June 2026, very large installed base | Family launched 2018 · ABB's current controller |
| Cabinet form factor | Single and dual cabinet, compact IRC5C, panel-mounted | E10, C30, C90XT, V250XT, V400XT |
| Motion control | QuickMove and TrueMove (first released 1994; second generation from 2009) | ABB's 2024 platform: up to 25% faster and up to 20% less energy than the previous controller, by ABB's figures |
| Safety | SafeMove2 option (PL d, Cat. 3) | SafeMove option (PL d, Cat. 3) |
| Connectivity | Fieldbus options: PROFINET, EtherNet/IP, DeviceNet, PROFIBUS and others | PROFINET and EtherNet/IP among the fieldbus options |
| Programming surface | RAPID · FlexPendant | RAPID · FlexPendant, plus Wizard block programming for cobots |
| Simulation | RobotStudio (RobotWare 5 or 6) | RobotStudio (RobotWare 7) |
Every classic IRB has the same six-axis articulated layout. ABB numbers the axes 1 to 6 from the base to the flange (a jointtarget stores them as rax_1 to rax_6), and the world frame is right-handed with +Z up, as ISO 9787 defines. Hover or click a part to see what it does.
Tool centre point: the point the robot actually positions, usually the tip of the gripper or torch, not the flange.
A program is a set of modules (MODULE ... ENDMODULE). PROC is a procedure, FUNC returns a value, TRAP answers an interrupt. Execution starts in the routine named main. System modules hold data every program shares, such as tooldata, and stay loaded when you load a new program.
MODULE MainModule
PROC main()
! ...
ENDPROC
ENDMODULEMoveJ moves all axes together: fastest, and the TCP path is a curve. MoveL keeps the TCP on a straight line. MoveC runs an arc through a circle point. MoveAbsJ goes to axis angles, so a home move never meets a configuration problem. Every move takes target, speeddata, zonedata and tooldata, in that order.
MoveJ pHome, v1000, z50, tGripper; MoveL pPick, v200, fine, tGripper;
The TCP is defined by tooldata. Targets are stored in a work object (wobjdata), which holds a user frame (the fixture) and an object frame (the part on it). Re-teach the user frame after a fixture moves and every point in it follows. Without \WObj a move uses wobj0, which coincides with the world frame.
MoveL pPick, v500, fine, tGripper \WObj:=wPallet;
robtarget: position [x,y,z] in mm, orientation as a quaternion, axis configuration [cf1,cf4,cf6,cfx] and external axes. jointtarget: axis angles. speeddata runs from v5 to v7000 plus vmax; v1000 is 1000 mm/s at the TCP and 500 degrees/s reorientation. zonedata: fine, then z0 to z200, where z10 allows a 10 mm TCP zone.
CONST robtarget pPick:= [[800,0,300],[0,0,1,0], [0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
CONST never changes. A VAR gets its initial value back when the program is reset. A PERS keeps its current value, written back into the module, through resets and restarts. Taught targets are usually CONST, tooldata, wobjdata and counters PERS, scratch values VAR.
CONST num nLayers:=6; VAR num nTry:=0; PERS num nPartsDone:=0;
SetDO and ResetDO write digital outputs, PulseDO pulses one, SetGO writes a number to a group of bits. WaitDI blocks until an input has a value; give it \MaxTime in production code. RAPID uses the signal names from the I/O configuration, such as doGripper and diPartReady.
SetDO doGripper, 1; WaitDI diPartReady, 1 \MaxTime:=10;
IF/ELSEIF/ELSE, FOR, WHILE and TEST/CASE. An interrupt takes three steps: CONNECT an intnum to a TRAP, order the event with ISignalDI, and IDelete it when you are done. TRAPs are for process events like a vacuum loss. E-stops and guard doors belong to the safety system, not to RAPID.
CONNECT iPartLost WITH tPartLost; ISignalDI diVacuumOk, 0, iPartLost;
PROC for procedure, FOR ... FROM ... TO ... DO with its own ENDFOR, and a data type written before the name with no colon (VAR num i;). RAPID even declares the FOR counter for you. The shape of the program is the same, so anyone who has read Pascal can follow RAPID.
procedure Cycle;
var i: integer;
begin
for i := 1 to 5 do
WriteLn('step ', i);
end;PROC Cycle()
FOR i FROM 1 TO 5 DO
TPWrite "step " + ValToStr(i);
ENDFOR
ENDPROCThese two motion types make up most of any program. Same start, same end, different path, because MoveJ interpolates in joint space and MoveL in Cartesian space. Toggle below and watch the TCP trace.
In RAPID the third argument of a Move instruction is its zonedata. fine stops the robot at the point. z0…z200 lets the TCP cut the corner inside a zone of that radius in mm and carry on without stopping, which is where cycle time is won. The controller shrinks a zone that is larger than half the move, and the instructions after a zone point (SetDO, WaitTime) run before the robot reaches the point.
Every vendor has the same idea under another name: ABB zonedata (radius in mm), KUKA $APO.CDIS with C_DIS (distance in mm), FANUC CNT 0 to 100 (a degree of rounding, not a distance), UR the blend radius r in metres. None of them draws a true circular arc: each controller plans its own smooth transition inside the zone.
When you write MoveAbsJ jHome, v1000, fine, tool0;, the controller runs forward kinematics: it walks the chain from base to flange and works out where the TCP ends up. There is exactly one answer, which is why a jointtarget never has a configuration problem. The widget below is a three-link planar version of the same calculation; move the sliders and watch the TCP pose.
| Instruction | Category | Purpose | Example |
|---|---|---|---|
| MoveJ | Motion | Joint move: every axis starts and stops together, so the TCP path is a curve you do not control. Fastest way through free air. | MoveJ pHome, v1000, z50, tGripper; |
| MoveL | Motion | Linear move: the TCP runs a straight line at the speeddata TCP speed (mm/s). Use it for the last approach, the pick and the retreat. | MoveL pPick, v200, fine, tGripper; |
| MoveC | Motion | Circular move from the current position through a circle point to the end point. Keep the three points well apart or the arc is badly defined. | MoveC pMid, pEnd, v300, z10, tGlue; |
| MoveAbsJ | Motion | Move to a jointtarget (axis angles in degrees). No configuration choice is involved, which makes it the safe way to a home or service position. | MoveAbsJ jHome, v1000, fine, tool0; |
| MoveLDO | Motion | Linear move that sets a digital output in the middle of the corner path of its zone point. | MoveLDO p20, v1000, z30, tool0, doGlue, 1; |
| Offs | Motion | Function: a copy of a robtarget shifted x, y, z mm in the work object frame. The usual way to make approach points and pallet grids from one taught point. | MoveL Offs(pPick, 0, 0, 100), v500, z20, tGripper; |
| RelTool | Motion | Function: a robtarget shifted (and optionally rotated) in the tool frame, for example straight back along the tool Z axis. | MoveL RelTool(pPick, 0, 0, -100), v500, z20, tGripper; |
| SetDO | I/O | Write a digital output to 0 or 1. | SetDO doGripper, 1; |
| ResetDO | I/O | Set a digital output to 0. | ResetDO doGripper; |
| PulseDO | I/O | Pulse a digital output. The default pulse is 0.2 s; \PLength sets another length. | PulseDO \PLength:=0.5, doEject; |
| SetGO | I/O | Write a number to a group output (several bits read as one integer), for example a recipe number to the PLC. | SetGO goRecipe, 12; |
| WaitDI | Wait | Wait until a digital input has a value. Add \MaxTime so a dead sensor raises an error you can handle instead of a silent stop. | WaitDI diPartReady, 1 \MaxTime:=10; |
| WaitUntil | Wait | Wait until any boolean expression is TRUE. | WaitUntil diClampA = 1 AND diClampB = 1; |
| WaitTime | Wait | Wait a number of seconds. Motion queued before it carries on. | WaitTime 0.5; |
| IF | Flow | Conditional with optional ELSEIF and ELSE. | IF nCount > 10 THEN ... ENDIF |
| FOR | Flow | Counted loop. The loop variable is declared by the FOR itself and only exists inside it. | FOR i FROM 1 TO 5 DO ... ENDFOR |
| WHILE | Flow | Loop while a condition is TRUE, tested before each pass. | WHILE bRun DO ... ENDWHILE |
| TEST | Flow | Switch on a value: CASE lists, DEFAULT for the rest. | TEST nMode CASE 1: ... DEFAULT: ... ENDTEST |
| PROC | Structure | Declare a procedure. Call it by name with no brackets: Pick; or PickAt 150; | PROC PickAt(num zHeight) ... ENDPROC |
| FUNC | Structure | Declare a function that returns a value. Function calls take brackets. | FUNC num Add(num a, num b) ... ENDFUNC |
| TRAP | Structure | Interrupt routine. It runs when its interrupt fires, then the program carries on where it was. | TRAP tPartLost ... ENDTRAP |
| CONST | Structure | Constant data. Taught positions are often CONST so a program cannot change them by accident. | CONST robtarget pPick:=[[800,200,300],[0,0,1,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]]; |
| VAR | Structure | Variable. Gets its initial value back when the program is reset (program pointer to Main) or the module is reloaded. | VAR num nCount:=0; |
| PERS | Structure | Persistent: the current value is written back into the module, so it survives a program reset and a restart. Tooldata, wobjdata and part counters are usually PERS. | PERS num nPartsDone:=0; |
| CONNECT | System | Bind an intnum interrupt identity to a TRAP routine. | CONNECT iPartLost WITH tPartLost; |
| ISignalDI | System | Order an interrupt when a digital input changes to a value. | ISignalDI diVacuumOk, 0, iPartLost; |
| IDelete | System | Cancel an interrupt and free its identity. Do it before you CONNECT the same intnum again. | IDelete iPartLost; |
| ConfL | System | Turn configuration supervision for linear moves on or off. With \Off the robot may finish a MoveL in a different axis configuration from the one taught. | ConfL \On; |
| VelSet | System | Scale programmed speed by a percentage and cap TCP speed in mm/s for all following moves. | VelSet 50, 800; |
| AccSet | System | Reduce acceleration (percent) and its ramp (percent), for a heavy or loose part. | AccSet 50, 50; |
These are the faults that turn up on real cells, most of them during commissioning.
SetDO after MoveL pPlace, v500, z20 opens the gripper while the robot is still rounding the corner, so the part drops early: RAPID runs the logical instructions after a fly-by point before the robot reaches the point. Put fine on any point where I/O follows, or use MoveLDO or TriggL when the switch has to happen on the path.
A gripper declared as 1 kg that really weighs 4 kg with the part makes the path overshoot and the motors work harder than the dynamic model expects. Measure the tool with the LoadIdentify service routine and switch to the part load with GripLoad when the gripper closes.
If all points live in the robot base frame, moving the fixture 20 mm means re-teaching every one of them. Teach them in a wobjdata whose user frame sits on the fixture, and after a move you re-teach the three points of the user frame instead.
Turning configuration supervision off lets a MoveL finish in a different axis configuration from the one taught, and the robot may swing the wrist round to get there. Fix the robconf of the target, or reach it with a MoveJ first.
A dead sensor leaves the robot standing at WaitDI with nothing on the FlexPendant to say why. Add \MaxTime and handle ERR_WAIT_MAXTIME in the routine’s ERROR handler, or use \TimeFlag, so the operator is told which signal the robot is waiting for.
A VAR goes back to its initial value whenever someone moves the program pointer to Main, so a part counter or a pallet layer number silently restarts at zero. Anything the cell has to remember belongs in PERS.