Typed read/write abstraction for all FANUC robot controller register types, with a bidirectional Karel ↔ TP variable bridge and a GPP template for mapping Karel structs to registers.
Karel has no native way to read or write FANUC registers without calling raw built-ins (GET_REG, SET_INT_REG, GET_PORT_VAL, etc.) and manually dispatching on register type. This module wraps all of that behind a consistent registers__* API with error checking, comment (label) management, and type-safe getters and setters.
Reach for this module whenever you need to:
- Read or write R[], SR[], PR[], F[], DI/DO, AI/AO, or other I/O ports from Karel
- Label registers with string comments visible on the teach pendant
- Bridge a Karel struct field to/from a TP register (e.g. for operator input via TP)
- Define a full struct ↔ register mapping declaratively (via
regmap)
Note: For position register operations (
PR[]) use kl-pose (pose__set_posreg_xyz,pose__get_posreg_xyz, etc.). Theregisterstpbridge calls those routines internally.
| File | Purpose |
|---|---|
src/registers.kl |
Core implementation — get/set/comment for all register types |
src/registerstp.kl |
Karel ↔ TP bridge using GET_VAR / SET_VAR |
include/registers.klh |
Public header — import to use registers__* routines |
include/register_types.klt |
Type code constants (DATA_REG, io_din, etc.) — include separately |
include/registers.klt |
Module variable ok : BOOLEAN — included in program block |
include/registerstp.klh |
Public header for registerstp__* routines |
lib/regmap.klc |
GPP class template for struct ↔ register mapping |
lib/regmap.klh |
regmap class interface |
lib/regmap.klt |
map_select_getter / map_select_setter macro definitions |
test/test_regist.kl |
KUnit tests for core register API |
test/test_regmap.kl |
KUnit test for regmap roundtrip |
test/test_set_var.tpp |
TP-Plus test for registerstp bridge |
test/test_set_struct.tpp |
TP-Plus test for regmap from TP side |
test/config/testregmap.klt |
Example regmap config |
Always %include register_types.klt before using type constants. Do not hardcode integer values.
%include register_types.klt
DATA_REG -- R[n] numeric registers
DATA_POSREG -- PR[n] position registers
DATA_STRING -- SR[n] string registers
INVALIDTYPE -- sentinel value (17043)
-- I/O type codes (from FANUC kliotyps.kl):
io_din / io_dout -- DI[n] / DO[n]
io_anin / io_anout -- AI[n] / AO[n]
io_flag -- F[n]
io_rdi / io_rdo -- RI[n] / RO[n]
io_gpin / io_gpout -- GI[n] / GO[n]
io_uopin / io_uopout -- UI[n] / UO[n]
io_sopin / io_sopout -- SI[n] / SO[n]
When you have a string code (e.g., from parsing a config file) and need the integer constant:
typ = registers__get_type_enum('DI') -- returns io_din
str = registers__get_type_name(io_din) -- returns 'DI'
Supported strings: 'R', 'PR', 'SR', 'F', 'DI', 'DO', 'AI', 'AO', 'RI', 'RO', 'GI', 'GO', 'UI', 'UO'
-- Numeric register R[n]
val_i = registers__get_int(10) -- R[10] as INTEGER
val_r = registers__get_real(10) -- R[10] as REAL
is_r = registers__is_real(10) -- TRUE if R[10] currently holds REAL
is_i = registers__is_int(10) -- TRUE if R[10] currently holds INTEGER
-- String register SR[n]
s = registers__get_string(1)
-- Flag F[n]
b = registers__get_boolean(27) -- F[27] as BOOLEAN
-- Any I/O port (returns raw integer: 0/1 for digital, scaled for analog)
v = registers__get_io(io_din, 14) -- DI[14]
v = registers__get_io(io_anin, 2) -- AI[2]
registers__set_int(10, 42)
registers__set_real(133, 3.14)
registers__set_string(1, 'job_001')
registers__set_boolean(27, TRUE) -- F[27]
registers__set_io(io_dout, 3, TRUE) -- DO[3] = ON
Comments appear next to the register number on the teach pendant. Set once at startup; they persist on the controller.
%include register_types.klt
-- Write labels
registers__set_comment(DATA_REG, 10, 'part_count')
registers__set_comment(DATA_POSREG, 4, 'home_pose')
registers__set_comment(DATA_STRING, 1, 'job_name')
registers__set_comment(io_dout, 3, 'laser_enable')
-- Read back
cmt = registers__get_comment(DATA_REG, 10) -- 'part_count'
-- Clear all R[] labels (values preserved)
registers__clear_comments(DATA_REG, FALSE)
-- Clear labels AND reset R[] values to 0
registers__clear_comments(DATA_REG, TRUE)
registerstp bridges Karel program variables to FANUC registers so TP programs can read and write them. Uses GET_VAR / SET_VAR built-ins. String limit: 32 characters.
progname = Karel program name. varname = variable name, dot-notation for struct fields (e.g., 'config.step_count').
The package.json exposes these as named TP interfaces:
# Getters — read Karel variable, write to register
intvar = get_kint('<program_name>', '<variable>')
realvar = get_krel('<program_name>', '<variable>')
boolvar = get_kio('<program_name>', '<variable>', 'F')
strvar = get_kstr('<program_name>', '<variable>')
posvar = get_kpos('<program_name>', '<variable>') # group 1
posvar.group(1) = get_kposgrp('<program_name>', '<variable>')
jntvar = get_kjnt('<program_name>', '<variable>') # group 1
jntvar.group(1) = get_kjntgrp('<program_name>', '<variable>')
# Setters — read register, write to Karel variable
set_kint(intvar, '<program_name>', '<variable>')
set_krel(realvar, '<program_name>', '<variable>')
set_kbool(boolvar, '<program_name>', '<variable>')
set_kstr(strvar, '<program_name>', '<variable>')
set_kxyz(&posvar, '<program_name>', '<variable>')
set_kjnt(&jntvar, '<program_name>', '<variable>')-- Read Karel variable → register
registerstp__get_karel_int('myapp', 'config.step_count', 5)
registerstp__get_karel_real('myapp', 'speed', 6)
registerstp__get_karel_string('myapp', 'job_name', 1)
registerstp__get_karel_xyz('myapp', 'target_pose', 4, 1) -- reg 4, group 1
registerstp__get_karel_joint('myapp', 'home_joint', 5, 1)
registerstp__get_karel_io('myapp', 'ready', 'F', 2)
-- Register → Karel variable
registerstp__set_karel_int(registers__get_int(5), 'myapp', 'config.step_count')
registerstp__set_karel_real(registers__get_real(6), 'myapp', 'speed')
registerstp__set_karel_string(registers__get_string(1), 'myapp', 'job_name')
registerstp__set_karel_xyz(pose__get_posreg_xyz(4, 1), 'myapp', 'target_pose')
registerstp__set_karel_joint(pose__get_posreg_joint(5, 1), 'myapp', 'home_joint')
-- Note: set_karel_bool takes INTEGER (0/1), not BOOLEAN
registerstp__set_karel_bool(registers__get_io(io_flag, 2), 'myapp', 'ready')
regmap.klc is a GPP template that maps every field of a Karel struct to a specific register, letting you push or pull the whole struct in one call. It's the right pattern when a TP program needs bidirectional access to a multi-field Karel struct.
-- myconfig.klt
%define REGMAP_TYPE t_MY_PARAMS
-- Use REGMAP_STRUCT to define the struct inside the class,
-- or REGMAP_STRUCT_IMPORT to reference an externally defined type.
%define REGMAP_STRUCT `TYPE
t_MY_PARAMS FROM class_name = STRUCTURE
laser_power : REAL
step_count : INTEGER
job_name : STRING[16]
home_pose : XYZWPR
enabled : BOOLEAN
ENDSTRUCTURE`
-- REGMAPPGET: struct field → register (args: progname, varname, regtype, reg_id, field, type, group)
%define REGMAPPGET `
map_select_getter(progname, varname, 'R', 1, 'laser_power', 'REAL', 1)
map_select_getter(progname, varname, 'R', 2, 'step_count', 'INTEGER', 1)
map_select_getter(progname, varname, 'SR', 3, 'job_name', 'STRING', 1)
map_select_getter(progname, varname, 'PR', 4, 'home_pose', 'XYZWPR', 1)
map_select_getter(progname, varname, 'F', 5, 'enabled', 'BOOLEAN', 1)
`
-- REGMAPPSET: register → struct field (inverse)
%define REGMAPPSET `
map_select_setter(progname, varname, 'R', 1, 'laser_power', 'REAL', 1)
map_select_setter(progname, varname, 'R', 2, 'step_count', 'INTEGER', 1)
map_select_setter(progname, varname, 'SR', 3, 'job_name', 'STRING', 1)
map_select_setter(progname, varname, 'PR', 4, 'home_pose', 'XYZWPR', 1)
map_select_setter(progname, varname, 'F', 5, 'enabled', 'BOOLEAN', 1)
`
map_select_getter / map_select_setter argument order: (progname, varname, regtype, register_id, field_name, type_string, group_no)
regtype values: 'R' (numeric), 'SR' (string), 'PR' (position), 'F'/'DI'/'DO'/etc. (I/O)
%class mymap(regmap.klc, regmap.klh, myconfig.klt)
-- All struct fields → their mapped registers
mymap__set_registers('myapp', 'params')
-- All mapped registers → struct fields
mymap__get_registers('myapp', 'out_params')
See test/config/testregmap.klt and test/test_regmap.kl for a complete working example.
rossum .. -w -o -t
ninja
kpush
kunittest/test_regist.kl— KUnit tests for core register API (R[], F[], comments, type checks)test/test_regmap.kl— KUnit test for regmap struct roundtriptest/test_set_var.tpp— TP-Plus example forregisterstpgetters/setterstest/test_set_struct.tpp— TP-Plus example calling a regmap object
| Mistake | Symptom | Fix |
|---|---|---|
registers__get_real on an INTEGER register |
Wrong value or type abort | Use registers__is_real(n) first; always match getter type to setter type |
| Hardcoding type integer values instead of constants | Wrong register type accessed silently | %include register_types.klt and use named constants (DATA_REG, io_din, etc.) |
Passing a string ('DI') to get_io/set_io |
INVALIDTYPE with no visible error |
Use registers__get_type_enum('DI') to convert string → integer |
Missing grp_no in map_select_getter for PR fields |
Wrong motion group on multi-arm controller | Supply explicit group number (1-based) as 7th argument |
Calling registerstp__set_karel_bool with a BOOLEAN |
Compiler type error | Parameter is INTEGER (0 or 1) — pass registers__get_io(io_flag, n) directly |
String values > 32 chars with get_karel_string |
Silent truncation | MAX_STRING = 32 in registerstp — keep SR[] values within that limit |
registers__clear_comments(..., TRUE) mid-run |
Other programs lose R[] values | Only use reset_reg=TRUE during initialization, never during operation |
registers is a Layer 5 module. It depends on errors, pose, systemlib, TPElib, and ktransw-macros. Modules that depend on it include hash-registers, display, csv, paths/lam, and paths/pathlayer.
regmap.klc is not compiled standalone — it is expanded via %class inside the consumer module's build.
For full build instructions see the Ka-Boost readme.