Serial Communication Examples

Serial Examples

Ice Maker Communication Protocol Example

-- CRC checksum function, parameter is data string
function Crc16(buf)
    local init = 0xFFFF
    local poly = 0xA001
    local ret = init
    local byte=0
    for j=1,#buf,1 do
        byte = string.byte(buf,j)
        ret=((ret ~ byte) & 0xFFFF)
        for i=1,8,1 do
            if((ret & 0x0001)>0) then
                ret = (ret >> 1)
                ret = ((ret ~ poly) & 0xFFFF)
            else
                ret= (ret >> 1)
            end
        end
    end
    local hi = ((ret >> 8) & 0xFF)
    local lo = (ret & 0xFF)
    ret = ((lo << 8) | hi)
    return ret
end
local com1 = serial.open("/dev/ttyS0")  ---Serial selection: 232 port
com1:set_timeout(300)   --Read timeout
com1:set_baud_rate(9600)   --Set baud rate
com1:set_parity("None")   --None: no parity
--Send command to serial function
function Send_Cmd_to_com(cmd)
    -- print('cmd :',cmd)
    com1:write(cmd) -- Send corresponding command
    -- Loop read until data is received and checksum verified, or try 10 times and return false if no data
    for i = 1,3 do
        wait(100)
        -- Read serial, use pcall to catch errors
        success, result = pcall(function() return com1:read() end)
        -- print(success)
        if success==true and  result~=nil then
            -- print('receive:',result) -- Print HEX
            crc_response = Crc16(string.char(table.unpack(result,1,#result-2)))
-- print('crc_response:',crc_response) 
            -- print( crc_response>>8 ,crc_response&0xFF) 
            if  result[#result-1]==crc_response>>8 and result[#result]==crc_response&0xFF then
                return result
            end
        end
    end
    return false
end
--Dispense ice function, parameter is dispense time in 0.1 seconds, e.g. input 40 means dispense ice for 4 seconds. Returns true if successful, false if failed, other values indicate command or communication issues
function Make_ice(out_ice_time)
if out_ice_time==nil then
        out_ice_time=10
    end
    makeice_cmd = {0xA5,0x5A,0x01,0x02} 
    out_time=  math.ceil(out_ice_time) --Round time
    table.insert(makeice_cmd, out_time&0xff00)
    table.insert(makeice_cmd, out_time&0xff)
    crc_result = Crc16(string.char(table.unpack(makeice_cmd))) --Get checksum
table.insert(makeice_cmd, crc_result>>8)
    table.insert(makeice_cmd, crc_result&0xFF)
    --Send ice dispense command
    make_ice_result= Send_Cmd_to_com(makeice_cmd)
    if make_ice_result ~=false then
        --Normal command ice dispense result
        if #make_ice_result==8 then
            status_code=table.unpack(make_ice_result,5,5)
            if status_code==0 then  --Ice dispense successful
                return true 
            else                  --Ice dispense failed
                return false
            end
        --Error command result
        elseif #make_ice_result==7 then
            abnormal_code= table.unpack(make_ice_result,5,5)
            if abnormal_code==0 then  --Ice dispense failed due to position error
                return 'Undefined error'
            elseif abnormal_code==2 then  --Ice dispense failed due to command issue
                return 'Unrecognized command'
            elseif abnormal_code==3  then  --Ice dispense failed due to CRC error
                return 'CRC checksum error'
            elseif abnormal_code==4  then  --Ice dispense failed due to system busy
                return 'System busy'
            end
        end
    else
        --Communication fault
        print('Communication error with ice maker when sending ice dispense command')
        return 'Communication error'  --Returns false when no return value from command
    end
end
--Read ice maker status
function Read_machine_status()
read_status_cmd = {0xA5,0x5A,0x01,0x01,0x00,0x00,0x10,0xDF}
--Send read status command
    read_status_result= Send_Cmd_to_com(read_status_cmd)
    --Normal command status return
    if read_status_result ~=false then
        if #read_status_result==8 then
machine_status_code= table.unpack(read_status_result,5,5)
            error_code = table.unpack(read_status_result,6,6)
            print('Ice maker status code:', machine_status_code , ' Error code:',error_code )
            if machine_status_code==2 then
                return 'Idle standby'
            elseif machine_status_code==3 then
                return 'Dispensing ice or water'
            elseif machine_status_code==4 then
                return 'Draining ice'
            elseif machine_status_code==5 then
                if error_code==1  then
                    return 'Insufficient water supply'
                elseif error_code==2 then
                    return 'Internal temperature too low'
                elseif error_code==3  then
                    return 'Internal temperature too high'
                elseif error_code==4  then
                    return 'Compressor temperature too high'
                elseif error_code==5  then
                    return 'Exhaust port temperature too low'
                elseif error_code==6 then
                    return 'Motor overcurrent'
                elseif error_code==7  then
                    return 'Communication error'
                elseif error_code==8  then
                    return 'Data storage error'
                elseif error_code==9  then
                    return 'Motor stall'
                elseif error_code==10  then
                    return 'Motor warning'
                end
elseif machine_status_code==6 then
                return  'Cleaning'
            elseif machine_status_code==1 or machine_status_code==0 then
                return 'Power-on initialization'
            elseif machine_status_code==7 then
                return 'Waiting to take ice' 
            end
        --Abnormal command status return
        elseif #read_status_result==7 then
            abnormal_code= table.unpack(read_status_result,5,5)
            if abnormal_code==0 then 
                return 'Undefined error'
            elseif abnormal_code==2 then
                return 'Unrecognized command'
            elseif abnormal_code==3  then
                return 'CRC checksum error'
            elseif abnormal_code==4  then
                return 'System busy'
            end
        end
    --Communication fault, no return value
    else
        print('Communication error with ice maker when reading status' )
        return 'Communication error'
    end
    return false
end
--Check ice bucket status
function Read_icebucket_status()
read_icebucket_cmd = {0xA5,0x5A,0x01,0x03,0x00,0x00,0xB1,0x1F}
--Send read status command
    read_icebucket_result= Send_Cmd_to_com(read_icebucket_cmd)
    --Normal command status return
    if read_icebucket_result~=false then
        if #read_icebucket_result==8 then
icebucket_status_code= table.unpack(read_icebucket_result,5,5)
            if icebucket_status_code==1 then
                return 'Ice bucket full'
            else
                return 'Ice bucket not full'
            end
        --Abnormal command status return
        elseif #read_icebucket_result==7 then
            icebucket_abnormal_code= table.unpack(read_icebucket_result,5,5)
            if icebucket_abnormal_code==0 then 
                return 'Undefined error'
            elseif icebucket_abnormal_code==2 then
                return 'Unrecognized command'
            elseif icebucket_abnormal_code==3  then
                return 'CRC checksum error'
            elseif icebucket_abnormal_code==4  then
                return 'System busy'
            end
        end
    --Communication fault, no return value
    else
        print('Communication error with ice maker when reading ice bucket status' )
        return 'Communication error'
    end
    return false
end
print(Make_ice(10))
print(Read_machine_status())
print(Read_icebucket_status())

ModBus Examples

Control Box Modbus Example

-- Use Modbus/RTU
local com1 = serial.open("/dev/ttyS1")
com1:set_timeout(200)
com1:set_baud_rate(9600)
local mb = modbus.new_rtu(com1)
-- Configure Modbus
mb:set_timeout(500)
mb:set_slave(0x01)
-- Set 1 DO, use pcall to catch errors
success, result = pcall(function() mb:write_single_coil(0x0000, true) end)
if not success then
  print("Error: "..tostring(result))
else
    print("Write successful")
end
-- Set 5 DO
success, result = pcall(function()
  mb:write_multiple_coils(0x0000, {true,true,true,true,true})
end)
if not success then
  print("Error: ", result)
else
    print("Write successful")
end
 -- Read 5 DO
success, result = pcall(function() return mb:read_coils(0x0000, 5) end)
if not success then
    print("Error: ", result)
else
    print(result)
end

Flange Modbus Example

-- Use flange Modbus for controlling end-of-arm tooling like grippers
local mb = modbus.new_flange() -- Flange serial address is fixed, no need to configure serial instance like control box modbus
-- Configure Modbus
mb:set_timeout(500)
mb:set_slave(0x01)
mb:write_single_register(0x0600, 0x0032)
mb:read_input_registers(0x0601, 0x0064)
force = mb:read_input_registers(0x0600, 1)
print(force)
amplitude = mb:read_input_registers(0x0601, 1)
print(amplitude)