[{"data":1,"prerenderedAt":73},["ShallowReactive",2],{"integration-node-red-contrib-abb-gofa\u002F":3},{"_id":4,"categories":5,"author":7,"description":9,"npmOwners":10,"npmScope":12,"name":4,"ffCertified":13,"downloads":14,"version":16,"updatedAt":17,"maintainers":18,"homepage":21,"bugs":22,"repository":24,"time":27,"lastUpdated":17,"created":28,"license":69,"githubOwner":70,"githubRepo":4,"examples":71,"readme":72},"node-red-contrib-abb-gofa",[6],"catalogue",{"name":8},"Nantaphat Yoktaworn","Node-RED nodes for controlling an ABB GoFa (CRB 15000) collaborative robot via RWS and a RAPID TCP socket server",[11],"nnnn022",null,false,{"week":15},3097,"2.4.12","2026-07-22T06:45:38.442Z",[19],{"name":11,"email":20},"nantaphat.yoktaworn@gmail.com","https:\u002F\u002Fgithub.com\u002FNantaphat-Yoktaworn\u002Fnode-red-contrib-abb-gofa#readme",{"url":23},"https:\u002F\u002Fgithub.com\u002FNantaphat-Yoktaworn\u002Fnode-red-contrib-abb-gofa\u002Fissues",{"type":25,"url":26,"directory":4},"git","git+https:\u002F\u002Fgithub.com\u002FNantaphat-Yoktaworn\u002Fnode-red-contrib-abb-gofa.git",{"created":28,"modified":17,"1.0.1":29,"1.0.2":30,"1.1.0":31,"1.2.0":32,"1.2.1":33,"1.2.2":34,"1.2.3":35,"1.3.0":36,"1.4.0":37,"1.4.1":38,"1.4.2":39,"1.4.3":40,"1.5.0":41,"1.6.0":42,"1.7.0":43,"1.7.1":44,"2.0.0":45,"2.1.0":46,"2.1.1":47,"2.2.0":48,"2.2.1":49,"2.2.2":50,"2.2.3":51,"2.2.4":52,"2.2.5":53,"2.2.6":54,"2.3.0":55,"2.3.1":56,"2.4.1":57,"2.4.2":58,"2.4.3":59,"2.4.4":60,"2.4.5":61,"2.4.6":62,"2.4.7":63,"2.4.8":64,"2.4.9":65,"2.4.10":66,"2.4.11":67,"2.4.12":68},"2026-07-08T06:41:56.520Z","2026-07-08T06:41:56.702Z","2026-07-08T06:52:06.755Z","2026-07-09T02:58:29.985Z","2026-07-09T07:34:37.600Z","2026-07-09T08:15:25.825Z","2026-07-10T02:52:35.928Z","2026-07-10T03:06:04.717Z","2026-07-10T04:38:25.362Z","2026-07-10T04:57:43.380Z","2026-07-10T08:00:30.697Z","2026-07-10T08:14:54.951Z","2026-07-14T06:34:38.270Z","2026-07-15T02:25:19.284Z","2026-07-15T03:09:40.318Z","2026-07-15T04:38:44.701Z","2026-07-15T06:18:31.209Z","2026-07-15T08:24:54.276Z","2026-07-15T08:54:08.211Z","2026-07-16T01:43:15.905Z","2026-07-16T02:50:09.873Z","2026-07-16T03:07:48.503Z","2026-07-16T03:30:32.071Z","2026-07-16T06:42:26.726Z","2026-07-16T07:47:40.148Z","2026-07-16T09:15:36.348Z","2026-07-17T03:48:05.877Z","2026-07-17T08:53:22.993Z","2026-07-17T09:32:07.593Z","2026-07-20T04:00:53.202Z","2026-07-20T05:58:49.331Z","2026-07-20T08:45:21.126Z","2026-07-21T04:13:07.535Z","2026-07-21T04:48:25.955Z","2026-07-21T09:44:28.368Z","2026-07-21T10:02:10.252Z","2026-07-22T02:31:17.103Z","2026-07-22T03:42:51.436Z","2026-07-22T04:06:19.584Z","2026-07-22T04:14:26.811Z","2026-07-22T06:45:38.292Z","MIT","Nantaphat-Yoktaworn",[],"\u003Ch1 id=\"node-red-contrib-abb-gofa\">\u003Ca class=\"header-anchor\" href=\"#node-red-contrib-abb-gofa\">node-red-contrib-abb-gofa\u003C\u002Fa>\u003C\u002Fh1>\n\u003Cp>Node-RED nodes for controlling an \u003Cstrong>ABB GoFa (CRB 15000)\u003C\u002Fstrong> collaborative robot with an \u003Cstrong>OmniCore\u003C\u002Fstrong> controller over the local network. Motion, telemetry, I\u002FO, RAPID program control, saved-point teach &amp; replay — no extra ABB licenses required.\u003C\u002Fp>\n\u003Cp>Developed and live-tested against a GoFa 12 (CRB 15000-12\u002F1.27) on an OmniCore C30, RobotWare 7.21.\u003C\u002Fp>\n\u003Ch2 id=\"-safety-and-security\">\u003Ca class=\"header-anchor\" href=\"#-safety-and-security\">⚠️ Safety and security\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>This package moves a real robot arm.\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>The software \u003Cstrong>STOP\u003C\u002Fstrong> command and Node-RED itself are \u003Cem>not\u003C\u002Fem> safety functions. The robot's own safety controller, reduced-speed collaborative limits, and the physical emergency stop are the only real safety layer. Never rely on a flow to keep people safe.\u003C\u002Fli>\n\u003Cli>The RAPID socket server (port 1025) accepts motion commands from \u003Cstrong>anyone who can reach the robot's IP — there is no authentication on that port\u003C\u002Fstrong>. Run the robot on an isolated or firewalled network segment. The same goes for RWS credentials sent over HTTPS with certificate checking disabled (the controller uses a self-signed certificate).\u003C\u002Fli>\n\u003Cli>Jog\u002Frotate step limits (50 mm \u002F 30°) are enforced in the RAPID module, not in Node-RED — if you edit \u003Ccode>MainModule.mod\u003C\u002Fcode>, keep them.\u003C\u002Fli>\n\u003Cli>The node property panels have live-action buttons (jog, move, motors on\u002Foff, …) backed by Node-RED admin HTTP endpoints. The browser confirmation dialogs are convenience only, not a security control. \u003Cstrong>Configure \u003Ca href=\"https:\u002F\u002Fnodered.org\u002Fdocs\u002Fuser-guide\u002Fruntime\u002Fsecuring-node-red\">\u003Ccode>adminAuth\u003C\u002Fcode>\u003C\u002Fa> on any Node-RED instance controlling a real robot\u003C\u002Fstrong> — it is required, not optional. As of 2.4.10 these motion endpoints are \u003Cstrong>refused (HTTP 403) when \u003Ccode>adminAuth\u003C\u002Fcode> is not configured\u003C\u002Fstrong>, so an unauthenticated editor port can no longer trigger motion. If your instance has no \u003Ccode>adminAuth\u003C\u002Fcode> but is genuinely protected another way (isolated cell network \u002F firewall \u002F reverse proxy), tick \u003Cstrong>Allow insecure live control\u003C\u002Fstrong> on the \u003Ccode>gofa-robot\u003C\u002Fcode> config node to re-enable them at your own risk. Deployed flows are unaffected either way — this guard only covers the editor buttons.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"how-it-works\">\u003Ca class=\"header-anchor\" href=\"#how-it-works\">How it works\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Two transports, one rule — \u003Cstrong>motion goes through a TCP socket, everything else goes through RWS\u003C\u002Fstrong>:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>TCP socket (port 1025)\u003C\u002Fstrong> — a small RAPID program (\u003Ccode>rapid\u002FMainModule.mod\u003C\u002Fcode>, bundled with this package) runs a socket server on the controller. Each motion node opens a connection, sends one newline-terminated command (\u003Ccode>HOME\u003C\u002Fcode>, \u003Ccode>GOTOJ…\u003C\u002Fcode>, \u003Ccode>J1+10\u003C\u002Fcode>, …), reads one \u003Ccode>OK:\u003C\u002Fcode>\u002F\u003Ccode>ERR:\u003C\u002Fcode> reply, and closes.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Robot Web Services (HTTPS, port 443)\u003C\u002Fstrong> — OmniCore's built-in REST API, used for telemetry (pose, joints, state), motor on\u002Foff, RAPID start\u002Fstop, I\u002FO read\u002Fwrite, file transfer, and WebSocket subscriptions.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>RWS-only nodes (status, pose, joints, I\u002FO, …) work without the RAPID module; motion nodes need it loaded and running.\u003C\u002Fp>\n\u003Ch2 id=\"requirements\">\u003Ca class=\"header-anchor\" href=\"#requirements\">Requirements\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>ABB GoFa CRB 15000 with an OmniCore controller, RobotWare 7.x\u003C\u002Fli>\n\u003Cli>Node-RED ≥ 3.0, Node.js ≥ 18\u003C\u002Fli>\n\u003Cli>Network access to the controller (HTTPS 443 + TCP 1025)\u003C\u002Fli>\n\u003Cli>RobotStudio (free) — once, to create an RWS user with the right grants\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"install\">\u003Ca class=\"header-anchor\" href=\"#install\">Install\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>From your Node-RED user directory (usually \u003Ccode>~\u002F.node-red\u003C\u002Fcode>):\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">npm install node-red-contrib-abb-gofa\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>(or \u003Cstrong>Menu → Manage palette → Install\u003C\u002Fstrong> inside the Node-RED editor.)\u003C\u002Fp>\n\u003Cp>Restart Node-RED — a \u003Ccode>gofa-robot\u003C\u002Fcode> config node and 43 \u003Ccode>gofa-*\u003C\u002Fcode> nodes appear under the \u003Cstrong>GoFa\u003C\u002Fstrong> category.\u003C\u002Fp>\n\u003Ch2 id=\"controller-setup-once\">\u003Ca class=\"header-anchor\" href=\"#controller-setup-once\">Controller setup (once)\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>1. Create an RWS user.\u003C\u002Fstrong> The built-in \u003Ccode>Admin\u003C\u002Fcode> account cannot start\u002Fstop RAPID remotely. In RobotStudio: connect to the controller → \u003Cstrong>Authenticate\u003C\u002Fstrong> → \u003Cstrong>Edit User Accounts\u003C\u002Fstrong> → add a role with the \u003Cstrong>Remote Start\u003C\u002Fstrong> and \u003Cstrong>Remote Stop\u003C\u002Fstrong> grants → create a user with that role. Read-only nodes work with any account.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>2. Upload the RAPID module.\u003C\u002Fstrong> The module ships in this package. Easiest path: add a \u003Ccode>gofa-file\u003C\u002Fcode> node (action \u003Cstrong>upload\u003C\u002Fstrong>) and set its \u003Cstrong>Local Path\u003C\u002Fstrong> to the \u003Cem>absolute\u003C\u002Fem> path of the bundled file (e.g. \u003Ccode>\u002Fhome\u002Fpi\u002F.node-red\u002Fnode_modules\u002Fnode-red-contrib-abb-gofa\u002Frapid\u002FMainModule.mod\u003C\u002Fcode> — a relative path resolves against the Node-RED process directory, not your user dir). It uploads over RWS and automatically patches the module's \u003Ccode>SERVER_IP\u003C\u002Fcode> constant to your robot's IP (the RAPID socket server cannot bind a wildcard address, so this must match). Or upload manually:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">curl -sk -u &lt;user&gt;:&lt;password&gt; -X PUT -H \"Content-Type: text\u002Fplain;v=2.0\" \\\n  --data-binary @rapid\u002FMainModule.mod \\\n  \"https:\u002F\u002F&lt;ROBOT_IP&gt;\u002Ffileservice\u002F\\$HOME\u002FPrograms\u002FMainModule.mod\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>(If you upload manually, edit \u003Ccode>SERVER_IP\u003C\u002Fcode> in the file to your robot's IP first.)\u003C\u002Fp>\n\u003Cp>\u003Cstrong>3. Load and start it on the FlexPendant.\u003C\u002Fstrong> \u003Cstrong>Code\u003C\u002Fstrong> → \u003Cstrong>⋮\u003C\u002Fstrong> → \u003Cstrong>Load Module\u003C\u002Fstrong> → \u003Ccode>HOME\u002FPrograms\u002FMainModule.mod\u003C\u002Fcode>, then \u003Cstrong>Debug\u003C\u002Fstrong> → \u003Cstrong>PP to Main\u003C\u002Fstrong>, switch to \u003Cstrong>Auto\u003C\u002Fstrong> mode, \u003Cstrong>Motors on\u003C\u002Fstrong>, \u003Cstrong>Play\u003C\u002Fstrong> (▶). The controller now answers on port 1025 (test: send \u003Ccode>PING\\n\u003C\u002Fcode>, expect \u003Ccode>OK:PING\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Ch2 id=\"usage\">\u003Ca class=\"header-anchor\" href=\"#usage\">Usage\u003C\u002Fa>\u003C\u002Fh2>\n\u003Col>\n\u003Cli>Open any \u003Ccode>gofa-*\u003C\u002Fcode> node → add a \u003Cstrong>gofa-robot\u003C\u002Fstrong> config node: robot IP, ports (443 \u002F 1025), the username\u002Fpassword from step 1.\u003C\u002Fli>\n\u003Cli>Wire an \u003Ccode>inject\u003C\u002Fcode> into e.g. \u003Ccode>gofa-status\u003C\u002Fcode> or \u003Ccode>gofa-ping\u003C\u002Fcode> to verify connectivity, then go from there.\u003C\u002Fli>\n\u003Cli>Every node has full usage docs in the Node-RED sidebar help.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Ready-made example flows (a per-node demo, a full control dashboard, and a physical-button teach workflow) are in the \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FNantaphat-Yoktaworn\u002Fnode-red-contrib-abb-gofa\u002Ftree\u002Fmain\u002Fflows\">GitHub repo's \u003Ccode>flows\u002F\u003C\u002Fcode> directory\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"nodes\">\u003Ca class=\"header-anchor\" href=\"#nodes\">Nodes\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Every node below (except the \u003Ccode>gofa-robot\u003C\u002Fcode> config node) has an \u003Cstrong>Output payload (debug)\u003C\u002Fstrong>\ncheckbox, unchecked by default. Unchecked, a node still fires on completion to trigger the\nnext node in the flow, but with an empty payload instead of full debug data — no \u003Ccode>change\u003C\u002Fcode> node\nneeded just to silence output. Check it to get the full \u003Ccode>msg.payload\u003C\u002Fcode> described per node below.\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Node\u003C\u002Fth>\n\u003Cth>Transport\u003C\u002Fth>\n\u003Cth>Description\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-robot\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>config\u003C\u002Ftd>\n\u003Ctd>Shared connection settings (IP, ports, credentials, points storage)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-status\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>Controller state, operating mode, speed ratio, RAPID execution state\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-connection-status\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS + Socket + Background\u003C\u002Ftd>\n\u003Ctd>Checks RWS, the TCP socket server, and the \u003Ca href=\"#background-task-optional\">Background task\u003C\u002Fa> independently — reachable? reply time? — without assuming any one already works; also reports each layer's module version and whether an EGM session is active\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-pose\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>Current TCP pose (position + quaternion + config flags)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-joints\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>All 6 joint angles\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-system-info\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>RobotWare version, controller identity\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-elog\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>Controller event log — Domain (category) + Min Severity (info\u002Fwarning+\u002Ferror-only) filters\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-motor\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>Motors on\u002Foff\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-move\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Go home \u002F set home\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-movej\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Absolute joint move (\"Move Joints\") — Move type: Joint (default) \u002F Linear. Validates each target angle against the robot's Joint Limits (CRB 15000-12 defaults) before sending — an out-of-range target returns a clean error instead of faulting RAPID\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-jog\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Cartesian jog (±mm \u002F ±°)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-joint-jog\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Single-joint jog\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-zone-set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Path blend zone (FINE…Z100)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-speed-set\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Speed override via \u003Ccode>VelSet\u003C\u002Fcode> — set or read current (\u003Ccode>C_MOTSET.vel.oride\u003C\u002Fcode>); see CLAUDE.md for why \u003Ccode>SpeedRefresh\u003C\u002Fcode> doesn't work here\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-stop-motion\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS + Socket\u003C\u002Ftd>\n\u003Ctd>Motion halt. \u003Cstrong>Mode\u003C\u002Fstrong>: \u003Ccode>immediate\u003C\u002Fcode> (default) halts an in-progress HOME\u002FGOTOJ\u002FGOTOL\u002FMOVEJ\u002FMOVEL now via an RWS execution-stop + auto resetPP\u002Fstart (arm stays put, socket recovers; needs Auto + motors on); \u003Ccode>queued\u003C\u002Fcode> is the legacy socket STOP that only cancels a not-yet-started move\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-ping\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Connectivity test with round-trip time\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-grip\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>Digital output on\u002Foff (gripper-style)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-save-point\u003C\u002Fcode> \u002F \u003Ccode>gofa-go-point\u003C\u002Fcode> \u002F \u003Ccode>gofa-point-list\u003C\u002Fcode> \u002F \u003Ccode>gofa-delete-point\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>mixed\u003C\u002Ftd>\n\u003Ctd>Teach &amp; replay named points, stored locally or on the robot's own disk\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-points\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>disk\u003C\u002Ftd>\n\u003Ctd>Bulk export\u002Fimport of the point list (action: export \u002F import — import \u003Cstrong>replaces\u003C\u002Fstrong> the whole list)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-sequencer\u003C\u002Fcode> \u002F \u003Ccode>gofa-stop-seq\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Visit saved points in order (dwell, loops, ping-pong) \u002F stop the sequence\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-setup\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS + Socket\u003C\u002Ftd>\n\u003Ctd>One-click first-run init for \u003Ccode>T_ROB1\u003C\u002Fcode> only: upload the bundled RAPID module (SERVER_IP auto-synced), load, reset PP, motors on, start, verify socket — with a per-step report. Does not set up the \u003Ca href=\"#background-task-optional\">Background task\u003C\u002Fa>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-rapid-exec\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>Start \u002F stop \u002F reset-PP \u002F load \u002F unload \u002F activate RAPID program\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-rapid-var-read\u003C\u002Fcode> \u002F \u003Ccode>gofa-rapid-var-write\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket\u003C\u002Ftd>\n\u003Ctd>Read\u002Fwrite RAPID PERS variables\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-rapid-tasks\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>List RAPID tasks and modules\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-file\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>Upload \u002F download \u002F delete controller files (action dropdown; upload auto-syncs \u003Ccode>SERVER_IP\u003C\u002Fcode>)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-mod-edit\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>Edit a \u003Ccode>.mod\u003C\u002Fcode> (or any text) file on the controller's disk right in the node's edit dialog — pick a file in \u003Ccode>$HOME\u002FPrograms\u003C\u002Fcode> (or name a new one), Load\u002FSave to robot, \u003Ccode>SERVER_IP\u003C\u002Fcode> auto-synced\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-io-list\u003C\u002Fcode> \u002F \u003Ccode>gofa-di-read\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS\u003C\u002Ftd>\n\u003Ctd>List signals, read inputs\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-do-write\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS, Socket, or Background\u003C\u002Ftd>\n\u003Ctd>Write outputs — Transport dropdown: RWS \u003Ccode>\u002Fset-value\u003C\u002Fcode> (default, needs \u003Ccode>Access: All\u003C\u002Fcode>), Socket \u003Ccode>SETDO\u003C\u002Fcode> (needs RAPID running), or \u003Ca href=\"#background-task-optional\">Background task\u003C\u002Fa> (works while \u003Ccode>T_ROB1\u003C\u002Fcode> is stopped)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-leadthrough\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket + RWS\u003C\u002Ftd>\n\u003Ctd>Hand-guiding (lead-through) on\u002Foff (action: enable \u002F disable)\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-asi-led\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Socket, RWS, or Background\u003C\u002Ftd>\n\u003Ctd>Arm status-light color and blink — Transport dropdown, same three options as \u003Ccode>gofa-do-write\u003C\u002Fcode> above\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-subscribe-state\u003C\u002Fcode> \u002F \u003Ccode>gofa-subscribe-io\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS WebSocket\u003C\u002Ftd>\n\u003Ctd>Push on controller-state \u002F I\u002FO-signal changes\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-subscribe-var\u003C\u002Fcode> \u002F \u003Ccode>gofa-subscribe-pose\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS poll\u003C\u002Ftd>\n\u003Ctd>Poll a RAPID variable \u002F TCP pose on an interval\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-subscribe-elog\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>RWS WebSocket\u003C\u002Ftd>\n\u003Ctd>Push new event log entries in real time; same Domain\u002FMin Severity filters as \u003Ccode>gofa-elog\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>gofa-egm\u003C\u002Fcode> \u002F \u003Ccode>gofa-egm-move\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>UDP (EGM)\u003C\u002Ftd>\n\u003Ctd>Sub-10ms joint-position streaming — see \u003Ca href=\"#egm-optional\">EGM (optional)\u003C\u002Fa> below, requires \u003Ccode>MainModuleEGM.mod\u003C\u002Fcode>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>The full RAPID socket protocol reference, RWS endpoint notes, and troubleshooting guide are in the \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FNantaphat-Yoktaworn\u002Fnode-red-contrib-abb-gofa#readme\">GitHub README\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"egm-optional\">\u003Ca class=\"header-anchor\" href=\"#egm-optional\">EGM (optional)\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Ccode>gofa-egm\u003C\u002Fcode> + \u003Ccode>gofa-egm-move\u003C\u002Fcode> stream joint positions over \u003Cstrong>EGM (Externally Guided Motion)\u003C\u002Fstrong> — a\nUDP\u002Fprotobuf channel capable of sub-10ms closed-loop motion, unlike the TCP socket protocol or\nRWS (which tops out around 500ms). It needs its own RAPID module and a one-time controller\nconfig, so it's opt-in rather than part of the default setup above.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Two nodes, split by job.\u003C\u002Fstrong> \u003Ccode>gofa-egm\u003C\u002Fcode> only starts\u002Fstops the EGM session and emits telemetry —\nit has an Action dropdown (\u003Ccode>Start EGM\u003C\u002Fcode> \u002F \u003Ccode>Stop EGM\u003C\u002Fcode>), same pattern as \u003Ccode>gofa-motor\u003C\u002Fcode>\u002F\n\u003Ccode>gofa-rapid-exec\u003C\u002Fcode>. \u003Ccode>gofa-egm-move\u003C\u002Fcode> is a separate node that sets the movement target: send it a\n\u003Ccode>[j1..j6]\u003C\u002Fcode> array and it checks whether a \u003Ccode>gofa-egm\u003C\u002Fcode> session is active on the same Robot — if so,\nit updates the live target (output 1); if not, it routes the message unchanged to a fallback\noutput (output 2) instead of erroring, e.g. to wire straight into \u003Ccode>gofa-movej\u003C\u002Fcode> for a normal\nnon-EGM move.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Two RAPID modules, one choice at a time:\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Module\u003C\u002Fth>\n\u003Cth>Use when\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>rapid\u002FMainModule.mod\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Default. Everything in this README works. No EGM support.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>rapid\u002FMainModuleEGM.mod\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>A full clone of \u003Ccode>MainModule.mod\u003C\u002Fcode> plus one added command, \u003Ccode>EGMJOINT\u003C\u002Fcode>, that switches the controller into a blocking EGM session. Load this instead when a flow needs \u003Ccode>gofa-egm\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003Cp>Only one can run at a time — whichever is loaded on the controller. \u003Cstrong>Switching requires\nunloading the currently-loaded module first\u003C\u002Fstrong> — \u003Ccode>loadmod\u003C\u002Fcode>'s \u003Ccode>replace\u003C\u002Fcode> option only replaces a\nmodule with the \u003Cem>same name\u003C\u002Fem>, and \u003Ccode>MainModule\u003C\u002Fcode>\u002F\u003Ccode>MainModuleEGM\u003C\u002Fcode> are different names, so loading\none while the other is still loaded leaves both loaded and RAPID rejects start with \"Global\nroutine name main ambiguous\" (both declare \u003Ccode>PROC main()\u003C\u002Fcode>). Full switch sequence either\ndirection: \u003Ccode>gofa-rapid-exec\u003C\u002Fcode> (\u003Ccode>stop\u003C\u002Fcode>) → \u003Ccode>gofa-rapid-exec\u003C\u002Fcode> (\u003Ccode>unloadmod\u003C\u002Fcode>, naming the module\n\u003Cem>currently\u003C\u002Fem> loaded — this only detaches it from the task, the file stays on the controller's\ndisk) → \u003Ccode>gofa-file\u003C\u002Fcode> upload (the other file) → \u003Ccode>gofa-rapid-exec\u003C\u002Fcode> (\u003Ccode>loadmod\u003C\u002Fcode> → \u003Ccode>resetpp\u003C\u002Fcode> →\n\u003Ccode>start\u003C\u002Fcode>). \u003Ccode>gofa-egm\u003C\u002Fcode> detects the wrong module itself (\u003Ccode>start\u003C\u002Fcode> fails with a clear \"load\nMainModuleEGM.mod first\" error instead of hanging) — but there is no way to run without one or\nthe other, so mixing them up just costs a reload, not a broken robot.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Why two modules instead of one:\u003C\u002Fstrong> an EGM session (\u003Ccode>EGMRunJoint\u003C\u002Fcode>) blocks the RAPID task for\nits whole duration, so the same task can't also be running the plain TCP socket server that\nevery other node in this package depends on — while \u003Ccode>gofa-egm\u003C\u002Fcode> is streaming, \u003Ccode>gofa-jog\u003C\u002Fcode>,\n\u003Ccode>gofa-go-point\u003C\u002Fcode>, and the rest simply can't connect. Keeping EGM support in a separate module\nmeans the default \u003Ccode>MainModule.mod\u003C\u002Fcode> — and everything that depends on it — is completely\nunaffected by this feature; it's not merged into the file every other node already relies on.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>One-time controller setup\u003C\u002Fstrong>, not done by any node: a UDP Unicast Device named\n\u003Ccode>EGM_PC\u003C\u002Fcode> (RobotStudio → Controller → Configuration → Communication → UDP Unicast Device →\nright-click → New UDP Unicast Device...; Remote Address = the Node-RED host's IP on the robot's\nsubnet, Remote Port Number = the \u003Ccode>gofa-egm\u003C\u002Fcode> node's configured UDP port, default \u003Ccode>6510\u003C\u002Fcode>, Local\nPort Number = \u003Ccode>0\u003C\u002Fcode>; requires a controller restart), and — on the Node-RED host — a firewall rule\nallowing inbound UDP on that port.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Caution — tool load data:\u003C\u002Fstrong> per ABB's EGM Application Manual, the robot should have correct\ntool load data (\u003Ccode>LoadIdentify\u003C\u002Fcode>) before starting EGM — incorrect load data can cause servo\ntorque overruns or safety halts when EGM issues fast corrections. With no tool physically\nmounted, \u003Ccode>MainModuleEGM.mod\u003C\u002Fcode>\u002F\u003Ccode>MainModule.mod\u003C\u002Fcode> both target \u003Ccode>tool0\u003C\u002Fcode> (RAPID's built-in empty-flange\ntool) rather than a placeholder tooldata, so there's no false load data to worry about right now.\nOnce a real gripper is mounted, run \u003Ccode>LoadIdentify\u003C\u002Fcode> (or otherwise measure its real mass\u002FCoG\u002F\ninertia\u002FTCP offset) and update both \u003Ccode>.mod\u003C\u002Fcode> files to use it before relying on EGM (or any motion)\nwith that tooling attached.\u003C\u002Fp>\n\u003Ch2 id=\"background-task-optional\">\u003Ca class=\"header-anchor\" href=\"#background-task-optional\">Background task (optional)\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Not required for anything above — every node in this package works without it. It exists to keep\nLED feedback and digital-output writes working during a hand-guiding session (or any other time\n\u003Ccode>T_ROB1\u003C\u002Fcode> is stopped), by running a small second RAPID module (\u003Ccode>rapid\u002FBackgroundLed.mod\u003C\u002Fcode>) in its\nown task. It backs the \u003Cstrong>Background\u003C\u002Fstrong> transport option on \u003Ccode>gofa-do-write\u003C\u002Fcode>\u002F\u003Ccode>gofa-asi-led\u003C\u002Fcode>, and the\n\u003Ccode>background\u003C\u002Fcode> field on \u003Ccode>gofa-connection-status\u003C\u002Fcode>. Setting it up needs one manual, one-time\nRobotStudio step (creating a new RAPID task isn't possible over RWS at all) — see the\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FNantaphat-Yoktaworn\u002Fnode-red-contrib-abb-gofa#background-task-backgroundledmod--t_led\">GitHub README's \"Background task\" section\u003C\u002Fa>\nfor the exact steps.\u003C\u002Fp>\n\u003Cp>Full node help (input\u002Foutput shapes, config) is in the Node-RED sidebar for \u003Ccode>gofa-egm\u003C\u002Fcode> and\n\u003Ccode>gofa-egm-move\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"test\">\u003Ca class=\"header-anchor\" href=\"#test\">Test\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>From a git checkout (the test suite is not included in the npm package):\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">npm test\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Runs \u003Ccode>test.js\u003C\u002Fcode> — unit tests for the pure helpers (\u003Ccode>gotoToken\u003C\u002Fcode>, \u003Ccode>parseXhtml\u003C\u002Fcode>, points persistence, LED payload resolution, the hand-rolled EGM protobuf codec) plus integration-style tests that drive node \u003Ccode>input\u003C\u002Fcode> handlers against a minimal Node-RED harness.\u003C\u002Fp>\n\u003Ch2 id=\"license\">\u003Ca class=\"header-anchor\" href=\"#license\">License\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FNantaphat-Yoktaworn\u002Fnode-red-contrib-abb-gofa\u002Fblob\u002Fmaster\u002FLICENSE\">MIT\u003C\u002Fa>\u003C\u002Fp>\n",1784738655182]