4. KAREL数据类型深入
KAREL 是强类型语言,变量在声明时就必须确定类型,运行期不会自动把字符串当数字用,也不会把整数悄悄提升为实数。理解每种类型的存储语义、取值范围和适用场景,是写出可维护、可移植机器人程序的前提。本节从“类型本身是什么”出发,落到“在机器人工程里怎么选、怎么用”。
一、标量类型:INTEGER、REAL、BOOLEAN、STRING
INTEGER 是 32 位有符号整数,典型取值范围约 −2 147 483 648 ~ 2 147 483 647。它适合表示计数、索引、状态码、I/O 端口号、循环变量、位置编号等“离散量”。例如 FOR i := 1 TO 6 DO 中的 i 必须是整型。需要注意的是,KAREL 的整数除法会截断小数部分,7 / 2 得到 3 而不是 3.5,涉及比例计算时应先转成 REAL。
REAL 是浮点实数,用于表示位置坐标、速度、力矩、时间、比例系数等连续量。机器人工程中绝大多数几何与运动参数都是 REAL,例如 x := 523.6、vel := 250.0。REAL 参与运算时要注意浮点比较不能直接用等号,判断“到位”通常写成 ABS(cur - tgt) < 0.05 这样的容差形式,否则可能因舍入误差永远不成立。
BOOLEAN 只有 TRUE 和 FALSE 两个值,用于标志位、使能条件、互锁判断。它常与逻辑运算符 AND、OR、NOT 配合,例如 IF ready AND NOT fault THEN。布尔量不要用整数 0/1 代替,虽然某些场合可以隐式转换,但会降低可读性并埋下类型隐患。
STRING 是字符序列,KAREL 中字符串有最大长度限制,声明时可写成 name : STRING[20]。它适合保存程序名、工件型号、提示信息、日志文本。字符串拼接用 +,取子串用 SUB_STR,求长度用 STR_LEN。字符串不能直接参与算术运算,需要先用 STR_TO_INT 或 STR_TO_REAL 转换,转换失败时结果不可靠,工程上应先校验再使用。
二、构造类型:数组、记录、枚举
数组(ARRAY) 把同类型元素按序号组织在一起,声明形如 joint : ARRAY[1..6] OF REAL。它天然适合表示六轴关节角、多工位料仓、批量点位表。数组下标从 1 开始,越界访问不会给出友好提示,因此循环边界必须与声明范围严格一致。多维数组可写成 ARRAY[1..3, 1..4] OF INTEGER,用于矩阵式工位布局。
记录(RECORD) 把不同类型字段组合成一个整体,是描述“一个对象多个属性”的最佳工具。例如定义一个工件记录:
TYPE workpiece : RECORD
code : STRING[16]
weight : REAL
count : INTEGER
ok : BOOLEAN
END RECORD
之后用 wp.code、wp.weight 访问字段。记录让参数成组传递,避免函数参数列表过长,也让“工件”“工具”“点位”这类实体在程序中保持完整语义。
枚举(ENUMERATION) 用一组有名字的常量代替裸数字,声明形如 TYPE state : ENUMERATION OF (IDLE, MOVING, GRIPPING, FAULT)。它把“状态机”表达得直观且安全:IF st = GRIPPING THEN 比 IF st = 2 THEN 可读得多,也避免了数字含义漂移。枚举值在内部仍按整数存储,但不应拿它做算术。
三、选用原则:从“数据本质”出发
选型的第一原则是按数据本质而非书写习惯。凡是“数得清个数”的量用 INTEGER;凡是“量得出大小、带小数”的量用 REAL;凡是“只有两种可能”的条件用 BOOLEAN;凡是“给人看或从外部读入的文本”用 STRING。把坐标写成 INTEGER 会丢失精度,把计数写成 REAL 会引入比较误差,把状态写成裸数字会让程序难以维护。
第二原则是成组数据用构造类型。六个关节角如果声明成 j1, j2, j3, j4, j5, j6 六个独立变量,循环处理时只能逐个写,扩展性差;写成 ARRAY[1..6] OF REAL 后,FOR i := 1 TO 6 DO ... joint[i] ... 即可统一处理。同理,一个工件的多个属性应放进 RECORD,而不是散落成多个平行数组——平行数组一旦增删字段,所有下标都要同步修改,极易出错。
第三原则是状态用枚举,不用魔法数字。当程序里出现 IF st = 3 THEN 时,三个月后没人记得 3 代表什么。改成枚举后,IF st = GRIPPING THEN 自解释,且编译器能帮助检查拼写。枚举还便于在示教器或日志中输出可读状态名。
四、类型转换与常见陷阱
KAREL 不会自动完成有风险的转换,需要显式调用转换函数。整数转实数用 INT_TO_REAL,实数转整数用 REAL_TO_INT(截断而非四舍五入),字符串转数值用 STR_TO_INT、STR_TO_REAL。工程上最容易踩的坑有三类:一是整数除法截断导致比例计算偏小;二是浮点等值比较永远不成立;三是字符串长度超限被截断,导致程序名或型号匹配失败。规避方法分别是:除法前转 REAL、比较用容差、声明时给足长度并在赋值前用 STR_LEN 校验。
五、一个综合示例
假设要管理一个三工位抓取任务,可这样组织数据:
TYPE station_state : ENUMERATION OF (EMPTY, LOADED, BUSY, DONE)
TYPE station : RECORD
name : STRING[12]
pos : ARRAY[1..6] OF REAL
state : station_state
cycles : INTEGER
ready : BOOLEAN
END RECORD
VAR
st : ARRAY[1..3] OF station
i : INTEGER
BEGIN
FOR i := 1 TO 3 DO
IF st[i].ready AND st[i].state = LOADED THEN
-- 执行抓取,位置取自 st[i].pos
st[i].cycles := st[i].cycles + 1
st[i].state := DONE
ENDIF
ENDFOR
END
这段代码把字符串、数组、记录、枚举、整型、布尔型全部用上,且每种类型都出现在它最合适的位置:name 是文本,pos 是连续几何量,state 是有限状态,cycles 是计数,ready 是条件。类型选对了,程序结构自然清晰,后续增加工位只需把数组上界从 3 改成 4,循环体无需改动。