Neuron SPI overlay and TCP modbus with docker



  • Hi, I'm Leonardo I work at Kartrak Automation and recently we bought a Neuron L203 to test our system in a UNIPI board. We would like to share with you some details of our installation.

    Our system rely on the Balena OS, a Yocto-based system which simplify the development of applications in a dockerized environment. Since our goal is making a low-level communication with the board we decided to install only the SPI overlay and TCP modbus service instead of the whole Evok system.

    We don't use Raspbian and we work with docker, the installation on the github does not work straightforward. The steps below show some details of the instalating that might help other users.

    Inside a container, you can follow the instructions to acess the HW of a neuron board.

    1 - Installing dependencies

    Install the dependencies:

    > apt-get install build-essential
    > apt-get install -y apt-transport-https
    > apt-get install -y wget
    > apt-get install -y libmodbus-dev
    

    Download neuron spi-overlay and tcp-modbus server

    > wget https://github.com/UniPiTechnology/neuron-tcp-modbus-overlay/archive/v.1.0.3.tar.gz
    > tar xvf v.1.0.3.tar.gz
    > cd neuron-tcp-modbus-overlay-v.1.0.3/
    

    2- Making the SPI overlay

    We generate the neuron-spi.dtbo compiling neuron-spi.dts following the github instructions

    > cd spi_overlay
    > sh compile-dtc
    

    The important thing to remember here is to copy the neuron-spi.dtbo inside the boot partition mtn/boot/overlays of the sd card. Different from the Raspbian, this folder is not accessible from inside a container so mount the RPI sd card in a computer and copy from there.

    For other OS the overlays folder can be handled differently. One may wrongly think that coping the .dtbo folder inside a /boot/overlays folder inside the container will make this work, but it won't. You have to use the boot partition since the OS will look for the overlays there.

    When restarting the board is important to make sure the overlay is working with ls /dev and see the devices:

    spidev0.0
    spidev0.1
    spidev0.2
    spidev0.3
    

    If only spidev0.0 and spidev0.1 is appearing, the spi overlay didn't work correctly.

    3- Using TCP modbus

    The TCP modbus uses systemctl commands to manage services. The problem here is that is not possible to run systemd daemon inside a docker container. To make this work we can use the docker-systemctl-replacement which allow us to exec systemctl commands. Therefore we have to replace the systemctl with:

    > wget https://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/docker/systemctl3.py -O /usr/local/bin/systemctl
    

    Now, just follow the github instructions making the neuron tcp server:

    > cd neuron-tcp-modbus-overlay-v.1.0.3/
    > cd neuron_tcp_server
    > make
    > make install
    > cp neurontcp.service /lib/systemd/system/
    

    Enable the neurontcp server with:

    > python /usr/local/bin/systemctl daemon-reload
    > python /usr/local/bin/systemctl enable neurontcp
    

    Start the server with:

    > python systemctl start neurontcp
    

    If everythig is working you should see your service active with:

    > python systemctl status neurontcp
    

    Testing with a python script

    Below is a very simple python code that changes sequantially the status of all relays and digital outputs on the L203 board. Inspired by this topic:

    #from pyModbusTCP.client import ModbusClient
    from pymodbus.client.sync import ModbusTcpClient as ModbusClient
    import time
    
    try:
        c = ModbusClient('localhost', port=502, unit_id=0, debug=False)
        c.connect()
    except ValueError:
        print("Error with host or port params")
    
    
    running=True
    
    
    while running:    
        print (c.read_coils(0,12))
        for ad in range(0,4):
            rq = c.write_coil(ad, True, unit=0)
            rr = c.read_coils(ad, 1, unit=0)
            print(str(ad), " - ", str(rr), " - ON")  
            time.sleep(0.2)
        for ad in range(100,114):
            rq = c.write_coil(ad, True, unit=0)
            rr = c.read_coils(ad, 1, unit=0)
            print(str(ad), " - ", str(rr), " - ON")      
            time.sleep(0.2)
        for ad in range(200,214):
            rq = c.write_coil(ad, True, unit=0)
            rr = c.read_coils(ad, 1, unit=0)
            print(str(ad), " - ", str(rr), " - ON")    
            time.sleep(0.2)
        time.sleep(2)
        for ad in range(0,4):
            rq = c.write_coil(ad, False, unit=0)
            rr = c.read_coils(ad, 1, unit=0)
            print(str(ad), " - ", str(rr), " - OFF") 
            time.sleep(0.2)
        for ad in range(100,114):
            rq = c.write_coil(ad, False, unit=0)
            rr = c.read_coils(ad, 1, unit=0)
            print(str(ad), " - ", str(rr), " - OFF")  
            time.sleep(0.2)
        for ad in range(200,214):
            rq = c.write_coil(ad, False, unit=0)
            rr = c.read_coils(ad, 1, unit=0)
            print(str(ad), " - ", str(rr), " - OFF")
            time.sleep(0.2)
        time.sleep(2)
        
        print (c.read_coils(1000,4))
        print (c.read_coils(1016,12))
        print (c.read_holding_registers(0,20))
        print (c.read_holding_registers(1000,32))
    
        print (c.read_holding_registers(100,1))
        time.sleep(1)
    

    That's it!

    We hope to help others that are starting with the Neuron board in a dockerized env. We are really happy with results untill now and with the UNIPI hardware. If anyone have sugestions on how to improve the setup we are really happy to talk and share.

    Thanks!

    (I'm not sure if this post should be on Installations, Ideas & Realisations or Tutorials but you can move there anyway)


Log in to reply