OmniCore RW 8.1 – Control Station Registration Fails with C004AB25 Using PC SDK 2026.1

Hi ABB Robotics Community,

I am developing a C# application to remotely control an ABB OmniCore 250XT using:

  • Controller: ABB OmniCore 250XT

  • RobotWare: 8.1.0

  • RobotStudio: 2026.1

  • PC SDK: 2026.1 (ABB.Robotics.Controllers.PC.dll version 26.2.11700.0)

  • Application: Standalone C# application using ConnectionType.Standalone

I am trying to migrate my existing application from the traditional Mastership approach to the RobotWare 8 Control Station / Write Access mechanism.

The controller connection and login work successfully:

this.controller_ =
    Controller.Connect(
        controllerInfo,
        ConnectionType.Standalone);

this.controller_.Logon(UserInfo.DefaultUser);

I then try to register the application as a Control Station:

string controlStationId =
    Guid.NewGuid().ToString();

this.controller_.ControlStation.Register(
    "DHVANI PC Control Station",
    controlStationId,
    1234,
    true);

However, the registration fails with:

RobApiException: C004AB25 : Control station id not allowed.

ERROR:
rdh_controller.cpp[10099]:
org_code: -20103
new_code: 0xc004ab25

The PC SDK command shown in the exception is:

Cmd:Set
Prop:RegisterControlStation

-DisplayName "DHVANI PC Control Station"
-Id "9fb7c7fd-9190-4658-9bad-20a8c31348fb"
-PinCode 1234
-ReleaseWriteAccessWhenLost True

The important point is that I am currently testing this with a RobotStudio Virtual Controller:

Name      : 6710-501712_2
IP        : 127.0.0.1
RobotWare : 8.1.0.0
Virtual   : True

The connection and login succeed, and I can read controller state/mode successfully:

Controller State : GuardStop
Operating Mode   : Auto

But ControlStation.Register() is rejected.

I have checked the PC SDK documentation for ControlStation. It states that:

Register(
    string displayName,
    string id,
    uint pinCode,
    bool releaseWriteAccessWhenLost)

registers the calling application as a Control Station, and that the id is the unique identifier for the application.

I would like to understand:

  1. Why does the Virtual Controller reject RegisterControlStation with C004AB25 / INVALID_CONTROL_STATION_ID?

  2. Is there any specific configuration required on an RW 8.1 Virtual Controller before calling ControlStation.Register()?

  3. Is the id required to follow a specific format or GUID scheme?

  4. Does the PIN need to be configured somewhere in the Virtual Controller/UAS?

  5. Does EnableExternalControl() need to be called before registration on a Virtual Controller?

  6. Are there any RobotWare options or RobotStudio settings required for Control Station registration?

  7. Is there a known compatibility issue between PC SDK 2026.1 (26.2.11700.0) and RobotWare 8.1.0 for Control Station registration?

  8. Once registration succeeds, what is the correct sequence for:
    Register → RequestWriteAccess → Load RAPID Module → Set Program Pointer → Start RAPID → ReleaseWriteAccess?

I would appreciate any guidance from someone who has successfully implemented PC SDK Control Station/Write Access with OmniCore RobotWare 8.x, especially on a Virtual Controller.

Thanks.

1 Like

Hi there

I reproduced this on an OmniCore RW 8.1.1 VC and found the cause. Everything below is from that run, not from the docs.

1 and 3. The id has to be a braced GUID. Same controller, same call, fresh session each time, only the id format changed:

unbraced  890d22b5-9842-4192-ade0-a03e537f87c9
  -> HTTP 400, ctrl=-1073435867, icode=-20103
     "Control station id not allowed"
  GET /rw/controlstation/id  ->  "none"

braced    {8dd4cd46-5757-4f80-96e0-38de864be6a9}
  -> 204 OK
  GET /rw/controlstation/id  ->  "{8dd4cd46-5757-4f80-96e0-38de864be6a9}"

-1073435867 is 0xC004AB25 as a signed 32-bit int, and the icode matches your org_code -20103, so this is the identical error down to the org code. In C# use Guid.NewGuid().ToString("B") instead of .ToString(). The default “D” format has no braces.

liao_Chen found the same thing from the PC SDK side back in June, in “PCSDK 2026 register with rw8”( link). The sample in the PC SDK documentation is missing the braces.

The GET /rw/controlstation/id read-back is worth keeping as a check. It returns “none” when nothing is bound and echoes your id when the registration actually took.

4. The pin is mandatory but its value is not checked. I registered with 1234, with 9999 and with an empty string. All three worked, on a controller where I had never configured a pin. A non-numeric value, or leaving the field out entirely, gives 400 (-1073445879). So it has to be present and numeric, but nothing needs setting up in advance and nothing pairs against it. The display name is mandatory too.

5. There is no enable step. My flow is two calls, register and then request write access, nothing in between. I probed the controller for an enable endpoint:

POST /rw/controlstation/enableexternalcontrol   -> 404
POST /rw/controlstation/externalcontrol/enable  -> 404
POST /rw/controlstation/enable-external-control -> 404
GET  /rw/controlstation/disableexternalcontrol  -> 405

The 405 means that path exists and only the verb was wrong. The enable variants all give 404, so they do not exist. The resource listing under /rw/controlstation shows disableexternalcontrol with no counterpart. A remote client can drop external control but cannot give it to itself.

2 and 6. Nothing extra was needed. No extra RobotWare option, no RobotStudio setting. A plain VC registered fine once the id format was right.

One caveat. The pendant’s Remote Access toggle was already on for my VC, and it shows up as control-station-external-control-enabled: true in the write access status. I did not test it switched off, because switching it back on needs a physical long press on the virtual pendant and that would have broken my rig. If the braces alone do not fix it, check that toggle next. Also worth keeping in mind that you are on 8.1.0 and I am on 8.1.1.

7. Not a version mismatch. 26.2.11700.0 is the PC SDK 2026.2 build and it has no API changes compared to 2026.1. That pairing is not your problem.

8. Your sequence is right. Two things about RW8 that cost me time:

Registration is session scoped. Register once per connection, not per write, and again after a reconnect.

A write clears write access as a side effect. After a successful write the status resource reports the access as no longer held, while the same session carries on writing fine. So the ReleaseWriteAccess() at the end of your sequence can fail on something you already lost. Check the status first, or let the release fail quietly.

One more thing that might save you some time. Registration worked while a different station held write access, so registering and holding write access are independent. You do not have to wait for the controller to be free before you register.

Unrelated, but relevant if you are testing on 8.1.1: the RMMP service is broken there, every verb answers 500. I checked it back to back against a working RW 7.21. Do not lose a day on it thinking it is your code.

Thanks for your UAS grant answer on the Rapid.Start() thread by the way, that one had been open a long time.

Thanks a lot for your help and for taking the time to investigate this issue. Your findings about the braced GUID helped me identify and fix the registration problem. Really appreciate your support!

1 Like

Is mastership needed for any operation in RW 8
like
using (Mastership.Request(this.controller_.Rapid))
{
SetAlarmSignal(0);
// Load the RAPID module
bool res = robTask.LoadModuleFromFile(filePath, RapidLoadMode.Replace);
if (res)
{
deviceResponse.SetCodeNumber(clsCodedData.SUCCESS);
deviceResponse.SetDescription($“Successfully loaded module for component {componentId}”);
}
}

private void button2_Click(object sender, EventArgs e)
{
// pptomain
try
{
if (controller == null)
{
return;
}

    if (controller.OperatingMode != ControllerOperatingMode.Auto)
    {
        MessageBox.Show("Set robot to Auto Mode");
        return;
    }

    if (controller.RobotWareVersion >= new Version(8, 0))
    {
        // RobotWare 8
        try
        {
            controller.ControlStation.RequestWriteAccess();
            tasks = controller.Rapid.GetTasks();
            tasks[0].ResetProgramPointer();     
            MessageBox.Show("pp to main !");
        }
        finally
        {
            controller.ControlStation.ReleaseWriteAccess();
        }
    }
    else
    {
        // <= robotware 7
        using (Mastership m = Mastership.Request(controller))
        {
            tasks = controller.Rapid.GetTasks();
            tasks[0].ResetProgramPointer();               
            MessageBox.Show("pp to main !");
        }
    }
}
catch (WriteAccessHeldException ex)
{
    MessageBox.Show("Write access is held by another client." + ex.Message);
}
catch (System.InvalidOperationException ex)
{
    MessageBox.Show("Mastership is held by another client." + ex.Message);
}
catch (System.Exception ex)
{
    MessageBox.Show("Unexpected error occurred: " + ex.Message);
}

}

StartResult startResult = this.controller_.Rapid.Start(RegainMode.Continue, ExecutionMode.Continuous, ExecutionCycle.Once);
if (startResult != StartResult.Ok)
{
    deviceResponse.SetDescription($"Failed to start rapid. Start result: {startResult}");
    return deviceResponse;
}

this return error can you help me…

Happy to help. First, can you print the actual StartResult value? The enum is descriptive and it usually names the cause directly.

Three things to check, in order of likelihood:

1. Controller state. Your first post shows Controller State : GuardStop. RAPID won’t start from GuardStop motors have to be on first. On a VC, reset the guard chain and switch motors on before Rapid.Start().

2. Write access must be held during the call. On RW8 the write clears write access as a side effect, so if you did PP-to-main first and then called Start() on the same registration, the access is already gone. Wrap Start() in its own RequestWriteAccess() / ReleaseWriteAccess() pair rather than reusing the one from the PP step.

3. The UAS grant . which is your own finding from the V250XT thread. Program-load grants and execution-start grants are separate on OmniCore, and a missing execute grant gives a silent failure rather than an exception. Worth confirming the Start grant is on the user you’re logging in as, same as the fix you posted there.

If it’s none of those, StartCheck.CallChain will reject when the program pointer isn’t at a valid entry routine try StartCheck.None once as a diagnostic to isolate it.
If none of that isolates it, one trick that’s saved me time on OmniCore: reproduce the same operation over raw RWS instead of through the SDK. If the controller accepts it there, the problem is in the SDK layer or the session state; if it rejects it too, it’s grants or controller state. I maintain an open-source TypeScript client that covers both RWS generations and the RW8 control-station path, so the request and response are visible rather than wrapped abb-rws-client on npm if it’s useful. Different language from your C#, but the HTTP shape is the thing worth seeing.

error
PP-to-main first and then called Start() -> i set the pointer to routine and start

Update – Issue Resolved

I finally resolved the Control Station registration and Write Access issue.

The main issue was the Control Station ID format. RobotWare 8.1 expects the ID in braced GUID format.

Instead of:


Guid.NewGuid().ToString()

I used:


Guid.NewGuid().ToString("B")

This generates:


{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}

After that, the correct PC SDK flow is:


Register Control Station
         ↓
Check Write Access
         ↓
RequestWriteAccess()
         ↓
Verify HeldByMe == true
         ↓
Enable MotionControl
         ↓
Perform RAPID operation

I also found that:


Held = true
HeldByMe = false

means the Write Access is held by another Control Station/session, while:


Held = true
HeldByMe = true

confirms that the current application owns the Write Access.

My final implementation now checks these states before every controller operation, so repeated calls do not unnecessarily register or request Write Access again.

Environment:

  • RobotWare 8.1.0.0
  • RobotStudio 2026
  • PC SDK 2026.2
  • OmniCore Virtual Controller
  • C#

Thanks to everyone who helped investigate this. This was especially useful because the original C004AB25 – Control station id not allowed error did not make the actual ID-format requirement obvious.