Robot ABB IRB 6400 + Controlador S4

Repositorio de documentación técnica y conocimiento operativo del sistema robótico ABB IRB 6400 con controlador S4. Este repositorio centraliza toda la información recopilada desde manuales originales, experiencia práctica en campo, configuraciones, programas de ejemplo y soluciones a fallas comunes.

BASE

Esta estructura corresponde a un sistema de archivos típico de un robot ABB con controlador S4. Te explico cada elemento:


ARCHIVOS PRINCIPALES


1. Archivos del Sistema (SYS)


· BASE.SYS → Archivo del sistema base que contiene parámetros esenciales del robot (tipo de robot, ejes, etc.)

· USER.SYS → Configuraciones de usuario (datos herramienta, marcos, velocidades, etc.)

· DAT_MT16.SYS → Datos del modelo de robot específico para el IRB 6400


2. Programas (PRG/TXT)


· PROG201.PRG → Programa de aplicación (código RAPID del robot)

· PROG201 (1).txt → Posiblemente una copia o exportación del mismo programa


3. Directorio RAMDISK/


Contiene copias de los archivos de sistema que se cargan en memoria RAM durante el arranque:


· BASE_MT.SYS → Base del manipulador (robot)

· COM200.SYS → Configuración de comunicación

· Estos se cargan al iniciar el sistema desde el disco duro/disquete


4. Directorio SYSPAR/


Archivos de configuración del sistema:


· EIO.CFG → Configuración de E/S (Entradas/Salidas)

· MMC.CFG → Configuración del módulo de control del motor

· MOC.CFG → Configuración de movimientos

· PROC.CFG → Configuración de procesos

· SIO.CFG → Configuración de comunicación serial

· SYS.CFG → Configuración general del sistema


¿POR QUÉ ESTA ESTRUCTURA?


El S4 de ABB organiza los archivos así porque:


1. Separación clara entre sistema, configuraciones y programas de usuario

2. RAMDISK permite acceso rápido a archivos críticos durante operación

3. SYSPAR centraliza todas las configuraciones técnicas

4. Compatibilidad con el sistema operativo VxWorks que usa el S4


FLUJO TÍPICO DE CARGA:


1. Al encender, carga BASE.SYS y DAT_MT16.SYS

2. Copia archivos esenciales a RAMDISK para rápido acceso

3. Carga configuraciones de SYSPAR/

4. Finalmente carga USER.SYS y programas de aplicación


¿Necesitas ayuda específica con alguno de estos archivos o quieres modificar algo en particular?

RAMDISK/BASE.SYS

Análisis del Archivo BASE.SYS - Módulo Base del Sistema ABB S4


📋 Descripción General


Archivo de sistema fundamental que define datos predefinidos, configuraciones base y rutinas esenciales para el controlador S4. Es el núcleo de la configuración del robot.


🔍 Estructura del Contenido


1. 📊 Datos del Sistema Predefinidos


```rapid

! Herramienta, objeto y carga por defecto

tooldata tool0 → Herramienta en el flange (origen)

wobjdata wobj0 → Objeto de trabajo mundial (base del robot)

loaddata load0 → Carga vacía (0 kg)

```


2. ⚡ Zonas de Aproximación (zonedata)


```rapid

fine → Parada exacta (sin aproximación)

z1-z200 → Zonas progresivas de aproximación

```


Estructura: [FINE?, dist_pzone, ori_zone, ...]


· fine: [TRUE, 0, 0, 0, 0, 0, 0] - Parada precisa

· z10: [FALSE, 10, 15, 15, 1.5, 15, 1.5] - Aproximación de 10mm


3. 🚀 Velocidades Predefinidas (speeddata)


```rapid

v5 a v7000 → Rangos de velocidad

```


Estructura: [tcp_speed, ori_speed, ext_ax_speed, ori_acc]


· v100: [100, 500, 5000, 1000] → 100 mm/s en TCP

· vmax: [5000, 500, 5000, 1000] → Velocidad máxima


4. 🔧 Constantes del Sistema


```rapid

testsignal → IDs para instrucción TestSign

flp1, ram1disk → Rutas de sistema

pi → Constante matemática (3.1415926)

```


5. ⚙️ Rutinas Esenciales


SYS_RESET() - Reset del Sistema


```rapid

VelSet 100, 5000; → 100% velocidad, 5000 mm/s max

AccSet 100,100; → 100% aceleración

SingArea \Off; → Desactiva área singular

ConfJ \On; ConfL \On; → Activa configuración de ejes

GripLoad load0; → Carga vacía

PDispOff; EOffsOff; → Desactiva offsets

```


Propósito: Restaurar parámetros de movimiento a valores por defecto.


RESTORE_IO() - Restauración I/O


```rapid

PFIOResto; → Restaura estado I/O tras corte de energía

```


TestDI() - Función de Test Digital Input


```rapid

FUNC bool TestDI(VAR signaldi Signal)

→ Devuelve TRUE si señal = 1

```


🎯 Propósito y Uso


Para el Sistema:


· Inicialización → Carga datos base al arrancar

· Referencia → Define valores por defecto del sistema

· Consistencia → Asegura comportamiento predecible


Para el Programador:


· Atajos → Usar z10 en vez de definir zona cada vez

· Estandarización → Velocidades comunes predefinidas

· Seguridad → fine para posiciones críticas


💡 Ejemplos de Uso en Programas


```rapid

! Usando constantes de BASE.SYS

MoveL p1, v500, z10, tool0; → Movimiento a 500 mm/s, zona 10mm

MoveJ p2, vmax, fine, tool0; → Movimiento rápido, parada exacta


! Resetear configuración

SYS_RESET;


! Testear entrada digital

IF TestDI(di_StartButton) THEN

  StartProcess;

ENDIF

```


⚠️ Consideraciones Importantes


1. NO MODIFICAR DIRECTAMENTE

   · Archivo crítico del sistema

   · Modificaciones pueden afectar estabilidad

2. HERENCIA

   · Todos los programas heredan estas definiciones

   · No necesitan declarar tool0, wobj0, etc.

3. PERSONALIZACIÓN

   · Para cambios, crear módulos propios

   · Ej: MY_ZONES.SYS con zonas personalizadas


🔧 Relación con Otros Archivos


```

BASE.SYS

  ↓

USER.SYS (extiende/modifica)

  ↓

PROGRAMAS (usan las definiciones)

```


📝 Notas para el Repositorio


Ubicación en documentación: 📚 Documentación Original/Archivos de Sistema/BASE.SYS.md


Contenido recomendado:


· Copia exacta del archivo

· Explicación de cada sección

· Ejemplos de modificación segura

· Comparativa con versiones posteriores (S4C, S4C+)


¿Necesitas que explique cómo crear una versión personalizada o cómo afectan estos parámetros al movimiento del robot?

RAMDISK/COM200.SYS

Análisis del Archivo COM200.SYS - Comunicación RPC Multitarea


📋 Descripción General


Sistema de comunicación RPC (Remote Procedure Call) para intercambio de datos entre el robot ABB IRB 6400 y un sistema externo (posiblemente un PLC o supervisor). Implementado como tarea secundaria (Task 1) en un entorno multitarea.


🎯 Contexto de la Aplicación


```yaml

Estación: FFS Schaufelbearbeitung (procesamiento de palas)

Ubicación: ABB Kraftwerke Birr/Bexbach (central eléctrica)

Función: Comunicación robot ↔ sistema de control externo (RPC)

Autor: Bernd Luckas - ABB Flexible Automation GmbH

Fecha: 22.08.1995 - 24.09.1996

Versión: 2.00

```


🔧 Especificaciones Técnicas


```yaml

Robot: IRB 6400 (modelo específico XXXX)

Hardware: M94A

Software: Basic CommWare 2.0 + Advanced Functions + Multitasking

Programa: 3HAB2317-1/05

Comunicación: RS232 por puerto sio1:

Protocolo: Telegramas personalizados (STX/ETX/ACK/NAK)

```


📊 Estructura del Protocolo de Comunicación


1. 📨 Telegrama de ESTADO (Robot → RPC)


```rapid

Formato: [STX] [Z] [Datos(12)] [ETX]

Posiciones:

  1: STX (2) - Start of Text

  2: Z (90) - Identificador "Zustand" (Estado)

  3: nAlr - Número de alarma

  4-6: nAnrC1-3- Número de alarma convertido (3 chars)

  7: nBtrz - Estado operativo (A=Auto, M=Manual, S=Stop)

  8: nQpoa - ??? 

  9: nEpoa - ???

  10: nSpb - ??? 

  11: nQtta - ???

  12: nEtta - ???

  13: nStb - ???

  14: ETX (3) - End of Text

```


2. 📩 Telegrama de ORDEN (RPC → Robot)


```rapid

Formato complejo con múltiples campos:

  - Tipo de orden (AuftragsArt)

  - Estación (StationsNr)

  - Posiciones (PlatzNrStation, PlatzNrIRB)

  - Tipo de transferencia (TransArt)

  - Peso (Gewicht)

  - Desplazamientos X,Y,Z (VerschiebX/Y/Z)

  - Rotación Z (DrehungZ)

  - Tipo de adaptador

  - Dirección de aproximación

  - Patrón de colocación

  - Tipo de pala (SchaufelTyp)

```


🔄 Diagrama de Flujo del Sistema


```

┌─────────────────┐ RS232 ┌─────────────────┐

│ Robot ABB │◄────────────►│ Sistema RPC │

│ IRB 6400 │ sio1: │ (Supervisor) │

│ │ │ │

│ TASK 0 (Main) │ I/O │ │

│ │ │ Digital │ │

│ ▼ │◄────────────►│ │

│ TASK 1 (COM) │ di/do │ │

└─────────────────┘ └─────────────────┘

       ▲ ▲

       └─────────── Telegramas ─────────┘

```


⚙️ Variables de Comunicación entre Tareas


Señales Digitales Task 0 ↔ Task 1:


```rapid

diCTENQ → Enable Request (Task 0 solicita comunicación)

doCTACK → Acknowledge (Task 1 confirma recepción)

```


Variables Compartidas (posiblemente en DAT_MT16.SYS):


```rapid

nZ_tgm → Flag telegrama estado procesado

nA_tgm → Flag telegrama orden procesado

nAnr → Número de alarma actual

nAlr → ??? 

nQpoa, nEpoa, nSpb, nQtta, nEtta, nStb → Parámetros de estado

```


🔍 Funciones Principales


main() - Ciclo Principal


```rapid

IF bInit=FALSE initialisiere; → Inicializa comunicación

ctrtask0; → Escanea solicitudes Task 0

ctrbetrz; → Controla estado operativo

IF bSend=TRUE send; → Envía telegrama estado

IF bSend=FALSE receive; → Recibe telegrama orden

IF bProcess_Atgm=TRUE process_Atgm; → Procesa orden recibida

stop_task; → Controla estado de tarea

```


send() - Envío de Telegramas


```rapid

1. Prepara buffer de salida (14 bytes)

2. Envía por RS232 (WriteBin)

3. Espera ACK (6) del RPC

4. Reintenta hasta 3 veces si falla

```


receive() - Recepción de Telegramas


```rapid

1. Lee bytes del puerto serie

2. Detecta STX (inicio) y ETX (fin)

3. Responde ACK al telegrama completo

4. Activa procesamiento si es válido

```


process_Atgm() - Procesamiento de Órdenes


```rapid

Convierte datos ASCII a valores numéricos:

- Campos de 1-5 dígitos

- Signo negativo detectado por carácter 45 (-)

- Escalas aplicadas (×0.1 para desplazamientos)

```


🚨 Sistema de Gestión de Errores


Códigos de Error (stFMTCOM01-07):


```yaml

01: "Kein ACK in RPC Antwort TGM" - Sin confirmación

02: "ERR_DEV_MAXTIME" - Timeout en dispositivo

03: "Kein ACK" (reintento)

04: "Keine Antwort von RPC" - Sin respuesta tras 3 intentos

05: "TGM-Kennung undefiniert" - Identificador desconocido

06: "ERR_FILEACC" - Error acceso a archivo

07: "ERR_DEV_MAXTIME inerhalb RPC-TGM" - Timeout interno

```


Prioridades:


· 0: Solo mensaje en Teach Pendant

· 1: Mensaje + detiene tarea (requiere OK)


💡 Ejemplo de Configuración para Repositorio


Archivo: 📚 Configuraciones/Comunicación/COM200_SYS.md


```markdown

## Configuración RS232 Implícita

(Puerto sio1: configurado en SIO.CFG)

- Baudrate: (desconocido, verificar en SIO.CFG)

- Paridad: (desconocido)

- Bits de datos: (desconocido)

- Bits de parada: (desconocido)


## Mapeo de Estados Operativos

nBtrz (Estado del robot):

  65 'A' → AUTO (diCProg_run=1 AND diCAuto_Ein=1)

  77 'M' → MANUAL (sin error, no auto)

  83 'S' → STOP (diCFehler=1)


## Protocolo de Handshake

1. Task 0 activa diCTENQ

2. Task 1 envía telegrama estado

3. Task 1 activa doCTACK

4. Task 0 desactiva diCTENQ

5. Task 1 desactiva doCTACK

```


🔗 Dependencias con Otros Archivos


```

COM200.SYS depende de:

├── BASE_MT.SYS (definiciones base)

├── DAT_MT16.SYS (variables compartidas)

└── SIO.CFG (configuración puerto serie)


COM200.SYS comunica con:

└── PROG201.PRG (Task 0 principal)

```


📝 Notas de Implementación


1. Multitarea Real → Task 1 independiente de movimiento

2. Comunicación Asíncrona → No bloquea movimiento robot

3. Robustez → Reintentos y manejo de errores

4. Industrial → Diseñado para 24/7 en planta


¿Necesitas que explique cómo configurar el puerto serie SIO.CFG o cómo integrar este sistema en una aplicación nueva?

<SMT>

<SMT> es simplemente un marcador utilizado en la especificación gramatical del lenguaje RAPID para indicar dónde debe colocarse una "declaración". No se trata de un comando que se deba escribir, sino de un marcador que muestra la estructura esperada del código, indicando que deben insertarse allí instrucciones válidas. En otras palabras, <SMT> sirve únicamente para guiar la organización del código en la documentación y los ejemplos, sin afectar la ejecución del programa.

Referencia:

 

Procedures

Procedures

MsgtoPC

ORIGINAL:

 !**********************************************************

  !* Procedure MsgtoPC () *

  !* *

  !* Diese Prozedur �bertr�gt eine Meldung von der *

  !* Vordergrundtask �ber die Task com (Hintergrundtask) *

  !* zu dem RPC *

  !* *

  !* *

  !* Input Parameter: string stMsgtpe *

  !* string stWert *

  !* *

  !* Date: Version: Programmer: Reason: *

  !* 16.11.95 1.00b B.Luckas *

  !**********************************************************

  PROC MsgtoPC(

    num nMsgtype,

    string stWert)

    TEST nMsgtype

    CASE syIRBStatus:

      IF stWert="1" THEN

        nFLRMode:=1;

        nAlr:=G;

        nAnr:=0;

        nQpoa:=NULL;

        nEpoa:=NULL;

        nSpb:=N;

        nQtta:=NULL;

        nEtta:=NULL;

        nStb:=N;

      ENDIF

      IF stWert="0" THEN

        nFLRMode:=0;

      ENDIF

      nZ_tgm:=1;

      handshakeZ;

    CASE syErrorMsg:

      !Umwandlung Fehlernummer

      bconv:=StrToVal(stWert,nAnr);

      nAlr:=K;

      !Negativ Quittierung Positionierauftrag

      IF nQpoa=P THEN

        nQpoa:=NULL;

        nEpoa:=N;

      ENDIF

      !Negativ Quittierung Transportauftrag

      IF nQtta=P THEN

        nQtta:=NULL;

        nEtta:=N;

      ENDIF

      nZ_tgm:=1;

      handshakeZ;

    CASE syinit:

      neustart;

      nZ_tgm:=1;

      handshakeZ;

    DEFAULT:

      TPWrite "Fehler bei MsgtoPC";

    ENDTEST

  ENDPROC

TRADUCCIÓN:

!**********************************************************

!* Procedimiento MsgtoPC () *

!* *

!* Este procedimiento transfiere un mensaje desde la *

!* tarea en primer plano a través de la tarea com (tarea en segundo plano) *

!* a la RPC *

!* *

!* *

!* Parámetros de entrada: cadena stMsgtype *

!* cadena stValue *

!* *

!* Fecha: Versión: Programador: Motivo: *

!* 16.11.95 1.00b B.Luckas *

!*********************************************************
PROC MsgtoPC(
num nMsgtype,
string stValue)

TEST nMsgtype
CASE syIRBStatus:

IF stValue="1" ENTONCES

Modo nFLRM:=1;

nAlr:=G;

nAnr:=0;

nQpoa:=NULL;

nEpoa:=NULL;

nSpb:=N;

nQtta:=NULL;

nEtta:=NULL;

nStb:=N;

ENDIF

SI stWert="0" ENTONCES

Modo nFLRM:=0;

ENDIF

nZ_tgm:=1;

apretón de manosZ;

CASE syErrorMsg:

!Número de error de conversión

bconv:=StrToVal(stWert,nAnr);

nAlr:=K;

Orden de posicionamiento de acuse de recibo negativo

SI nQpoa=P ENTONCES

nQpoa:=NULL;

nEpoa:=N;

FIN SI

Orden de transporte de acuse de recibo negativo

SI nQtta=P ENTONCES

nQtta:=NULL;

nEtta:=N;

FIN SI

nZ_tgm:=1;

handshakeZ;

CASO syinit:

reiniciar;

nZ_tgm:=1;

handshakeZ;

PREDETERMINADO:

TPWrite "Error en MsgtoPC";

FIN PRUEBA
FIN PROCESO

Instrucciones

Instrucciones

TPWrite

CFG


CFG

General

Topic Parameters that affect File name
Controller Event routines, etc. SYS.CFG
Communication Serial channels SIO.CFG
IO Signals I/O boards and signals EIO.CFG
Manipulator The robot and external axes

MOC.CFG

Teach Pendant Displaying data and access
on the teach pendant
MMC.CFG
Arc Welding Arc welding PROC.CFG

Estos archivos vienen definidos por defecto en el disquete de System Parameters.

 

No hay documentación oficial de aquella época que haya encontrado que diga cómo se estructura los archivos de configuración, así pues toda información aquí se ha extraído por comparación entre varios archivos y "lógica" que parece tener. Si bien es cierto, que hay pistas en documentación actual.

En todos estos archivos de configuración son archivos de texto plano y hay una cabecera al inicio del archivo del estilo:

SYS:CFG_1.0:2:0::

Estos parámetros vienen separados por : y siguiendo este ejemplo tenemos que,

SYS haciendo referencia al nombre del archivo, 

CFG_1.0 haciendo referencia a que pueda haber más de una configuración

Seguido de 2:0:: esto para determinar a qué versión del software pertenece ya que también se ha encontrado archivos con 2:1:: 

Veáse el apartado de SYS.CFG.


Puede contener algo de información útil, pero no es directa, con pinzás.
https://manualsnet.com/abb/robotware-add-ins

Captura de pantalla 2026-01-03 000827.png

Captura de pantalla 2026-01-03 000851.png

Captura de pantalla 2026-01-03 000952.png

Captura de pantalla 2026-01-03 001118.png

Captura de pantalla 2026-01-03 001005.png

Captura de pantalla 2026-01-03 001041.png

Captura de pantalla 2026-01-03 001026.png

Captura de pantalla 2026-01-03 001303.png

CFG

SYS.CFG

Aquí tenemos dos ejemplos de configuración tanto para la vesión 2.0 cómo la versión 2.1, ambos comparten los mismos campos. Explicados en orden de aparición.

NOMBRE FUNCIÓN
(*) SYS_MISC ??? (*) Sólo disponible en la vesión 2.1.
CAB_TASKS

Define las tareas de ejecución del robot en el controlador:

  • Nombre

  • Tipo (NORMAL, SEMISTATIC, etc.)

  • Programa asociado

  • Punto de entrada

Esto controla qué procesos funcionan simultáneamente.

  Configuraciones de distancias y tolerancias para la recuperación de posición del robot, usadas en movimientos automáticos y manuales.
CAB_EXEC_HOOKS

Estos son “ganchos” o hooks del sistema que asocian programas o rutinas con eventos internos como:

  • POWER_ON

  • START

  • RESET

Imagina que es un trigger que dice “cuando ocurra X, ejecutar Z”

CAB_TASK_MODULES

Este bloque especifica qué módulos de código se cargan para cada tarea definida:

  • Nombre del archivo (.sys, .mod, .prg)

  • Nombre del módulo

  • A qué tarea va asociado

Esto es lo que realmente hace que el robot sepa qué código ejecutar para cada parte del sistema.

MASTER_BOOL ???
AUTH_INTERACTIVE_UNITS ???
AUTH_CLIENTS ???
AUTH_CLIENT_PERMISSION ???
WORKDIR ???
MMC_ATTRIBUTE ???
MMC_FKEY ???
MMC_OUTLINE ???
MMC_CHOICE ???

 

CAB_EXEC_HOOKS:

-Routine "RESTORE_IO" -Shelf "POWER_ON" -Task "0"

Vamos a desglosar aquí que ocurre, la rutina (función de programación) RESTORE_IO (en este caso, definida en el archivo base.sys) es lanzada cuando se produce el evento de POWER_ON.

La tarea 0 no sé si está definida en algún sitio o es una forma de referirse al sistema operativo o una tarea que se ejecuta siempre en por encima de todo, al estilo SO.

 

SYS:CFG_1.0:2:0::
#
#
#
CAB_TASKS:

      -Name "MAIN" -Prog 0 -Task_in_forground "" -Type "NORMAL" -Entry "main"\
      -RewERIfStop 0
#
CAB_REGAIN_DIST:

      -Name "MAN" -Tcp_dist 0.010000 -Tcp_rot 0.200000 -Ext_dist 0.050000\
      -Ext_rot 0.200000

      -Name "AUTO" -Tcp_dist 0.500000 -Tcp_rot 1.570000 -Ext_dist 0.500000\
      -Ext_rot 1.570000
#
CAB_EXEC_HOOKS:

      -Routine "SYS_RESET" -Shelf "RESET" -Task "0"

      -Routine "SYS_RESET" -Shelf "START" -Task "0"

      -Routine "RESTORE_IO" -Shelf "POWER_ON" -Task "0"
#
#
CAB_TASK_MODULES:

      -File "ram1disk:base.sys" -ModName "BASE" -Task "0"

      -File "ram1disk:user.sys" -ModName "USER" -Task "0"
#
MASTER_BOOL:

#
AUTH_INTERACTIVE_UNITS:

#
AUTH_CLIENTS:

#
AUTH_CLIENT_PERMISSION:

#
WORKDIR:

#
#
MMC_ATTRIBUTE:

#
MMC_FKEY:

#
MMC_OUTLINE:

#
#
MMC_CHOICE:

#
#
#
#
#
#
#
#
#


SYS:CFG_1.0:2:1::
#
#
SYS_MISC:

#
#
CAB_TASKS:

      -Name "MAIN" -Prog 0 -Task_in_forground "" -Type "NORMAL" -Size 0\
      -StackSize 0 -BindRef 1 -Entry "main" -RewERIfStop 0
#
CAB_REGAIN_DIST:

      -Name "MAN" -Tcp_dist 0.050000 -Tcp_rot 0.200000 -Ext_dist 0.050000\
      -Ext_rot 0.200000

      -Name "AUTO" -Tcp_dist 0.500000 -Tcp_rot 1.570000 -Ext_dist 0.500000\
      -Ext_rot 1.570000
#
CAB_EXEC_HOOKS:

      -Routine "SYS_RESET" -Shelf "RESET" -Task "0"

      -Routine "SYS_RESET" -Shelf "START" -Task "0"

      -Routine "RESTORE_IO" -Shelf "POWER_ON" -Task "0"

      -Routine "glb_power_on" -Shelf "POWER_ON" -Task "0"

      -Routine "glb_start" -Shelf "START" -Task "0"

      -Routine "glb_restart" -Shelf "RESTART" -Task "0"

      -Routine "glb_stop" -Shelf "STOP" -Task "0"

      -Routine "glb_qstop" -Shelf "QSTOP" -Task "0"

      -Routine "glb_mode_switch" -Shelf "MODE_SWITCH" -Task "0"
#
#
CAB_TASK_MODULES:

      -File "ram1disk:base.sys" -ModName "BASE" -Task "0" -Storage "LOADED"\
      -Txres 0

      -File "ram1disk:user.sys" -ModName "USER" -Task "0" -Storage "LOADED"\
      -Txres 0

      -File "ram1disk:gluser.sys" -ModName "GLUSER" -Task "0" -Storage "LOADED"\
      -Txres 0

      -File "ram1disk:glbase.sys" -ModName "GLBASE" -Task "0" -Storage "LOADED"\
      -Txres 0

      -File "ram1disk:gltext.sys" -ModName "GLTEXT" -Task "0" -Storage "LOADED"\
      -Txres 0
#
MASTER_BOOL:

#
AUTH_INTERACTIVE_UNITS:

#
AUTH_CLIENTS:

#
AUTH_CLIENT_PERMISSION:

#
WORKDIR:

#
#
MMC_ATTRIBUTE:

#
MMC_FKEY:

#
MMC_OUTLINE:

#
#
MMC_CHOICE:

#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#

SYS:CFG_1.0:2:0::
#
#
#
CAB_TASKS:

      -Name "MAIN" -Prog 0 -Task_in_forground "" -Type "NORMAL" -Entry "main"

      -Name "com" -Prog 1 -Task_in_forground "MAIN" -Type "SEMISTATIC"\
      -Entry "haupt"
#
CAB_REGAIN_DIST:

      -Name "MAN" -Tcp_dist 0.010000 -Tcp_rot 1.000000 -Ext_dist 0.100000\
      -Ext_rot 1.570000

      -Name "AUTO" -Tcp_dist 0.500000 -Tcp_rot 1.570000 -Ext_dist 0.500000\
      -Ext_rot 1.570000
#
CAB_EXEC_HOOKS:

      -Routine "SYS_RESET" -Shelf "RESET" -Task "0"

      -Routine "SYS_RESET" -Shelf "START" -Task "0"

      -Routine "RESTORE_IO" -Shelf "POWER_ON" -Task "0"
#
#
CAB_TASK_MODULES:

      -File "ram1disk:base_mt.sys" -ModName "BASE_MT" -Task "com"

      -File "ram1disk:user.sys" -ModName "USER" -Task "0"

      -File "ram1disk:dat_mt16.sys" -ModName "DAT_MT16" -Task "0"

      -File "ram1disk:dat_mt16.sys" -ModName "DAT_MT16" -Task "com"

      -File "ram1disk:com200.sys" -ModName "Com200" -Task "com"

      -File "ram1disk:base.sys" -ModName "BASE" -Task "MAIN"
#
MASTER_BOOL:

#
AUTH_INTERACTIVE_UNITS:

#
AUTH_CLIENTS:

#
AUTH_CLIENT_PERMISSION:

#
WORKDIR:

#
#
MMC_ATTRIBUTE:

#
MMC_FKEY:

#
MMC_OUTLINE:

#
#
MMC_CHOICE:

#
#
#
#
#
#
#
#
#
#
#

CFG

SIO.CFG

Archivo:

SIO:CFG_1.0:2:0::

#

COM_PHY_CHANNEL_TYPE:


      -Name "sio" -Data1 0 -Data2 0 -Data3 0 -Data4 0 -Data5 0

#

COM_PHY_CHANNEL:


      -Name "sio1:" -Type "sio" -Channel 1 -Baudrate 9600 -Parity "none"\

      -NoOfBits 8 -NoOfStopBits 1.000000 -Duplex "full" -Data1 0 -Data2 0\

      -Data3 0 -Data4 0 -Data5 0


      -Name "printer1:" -Type "sio" -Channel 2 -Baudrate 9600 -Parity "none"\

      -NoOfBits 8 -NoOfStopBits 1.000000 -Duplex "full" -Data1 0 -Data2 0\

      -Data3 0 -Data4 0 -Data5 0


      -Name "sio3:" -Type "sio" -Channel 3 -Baudrate 9600 -Parity "none"\

      -NoOfBits 8 -NoOfStopBits 1.000000 -Duplex "full" -Data1 0 -Data2 0\

      -Data3 0 -Data4 0 -Data5 0


      -Name "sio4:" -Type "sio" -Channel 4 -Baudrate 9600 -Parity "none"\

      -NoOfBits 8 -NoOfStopBits 1.000000 -Duplex "full" -Data1 0 -Data2 0\

      -Data3 0 -Data4 0 -Data5 0

#

COM_TRP_TYPE:


      -Name "none" -Data1 0 -Data2 0 -Data3 0 -Data4 0 -Data5 0


      -Name "XON/XOFF" -Data1 0 -Data2 0 -Data3 0 -Data4 0 -Data5 0


      -Name "SLIP" -Data1 0 -Data2 0 -Data3 0 -Data4 0 -Data5 0

#

COM_TRP:


      -Name "printer1:" -Type "XON/XOFF" -PhyChannel "printer1:"\

      -HostName "none" -LocalAdress "100.100.100.101"\

      -RemoteAdress "100.100.100.102" -PortNo -1 -Data1 0 -Data2 0 -Data3 0\

      -Data4 0 -Data5 0

#

COM_APP_TYPE:


      -Name "RAP" -Data1 0 -Data2 0 -Data3 0 -Data4 0 -Data5 0 -InitFunc ""\

      -DrvC

onfig ""

#

COM_APP:


#

#

#

#

#

#

#

#

#

#

#

Según ChatGPT:

Este archivo es una configuración de comunicaciones serie (SIO) de un controlador ABB (RobotWare / RAPID). Define canales físicos, protocolos de transporte y aplicaciones que usan esos canales.


Voy sección por sección, de arriba a abajo.



---


1. Encabezado


SIO:CFG_1.0:2:0::


Indica:


Tipo de archivo: SIO (Serial I/O)


Versión del formato: CFG_1.0


Usado por RobotWare para configurar puertos serie RS-232/RS-422.




---


2. COM_PHY_CHANNEL_TYPE


COM_PHY_CHANNEL_TYPE:

      -Name "sio"


Define un tipo de canal físico llamado "sio".


👉 Es el tipo genérico de puerto serie del controlador ABB.



---


3. COM_PHY_CHANNEL (canales físicos reales)


Aquí se definen los puertos serie disponibles y sus parámetros eléctricos.


Ejemplo:


-Name "sio1:" -Type "sio" -Channel 1 -Baudrate 9600


Parámetros clave:


Name → Nombre lógico del puerto (ej. sio1:)


Channel → Número de puerto físico (1, 2, 3, 4)


Baudrate → 9600 baudios


Parity → none


NoOfBits → 8 bits de datos


NoOfStopBits → 1 bit de parada


Duplex → full (envío y recepción)



Puertos definidos:


Puerto lógico Canal físico Uso típico


sio1: 1 Comunicación serie genérica

printer1: 2 Impresora o dispositivo externo

sio3: 3 Libre

sio4: 4 Libre



👉 Todos usan RS-232 a 9600 8N1.



---


4. COM_TRP_TYPE (tipos de protocolo)


COM_TRP_TYPE:

      -Name "none"

      -Name "XON/XOFF"

      -Name "SLIP"


Define protocolos de transporte disponibles:


none → sin control de flujo


XON/XOFF → control de flujo por software


SLIP → encapsulación serie (menos común)




---


5. COM_TRP (transporte activo)


COM_TRP:

      -Name "printer1:" -Type "XON/XOFF" -PhyChannel "printer1:"


Aquí se asigna un protocolo a un puerto físico.


Significado:


El puerto printer1:


Usa control de flujo XON/XOFF


Se apoya en el canal físico printer1:



Las direcciones IP indicadas:


-LocalAdress "100.100.100.101"

-RemoteAdress "100.100.100.102"


⚠️ No son IP reales en este contexto

→ Son campos heredados del sistema de comunicaciones, no se usan en RS-232.


👉 En la práctica:


> El puerto printer1: está configurado para comunicar con una impresora o equipo serie usando XON/XOFF.





---


6. COM_APP_TYPE


COM_APP_TYPE:

      -Name "RAP"


Define el tipo de aplicación:


RAP → Comunicación usada por programas RAPID




---


7. COM_APP


COM_APP:


Está vacío → no hay ninguna aplicación RAPID asociada directamente a estos puertos en este archivo.


👉 La comunicación puede ser usada desde RAPID con instrucciones como:


Open "printer1:",\Write;

Write ...

Close;



---


Resumen rápido


Este archivo:


✅ Configura 4 puertos serie físicos

✅ Todos a 9600 baudios, 8N1, full duplex

✅ El puerto printer1: usa XON/XOFF

✅ Está pensado para impresora o dispositivo serie externo

✅ No define aún una aplicación específica, solo la infraestructura



---


Si quieres, puedo:


Decirte cómo usar printer1: desde RAPID


Explicar qué cable RS-232 usar


Ayudarte a migrarlo a RobotWare moderno


Revisar si sirve para un PLC o lector de códigos

Flujo de ejecución según ChatGPT

Perfecto, esa es la pregunta clave 👍

En los ABB S4 el flujo de ejecución no es intuitivo porque NO empieza en el programa RAPID directamente, sino en el sistema. Vamos paso a paso, de forma lineal, como realmente ocurre dentro del controlador.



---


🔁 Flujo real de ejecución en un ABB S4


Piensa en 3 capas:


1️⃣ Arranque del sistema

2️⃣ Carga de tareas RAPID

3️⃣ Ejecución del programa de usuario



---


1️⃣ ARRANQUE DEL CONTROLADOR


Cuando enciendes el S4:


➜ 1.1 Carga del sistema base


Se lee desde disquete (o disco):


BASE.SYS


Esto:


Inicializa CPU


Reserva memoria


Define qué otros .SYS se deben cargar



📌 Todavía NO hay RAPID ejecutándose



---


➜ 1.2 Carga de parámetros


Desde SYSPAR/:


SYS.CFG

MOC.CFG

PROC.CFG

EIO.CFG

...


Aquí el controlador aprende:


Qué robot es


Cómo se mueve


Qué entradas/salidas existen


Cuántas tareas habrá



📌 Aún no hay lógica de usuario



---


➜ 1.3 Carga de datos del robot


DAT_MT16.SYS


Define:


Longitudes de brazos


Ceros de ejes


Límites



⚠️ Sin esto, el robot no puede moverse



---


➜ 1.4 Creación del RAMDISK


Todo lo anterior se copia a:


RAMDISK/


👉 Desde este punto el sistema ya corre desde RAM, no desde disquete.



---


2️⃣ CARGA DE RAPID (NO ejecución todavía)


Ahora entra en juego USER.SYS



---


➜ 2.1 USER.SYS = “Índice de programas”


USER.SYS NO es un programa, es un loader.


Dentro dice cosas como:


Qué módulos RAPID cargar


En qué tareas


Qué módulo es principal



Ejemplo conceptual:


TASK PERS

LOAD PROG201.PRG


📌 Hasta ahora:


El programa existe en memoria


Pero no se está ejecutando




---


➜ 2.2 Compilación de RAPID


El controlador:


Lee PROG201.PRG


Lo compila


Verifica sintaxis



Si hay error → NO arranca



---


3️⃣ EJECUCIÓN DEL PROGRAMA RAPID


Aquí está la parte que suele confundir.



---


➜ 3.1 ¿Dónde empieza el programa?


En ABB S4 NO empieza en la primera línea.


Empieza en:


PROC main()


📌 SIEMPRE


No importa el nombre del archivo.



---


➜ 3.2 ¿Quién llama a main()?


El sistema operativo del S4:


BASE.SYS → USER.SYS → RAPID runtime → main()


Tú nunca llamas a main() manualmente.



---


➜ 3.3 Flujo típico dentro del programa


Ejemplo simplificado:


MODULE PROG201


PROC main()

    Init;

    WHILE TRUE DO

        Ciclo;

    ENDWHILE

ENDPROC


PROC Init()

    ! Inicialización

ENDPROC


PROC Ciclo()

    MoveJ p1, v100, z10, tool0;

ENDPROC


ENDMODULE


📌 El robot:


Entra a main()


Ejecuta Init


Se queda en el bucle infinito




---


🧠 Resumen mental (MUY IMPORTANTE)


El flujo NO es:


Disquete → PROG201.PRG → primera línea


El flujo REAL es:


POWER ON

 ↓

BASE.SYS

 ↓

SYSPAR/*.CFG

 ↓

DAT_MT16.SYS

 ↓

RAMDISK

 ↓

USER.SYS

 ↓

Carga módulos RAPID

 ↓

Busca main()

 ↓

Ejecuta main()



---


⚠️ Errores comunes


❌ “No hace nada al arrancar”

→ main() está vacío o no existe


❌ “Carga el programa pero no se mueve”

→ No hay bucle o está esperando una señal


❌ “No arranca el sistema”

→ Error en MOC.CFG o DAT_MT16.SYS



---


🧪 Ejercicio mental rápido


Si tú borras:


PROG201.PRG → el sistema arranca, pero sin programa


USER.SYS → no se carga ningún RAPID


BASE.SYS → el S4 no arranca


main() → el programa carga pero no corre




---


Si quieres, en el siguiente mensaje puedo:


Dibujarte el flujo como diagrama


Explicarte qué pasa cuando pulsas START en el FlexPendant


Revisar contigo un USER.SYS real línea por línea

Características

1000102303.jpg

https://www.robot-forum.com/robotforum/thread/48109-3hab2312-2-boot-disc-for-s4-needed/

 

1000102304.jpg

DSQC 317 Memory Board

DSQC 325 Main Computer

DSQC 326 Robot Computer

DSQC 256A System Board

DSQC 223 (x4) Digital I/O Board

1000102306.jpg

ELECTRICAL_TROUBLESHOOTING_MANUAL_FOR_IRB6400_INDUSTRIAL_ROBOT_&_S4_CONTROL_SYSTEM.pdf

Información extra sobre la compatibilidad con el software 

https://forums.robotstudio.com/discussion/13461/irb-1400-s4-controller-buy-boot-disk-but-can-039-t-use

https://www.robot-forum.com/robotforum/thread/603-irb6400-m94a-boot-discs/?pageNo=5

I/O parameters are in the User Manual starting at page 12-9.

Regarding the I/O boards, I suggest making parameter changes thru the teach pendant.

Great news that you have it running. Just guessing but it appears you have (2) BaseWare 2.1 disk packages for the IRB6400 - one labeled for the M94A IRB6400 and the other labeled for the M96 IRB6400. Could be that the load disk in the M94A disk pack is bad


While BaseWare OS 2.1 itself has no M96 version, there are IRB disks that go with BW2.1 for the IRB6400 that are either Elmo/Siemens (M94A) or M96. Perhaps the disk pack is labeled M96 to show which version IRB disk it contained. The IRB1400, 2400 & 3400 also ran BW 2.1 with their version IRB disks but only the IRB6400 robot had M94A & M96 versions manipulators.


BaseWare OS 2.1 is compatible with:

All 3 Robot Computer boards (DSQC300, 326, 335) as long as the installed firmware EPROMs were the RND/RNE or newer.

All 3 Main Computer boards are technically compatible but the slower 20Mhz DSQC306 can have external axis issues, the 25Mhz DSQC316 solves that but still lacks an internal power failure function available in BW2.1 & newer that the DSQC325 fixes.

External Memory boards DQSC317, 323, 324.


The DSQC325, 326, 323 combination is very compatible with BW2.1 as this was the standard setup for thousands of robots in GM, Chrysler, Ford & many others. I've personally loaded BW2.1 in well over a hundred S4 robots in this board configuration regardless of manipulator type.


Somewhat bewildered by changes needed in the MOC file unless it was to add an external axis. The IRB disk during the software load sets up the MOC file with the proper motors and associated parameters. The only editing of the MOC normally needed would be to correct the Fine Calibration data and to add external axes.

¡Qué buena noticia que lo tengas funcionando! Es solo una suposición, pero parece que tienes dos paquetes de discos con la versión base 2.1 para el IRB6400: uno para el IRB6400 m94a y el otro para el IRB6400 m96. Es posible que el disco de carga del paquete de discos m94a esté dañado.


Si bien el sistema operativo base 2.1 no tiene una versión m96, existen discos IRB compatibles con BW2.1 para el IRB6400, que son Elmo/Siemens (m94a) o m96. Quizás el paquete de discos esté etiquetado como m96 para indicar qué versión del disco IRB contenía. Los IRB1400, 2400 y 3400 también ejecutaban BW2.1 con sus discos IRB, pero solo el robot IRB6400 tenía manipuladores de las versiones m94a y m96. El sistema operativo base 2.1 es compatible con:

Las tres placas de computadora robótica (DSQC300, 326, 335), siempre que las EPROM de firmware instaladas sean RND/RNE o posteriores.

Las tres placas de computadora principal son técnicamente compatibles, pero la DSQC306 de 20 MHz, más lenta, puede presentar problemas con los ejes externos. La DSQC316 de 25 MHz soluciona este problema, pero aún carece de la función de fallo de alimentación interna disponible en BW2.1 y posteriores, que la DSQC325 corrige.

Las placas de memoria externa DQSC317, 323, 324.


La combinación DSQC325, 326, 323 es muy compatible con BW2.1, ya que esta era la configuración estándar para miles de robots en GM, Chrysler, Ford y muchos otros. Personalmente, he instalado BW2.1 en más de cien robots S4 con esta configuración de placa, independientemente del tipo de manipulador.


 Estoy un poco desconcertado por los cambios necesarios en el archivo MOC, a menos que sea para añadir un eje externo. Durante la carga del software, el disco IRB configura el archivo MOC con los motores y parámetros asociados adecuados. La única edición del MOC que normalmente se necesita es corregir los datos de calibración fina y añadir ejes externos.

DSQC 326 Robot Computer

The robot computer, controls the system's I/O, axis control, serial communication and teach pendant communication.

Conector: X5 SERIAL LINKS

1000102310.jpg

1000102311.png

-------

If I remember correct, the Serial Link RAP option disk that came with a lot of software was the key. Been about 25 years since played with the S4 RS232.

It's been 20 years for me too.

With Advanced Functions you can also read/write serial channels. RAP protocol also required special basic software (Basic Commware, BaseWare OS RAP)

-------

Si no recuerdo mal, el disco opcional Serial Link RAP que venía con mucho software fue clave. Hace unos 25 años que no juego con el S4 RS232.


Yo también hace 20 años.

Con las Funciones Avanzadas también se pueden leer y escribir canales serie. El protocolo RAP también requería software básico especial (Basic Commware, BaseWare OS RAP).

-------

Referencia:

https://www.robot-forum.com/robotforum/thread/51058-abb-ira-1400-rs232-port/

 

Videos de Youtube

https://youtube.com/shorts/VgjJ-GoykxM?si=A-tX33s-JCo4IiAG

 

IRB6400-3518

DSQC 317 Memory Board

DSQC 335 Main Computer

DSQC 326 Robot Computer

DSQC 256A System Board

DSQC 223 (x4) Digital I/O Board

1000105393.jpg

RobotWare & disquetes info

1000106040.jpg

https://forums.robotstudio.com/discussion/13461/irb-1400-s4-controller-buy-boot-disk-but-can-039-t-use

1000105442.webp

1000105443.png

Pregunta sobre los disquetes y el serial

Para el software S4, el disco de arranque es el disco (1) del software. Carga la información necesaria para cargar y descomprimir el software y las opciones, y también contiene gran parte del software principal compactado.

El número de serie del software debe ser el mismo en todos los discos BaseWare.

El software no puede identificar el número de serie del controlador ni el robot conectado. Debe asegurarse de tener el disco IRB correcto para el tipo de robot.

Los archivos disc.id tienen caracteres incrustados; cambiar el número de serie no los modificará.

---------------------------------------------------------------------------------

For S4 software, the boot disk is disk (1) of the software, it loads the information needed to load & unpack the software & options and also contains much of the compacted core software.

The serial # on the software needs to be the same on all the BaseWare disks.

The software cannot tell what the controller serial # is nor can it tell what robot is connected. You need to make sure you have the right IRB disk for the robot type you have.

disc.id files have embedded characters, changing the serial # won't change the embedded characters

----------------------------

El software S4 utiliza disquetes formateados para PC. El disco 1 de RobotWare contiene un archivo de arranque. Funciona con el firmware para cargar el sistema desde los archivos de los disquetes.

----------------------------

S4 software uses normal PC formatted floppies. Disk 1 of the RobotWare will have a boot file. It works with the firmware to load the system from the files on the floppy disks.

Referencia: https://test.robot-forum.com/robotforum/thread/51054-missing-disks-for-abb-irb-1400-with-s4-controller/

 

Serializar y deserializar instrucciones

¡Excelente! Has subido el manual de referencia de RAPID, el lenguaje de programación de los robots ABB. Este es un caso de estudio perfecto para un serializador/deserializador.


Analizando el documento, estamos ante un lenguaje industrial robusto con:


· Tipos de datos complejos: robtarget (posición + orientación + configuración + ejes externos), jointtarget, speeddata, zonedata, etc.

· Instrucciones con sintaxis variada: Desde simples (Set do1;) hasta complejas con múltiples argumentos opcionales y mutuamente excluyentes (MoveL [\Conc] ToPoint Speed [ \V ] | [ \T ] Zone [ \Z ] Tool [ \WObj ]).

· Estructura modular: Módulos, rutinas, datos.


Tu idea es correcta: generar el deserializador automáticamente a partir de la especificación de las instrucciones es el enfoque más mantenible y escalable. Te propongo una arquitectura para abordar este problema.


---


Arquitectura Propuesta: Enfoque de Metaprogramación


Dividiremos el problema en tres componentes principales:


1. Un Especificador de Instrucciones (Formato Intermedio): Definir un DSL (Domain Specific Language) en JSON/YAML que capture la estructura de cada instrucción de RAPID.

2. Un Generador de Código: Un script (en Python, por ejemplo) que lea ese DSL y genere el código del serializador/deserializador en tu lenguaje objetivo (C, C++, Rust, Python, etc.).

3. La Librería de Serialización/Deserialización: El código generado que hace el trabajo pesado, apoyándose en una capa base para leer/escribir bytes y manejar los tipos de datos.


Paso 1: Definir el Formato Intermedio (DSL)


Necesitamos una forma de describir cada instrucción. Usaré JSON como ejemplo por su claridad.


```json

{

  "instructions": [

    {

      "name": "MoveL",

      "description": "Moves the robot linearly",

      "syntax": "MoveL [\\Conc] ToPoint Speed [ \\V ] | [ \\T ] Zone [ \\Z ] Tool [ \\WObj ]",

      "opcode": 0x01,

      "arguments": [

        { "name": "Conc", "type": "switch", "optional": true, "tag": 0x01 },

        { "name": "ToPoint", "type": "robtarget", "required": true },

        { "name": "Speed", "type": "speeddata", "required": true },

        { "name": "V", "type": "num", "optional": true, "group": "speed_mode", "tag": 0x02 },

        { "name": "T", "type": "num", "optional": true, "group": "speed_mode", "tag": 0x03 },

        { "name": "Zone", "type": "zonedata", "required": true },

        { "name": "Z", "type": "num", "optional": true, "tag": 0x04 },

        { "name": "Tool", "type": "tooldata", "required": true },

        { "name": "WObj", "type": "wobjdata", "optional": true, "tag": 0x05 }

      ]

    },

    {

      "name": "Set",

      "opcode": 0x02,

      "arguments": [

        { "name": "Signal", "type": "signaldo", "required": true },

        { "name": "Value", "type": "dionum", "required": true }

      ]

    }

    // ... instrucciones para IF, FOR, WHILE, etc.

  ]

}

```


Puntos clave de este DSL:


· opcode: Un byte único que identifica la instrucción.

· group: Maneja argumentos mutuamente excluyentes (ej. \V o \T). En la serialización, primero se escribe un byte que indica qué argumento del grupo está presente.

· tag: Un identificador (ej. un byte) para argumentos opcionales, permitiendo un formato tipo TLV (Type-Length-Value).

· type: Puede ser un tipo primitivo (num, bool, string) o un tipo compuesto (robtarget). Estos tipos compuestos también necesitarán su propia definición en el DSL.


Paso 2: Definir los Tipos de Datos Compuestos


Los tipos como robtarget, speeddata, etc., tienen una estructura fija. Debemos definirlos también.


```json

{

  "data_types": [

    {

      "name": "robtarget",

      "fields": [

        { "name": "trans", "type": "pos" },

        { "name": "rot", "type": "orient" },

        { "name": "robconf", "type": "confdata" },

        { "name": "extax", "type": "extjoint" }

      ]

    },

    {

      "name": "speeddata",

      "fields": [

        { "name": "v_tcp", "type": "num" },

        { "name": "v_ori", "type": "num" },

        { "name": "v_leax", "type": "num" },

        { "name": "v_reax", "type": "num" }

      ]

    }

    // ... definiciones para pos, orient, confdata, extjoint, etc.

  ]

}

```


Paso 3: El Generador de Código


El generador leerá estos JSONs y producirá código en tu lenguaje de destino. A grandes rasgos, hará:


1. Para cada tipo de dato (robtarget, speeddata, etc.):

   · Generar una función serialize_Tipo() que escribe cada campo en orden en un buffer.

   · Generar una función deserialize_Tipo() que lee el buffer y reconstruye la estructura.

2. Para cada instrucción:

   · Generar una función serialize_Instruccion() que:

     1. Escribe el opcode.

     2. Escribe los argumentos requeridos en orden.

     3. Para argumentos opcionales, escribe un byte de máscara de bits indicando cuáles están presentes, seguido de los datos de cada uno.

     4. Para grupos mutuamente excluyentes, escribe un byte indicando la opción seleccionada y luego sus datos.

   · Generar una función deserialize_Instruccion() que haga lo inverso.


Paso 4: Formato de Serialización Binaria Propuesto


Dado que es para una máquina virtual, un formato binario es ideal.


```

+-------------------+-------------------+-------------------+-------------------+

| Opcode (1 byte) | Flags (1 byte) | Argumentos... |

+-------------------+-------------------+---------------------------------------+

```


· Opcode: Identifica la instrucción (ej. MoveL = 0x01).

· Flags: Byte de máscara de bits. Cada bit representa un argumento opcional o un grupo. Por ejemplo:

  · Bit 0: \Conc presente

  · Bit 1: \V presente (si está en un grupo)

  · Bit 2: \T presente

  · Bit 3: \Z presente

  · Bit 4: \WObj presente

· Argumentos: Se serializan en un orden predefinido.

  · Requeridos: Siempre presentes.

  · Opcionales: Solo se escriben si su flag está activo.

  · Grupos: Solo se escribe el argumento cuyo flag está activo.


Ejemplo de serialización de MoveL (sin opcionales):


```

[0x01] [0b00000000] [datos_de_ToPoint] [datos_de_Speed] [datos_de_Zone] [datos_de_Tool]

```


Ejemplo con \V y \WObj:


```

[0x01] [0b00000010 | 0b00010000] [datos_de_ToPoint] [datos_de_Speed] [V_value (4 bytes)] [datos_de_Zone] [datos_de_Tool] [datos_de_WObj]

```


Paso 5: Estructura del Proyecto


```

rapid-serializer/

├── spec/ # Especificación en JSON

│ ├── data_types.json

│ └── instructions.json

├── generator/ # Script generador (Python)

│ └── generate.py

├── runtime/ # Librería base (en tu lenguaje objetivo)

│ ├── buffer.h/cpp # Manejo de buffer de lectura/escritura

│ └── types.h/cpp # Definiciones de tipos base (num, bool, etc.)

├── generated/ # Código generado automáticamente

│ ├── rapid_types.h/cpp # Serializadores de tipos de datos

│ └── rapid_instructions.h/cpp # Serializadores de instrucciones

└── vm/ # Tu máquina virtual que usará el serializador

    └── ...

```


Conclusión


Este enfoque te da:


· Mantenibilidad: Para añadir una nueva instrucción, solo editas el JSON y vuelves a ejecutar el generador. No tocas el código de la VM.

· Consistencia: Las reglas de serialización son las mismas para todas las instrucciones.

· Flexibilidad: Puedes generar código para cualquier lenguaje de destino cambiando las plantillas en el generador.


¿Te gustaría que profundice en alguno de estos pasos? Por ejemplo, podría mostrarte cómo sería el código Python del generador, o cómo sería la función serialize_robtarget en C/C++.

ANTLRv4

ANTLRv4

Installing ANTLR4 in your Linux

PDF - Installing ANTLR4 in your Linux (2026-04-15)

Web - Installing ANTLR4 in your Linux (2026-04-15)

Java

Make sure you have Java installed. Check it with

java -version

If you don’t have it, install it normally with your distro package manager.


ANTLR4

Option 1: Using the package manager

Modern Linux distros already include a package for ANTLR, although it is probably too old.


sudo apt-get install antlr4

Option 2: Getting the jar file

Alternatively, you can go to https://www.antlr.org and follow the instructions there, which mainly consist of:


# Download antlr4 jar file to /usr/local/lib

cd /usr/local/lib

sudo wget http://www.antlr.org/download/antlr-4.13.2-complete.jar

IMPORTANT: Do NOT use earlier versions than 4.13, the API is different and it will not work with our code.


You will also need to create a command file that will ease the call to Antlr4. Edit a file named antlr4 and write into it:


#! /bin/bash

export CLASSPATH=".:/usr/local/lib/antlr-4.13.2-complete.jar:$CLASSPATH"

java -jar /usr/local/lib/antlr-4.13.2-complete.jar "$@"

save the file, and give it execution permission:


chmod +x antlr4

finally, move it to a folder in the default PATH


sudo mv antlr4 /usr/local/bin

C++ Runtime

Although Antlr4 is a Java-universe project, it can be instructed to generate C++ code. The resulting code uses some C++ classes included in a shared library (the runtime) that is not installed by default with Antlr4. To install it we can follow the steps below:


Option 1: Using the package manager

Some linux distributions have this library packaged. Installing the dev package should pull the binaries too. Make sure the version matches the 4.13 ANTLR version installed.


sudo apt-get install libantlr4-runtime-dev

Option 2: Compiling from source

If your distribution does not provide this package, you’ll need to install it from source:


First, install required tools and dependencies:


sudo apt-get install cmake uuid-dev pkgconf

Then, download the source from https://www.antlr.org/download.html and compile it.


# download source

mkdir antlr-src && cd antlr-src

wget http://www.antlr.org/download/antlr4-cpp-runtime-4.13.2-source.zip

# unzip file

unzip antlr4-cpp-runtime-4.13.2-source.zip

# create build directory for cmake

mkdir build && cd build

# create makefiles

cmake .. -DANTLR_JAR_LOCATION=/usr/local/lib/antlr-4.13.2-complete.jar -DCMAKE_INSTALL_PREFIX=/usr/local -DWITH_DEMO=True

# build and install

make

sudo make install

If you installed Antlr4 from a distribution package, your ANTLR_JAR_LOCATION will be something like /usr/share/java/antlr4-4.13.2.jar. Examine the contents of the package and set the right path in the cmake command.


Adapting Makefiles

Makefiles provided with the class exercises and lab project expect Antlr4 runtime to be in /assig/$USER/cl/runtime


In order to run them in your computer, you need to edit the Makefile and replace line 80


ANTLR_ROOT := /assig/$(USER)/cl/runtime

with


If you installed from distribution packages:


ANTLR_ROOT := /usr

If you installed the jarfile directly, set it to the folder where you created the antlr4 command file


ANTLR_ROOT := /usr/local

Once the Makefile is fixed, you should be able to compile the class examples:


cd intro/lab1/Calc

make antlr

make

./main calc1.txt

Setting up Library Paths

If you get errors when running your ./main program, it may be that the loader is not finding the runtime.


If you installed the runtime in /usr/local/lib you may need to update loader paths:


sudo ldconfig

If you installed the runtime in some other folder, you need to set the right environment variables so that the loader finds it:


export LD_LIBRARY_PATH=/my/runtime/folder

You can add this line to your .bashrc to avoid having to do it for every session.


MacOS users: in MacOS the variable name is DYLD_LIBRARY_PATH


Using grun to visualize trees

You can use grun to visualize and debug the trees your grammar is creating.


Details on how to do so are given in the Introduction to ANTLR4 page.


However, to run it in your computer you’ll need to set up the paths for the java components of ANTLR4. Edit your $HOME/.bashrc file and add the commands:


export ANTLR4=/usr/share/java

if ( $?CLASSPATH ) then

    export CLASSPATH=.:$ANTLR4/antlr-4.13.2-complete.jar:$CLASSPATH

else

    export CLASSPATH=.:$ANTLR4/antlr-4.13.2-complete.jar

fi

If you installed antlr4 by getting the jarfile instead of using the package manager, you may need to change the path /usr/share/java to another location (e.g. /usr/local/share/java or wherever you installed it)


Once .bashrc has been updated, open a new terminal to get the new configuration loaded.

ANTLRv4

Página nueva

Te ayudo a generar el código en C++ para tu gramática de ABB y a entender la diferencia entre Listener y Visitor.


1. Generación del Código C++ con ANTLR


Primero, descarga los archivos abbLexer.g4 y abbParser.g4 en el mismo directorio. Luego, ejecuta este comando en la terminal para generar el código C++ :


```bash

antlr4 -Dlanguage=Cpp -visitor -listener abbLexer.g4 abbParser.g4

```


Esto creará una serie de archivos .h y .cpp. Los más importantes son:


· abbLexer.h/cpp: El Analizador Léxico.

· abbParser.h/cpp: El Analizador Sintáctico.

· abbBaseListener.h/cpp y abbBaseVisitor.h/cpp: Clases base para tu propio código.


2. Crear un main.cpp para probar un programa


Para probarlo, necesitas un archivo main.cpp que lea un archivo de entrada, lo procese y muestre el árbol sintáctico. Aquí tienes una plantilla que puedes usar :


```cpp

#include <iostream>

#include <fstream>


#include "antlr4-runtime.h"

#include "abbLexer.h"

#include "abbParser.h"


using namespace antlr4;


int main(int argc, const char* argv[]) {

    if (argc < 2) {

        std::cerr << "Uso: " << argv[0] << " <archivo_de_entrada>" << std::endl;

        return 1;

    }


    // 1. Crear el flujo de entrada desde el archivo

    std::ifstream stream;

    stream.open(argv[1]);

    if (!stream) {

        std::cerr << "Error: No se pudo abrir el archivo " << argv[1] << std::endl;

        return 1;

    }


    // 2. Crear el lexer y el parser

    ANTLRInputStream input(stream);

    abbLexer lexer(&input);

    CommonTokenStream tokens(&lexer);

    abbParser parser(&tokens);


    // 3. Obtener el token de errores e iniciar el parsing

    parser.removeErrorListeners();

    parser.addErrorListener(new ConsoleErrorListener());

    

    tree::ParseTree* tree = parser.module_(); // 'module_' es la regla principal en abbParser.g4


    // 4. Imprimir el árbol sintáctico en formato LISP

    std::cout << "Árbol Sintáctico: " << tree->toStringTree(&parser) << std::endl;


    return 0;

}

```


3. Para qué sirven Listener y Visitor


Ambos son patrones de diseño para recorrer el árbol sintáctico y ejecutar tu propia lógica (como calcular valores, comprobar errores o traducir el código), pero su filosofía es distinta .


Cuándo usar cada uno:


· Visitor (Visitante): Te da el control total. Debes llamar explícitamente a visit() para recorrer los nodos hijos. Es ideal si necesitas retornar valores de los nodos (ej. al evaluar una expresión matemática) y quieres controlar el orden de la visita .

· Listener (Oyente): Es automático. El ParseTreeWalker de ANTLR recorre el árbol y va llamando a los métodos enterRegla y exitRegla . Es muy útil cuando necesitas ejecutar acciones antes y después de procesar un bloque, como manejar alcances de variables (entrar/salir de una función) o transformar el formato de salida.


Resumen práctico:


· Si estás creando un intérprete que calcula valores, te conviene Visitor.

· Si estás haciendo un traductor o analizador de alcances, el Listener puede ser más sencillo.


Importante: Para compilar, necesitarás la librería de runtime de ANTLR para C++. Si usas CMake, te recomiendo el script de este repositorio de ejemplo, que descarga y compila el runtime por ti automáticamente .


Espero que esto te aclare los pasos. Si tienes una duda más concreta sobre qué patrón usar para tu proyecto, puedes decírmelo

 

Por supuesto. Aquí tienes una versión más divulgativa y estructurada, lista para ser usada como la primera parte de un artículo de blog sobre ANTLR y C++.


---


De la Gramática al Código: Tu Primer Compilador con ANTLR y C++


Si alguna vez te has enfrentado a la tarea de leer un archivo de configuración extraño, un lenguaje de juguete o un formato de datos propietario, sabrás lo tedioso que es escribir un analizador (parser) a mano contando paréntesis y comas. Ahí es donde brilla ANTLR (ANother Tool for Language Recognition).


En esta primera entrada, vamos a tomar una gramática real de un robot industrial (ABB RAPID) y la vamos a convertir en un programa funcional en C++ que lea y valide archivos .sys. Veremos cómo generar el esqueleto del compilador y, lo más importante, entenderemos para qué demonios sirven el Listener y el Visitor (las dos grandes superestrellas o grandes dolores de cabeza de ANTLR).


1. Paso 1: Las Materias Primas (Lexer y Parser)


Partimos de dos archivos que definen el lenguaje:


· abbLexer.g4: Define cómo se parten las palabras y símbolos (módulos, :=, PROC, números).

· abbParser.g4: Define la gramática, es decir, el orden lógico de esas palabras (un módulo contiene datos, procedimientos, etc.).


2. Paso 2: Invocando al Mago (Generación de Código C++)


El primer paso es casi mágico. Con los archivos .g4 en una carpeta, abrimos la terminal y lanzamos el hechizo de ANTLR para C++:


```bash

antlr4 -Dlanguage=Cpp -visitor -listener abbLexer.g4 abbParser.g4

```


¿Qué hace este comando?


· -Dlanguage=Cpp: Le dice a ANTLR que no queremos Java ni Python, queremos clases C++ de alto rendimiento.

· -visitor -listener: Le pedimos que nos prepare el terreno para ambas estrategias de recorrido del árbol (luego veremos la diferencia).


Tras ejecutar esto, la carpeta se llenará de archivos .h y .cpp. No te asustes, tú solo vas a tocar main.cpp.


3. Paso 3: El Punto de Entrada (main.cpp)


Necesitamos un programa que coja un archivo de texto, se lo pase a nuestro recién nacido analizador y nos diga si es válido o no. Aquí tienes el main.cpp mínimo viable para C++:


```cpp

#include <iostream>

#include <fstream>

#include "antlr4-runtime.h"

#include "abbLexer.h"

#include "abbParser.h"


using namespace antlr4;


int main(int argc, const char* argv[]) {

    // 1. Abrir el archivo de ejemplo

    std::ifstream stream(argv[1]);

    ANTLRInputStream input(stream);

    

    // 2. Fase Léxica: Romper el texto en Tokens

    abbLexer lexer(&input);

    CommonTokenStream tokens(&lexer);

    

    // 3. Fase Sintáctica: Construir el Árbol

    abbParser parser(&tokens);

    tree::ParseTree* tree = parser.module_(); // 'module_' es la regla raíz


    // 4. Imprimir el resultado

    std::cout << "Árbol generado: " << tree->toStringTree(&parser) << std::endl;

    

    return 0;

}

```


Si compilas este código (enlazando con la librería de runtime de ANTLR) y le pasas un archivo .sys válido, verás en consola un montón de paréntesis representando la estructura jerárquica del código. ¡Ya tienes un reconocedor sintáctico!


4. El Dilema: ¿Listener o Visitor?


Aquí viene la parte filosófica. Ya sabemos leer el archivo, pero ahora queremos hacer algo con esa información (traducirlo a otro lenguaje, calcular posiciones del robot, pintar un diagrama...). ANTLR nos da dos herramientas para recorrer ese árbol que acabas de imprimir. Elegir bien te ahorrará muchas horas de depuración.


Característica Listener (El Piloto Automático) Visitor (El Conductor Manual)

Recorrido Automático. Un "Andador" (ParseTreeWalker) recorre cada nodo en profundidad. Manual. Tú escribes visit() explícitamente para navegar a los hijos que quieras.

Control de Flujo No puedes pararlo. Siempre visita todos los nodos. Tú decides si visitas el hijo izquierdo, el derecho o ninguno.

Retorno de Datos No devuelves valores directamente (normalmente usas variables externas o una pila). Sí devuelve valores. Ideal para expresiones matemáticas (visitSuma devuelve un int).

Caso de Uso Ideal Traducción de formato (ej. pasar de ABB a Python) o Análisis de alcance (entrar/salir de una función). Evaluación/Interpretación directa o Análisis Semántico que requiere calcular tipos complejos.


En resumen para tu blog:


· Si tu objetivo es imprimir el código en otro lenguaje o contar cuántas veces aparece la palabra PROC, usa Listener.

· Si tu objetivo es ejecutar el programa del robot en un simulador virtual (hacer que el robot se mueva según las coordenadas del archivo), usa Visitor.


5. Próximos Pasos


En la siguiente parte de esta serie, implementaremos un Visitor personalizado para extraer todas las declaraciones de variables TOOLDATA del archivo del robot y generar un archivo JSON con la configuración. ¡Nos vemos en el código!