tallakt
Hi
I was working on an old idea of a “Soft PLC” written on top of Elixir. It was too much work but with the advent of better AI I thought maybe it could be possible to explore the idea cheaply.
My library is called Xignal and is not yet public. I am looking for other people into industry/automation who may be interested in discussing this before I make the project public. To give a taster, the code could look like this:
# A sump pump station: a level transmitter and three contacts on a Modbus TCP I/O module, a pump tha
t
# starts at a high level and stops at a low one, three alarms, and an OPC UA server for the HMI with
the
# alarms as conditions.
#
# elixir pump_station.exs
#
# then browse opc.tcp://localhost:4840 with an OPC UA client such as UaExpert.
Mix.install([{:xignal, github: "tallakt/xignal"}, {:yaopcua, "~> 0.2"}])
defmodule Station do
use Xignal
xignal pump(raw, high_switch, overload, running, auto, start_at, stop_at, ack, alarms) do
level = raw / 100
run = auto and not overload and sr(level > start_at, level < stop_at)
{_q, starts} = ctu(run, false, 1_000_000)
high = Xignal.Alarm.check(alarms.high, ton(high_switch or level > 95.0, ~t(5s)), ack)
trip = Xignal.Alarm.check(alarms.overload, overload, ack)
stuck = Xignal.Alarm.check(alarms.no_start, ton(run and not running, ~t(5s)), ack)
[level: level, run: run, starts: starts, alarm: high[:on] or trip[:on] or stuck[:on]]
end
end
io = Xignal.Modbus.new("127.0.0.1", port: 1502, scan: Xignal.t("100ms"))
level = Xignal.Modbus.input(io, input_register: 0, desc: "Level, 0.01 %")
high_switch = Xignal.Modbus.input(io, discrete_input: 0, desc: "High level switch")
overload = Xignal.Modbus.input(io, discrete_input: 1, desc: "Pump overload")
running = Xignal.Modbus.input(io, discrete_input: 2, desc: "Pump running")
alarms = Xignal.Alarm.new(:station)
points = %{
high: Xignal.Alarm.define(alarms, :level_high, desc: "Sump level high", severity: :high),
overload: Xignal.Alarm.define(alarms, :pump_overload, desc: "Pump overload", severity: :critical),
no_start: Xignal.Alarm.define(alar"Pump did not start")
}
hmi = Xignal.OPCUA.Server.new(port: 4840, alarms: :station)
percent = [range: {0.0, 100.0}, unit
auto = Xignal.OPCUA.Server.input(hmi, "Station/Auto", default: true)
start_at = Xignal.OPCUA.Server.input, [default: 80.0] ++ percent)
stop_at = Xignal.OPCUA.Server.input(hmi, "Station/StopLevel", [default: 20.0] ++ percent)
ack = Xignal.OPCUA.Server.input(hmi,fault: false)
Station.pump(level, high_switch, ovet_at, stop_at, ack, points)
|> Xignal.Modbus.sink(:run, Xignal.Modbus.output(io, coil: 0, desc: "Pump run"))
|> Xignal.OPCUA.Server.sink(:level, (hmi, "Station/Level", [default: 0.0]
++ percent))
|> Xignal.OPCUA.Server.sink(:run, Ximi, "Station/PumpRunning", default: fa
lse))
|> Xignal.OPCUA.Server.sink(:starts,t(hmi, "Station/PumpStarts", default:
0))
|> Xignal.OPCUA.Server.sink(:alarm, (hmi, "Station/Alarm", default: false)
)
Xignal.Modbus.print_io_list(io)
Xignal.Runner.run_forever([io, alarm)
The plan is to make Xignal open source once I get the necessary “go” from my employer.
Xignal has
- many IO servers supported, as client and server (modbus, bacnet, OPC-UA,)
- handles state changes for you allowing safe edits and hot reload
- had many primitives you would expect to see in PLS software (eg. ton(..) for signal time on)
- Is pure Elixir so you could meld it with anything else, like a web service
The yaopcua library came out as something I wanted to support Xignal, but in a separate library. I didn’t want to use the existing OPC client that was depending on C in the background, but rather have this project pure Elixir/Erlang. For a PLC type of application, you really want to avoid crashes. Anyway, the `yaopcua` library is already on hex.pm and should work well as far as I can tell. It has not been thoroughly tested outside the tests in the git repo.
If anyone would like to try it out who has access to OPC-UA hardware that would be interesting feedback. Obviously getting this from project idea + AI into something tested in a few real situations is a bigger task, that I am now starting to explore.
This is meant as a “pre annouce” post.
Trending in RFCs
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #ai
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
cmo
It will look very foreign to someone who is used to ladder logic or function block.
A module with a bunch of function calls for defining tags or defining them at any point in a program is going to be a lot messier and harder to maintain than a table with sorting and filtering.
Did it have a front end, i.e What is the live debugging story? Can you display trends? Can you see tag values?
Does it have a testing framework?
Can you have separate routines, programs, etc? Can you have periodic ones?
You can’t really do live editing and testing right? It’s just upload a new program? How does it handle that? Do you swap everything out at the end of a scan?
Also, what does
srmean? Not seen that one before.tallakt
Many questions there.
It will look foreign. Though for AI it will be more at home. The structure is usually similar, so I guess some users could adapt. Its not for everyone. I tried to make it simple, but its still Elixir.
The think I like is that its text programming, not tied into some graphical system generating XML files. Sometimes you can get eg ST code in PLC software, but its not a complete program that you could put into git and run CI easily. So that part is a lot easier with Xignal
Hmmm. I dont think many problems could be expressed as a table. So I dont really know what you mean here. But Xignal features a nice state machine. For me its a lot easier than eg. dealing with Siemens software.
It can show “online view”, a web page containing the code, then the live values next to each statement. I think this should be almost on par with many PLC software I have used. Though very few bells and whistles at this point. You can see IO and state machine states etc.
Yes. It uses Elixir testing and then there is a test runner that does not use wall time. I think this is a huge improvement to PLS software I have seen, and also for AI it can iterate better with testing.
You could have any structure you want. Each “PLC” can be a genserver. Run many in one process or just separate them on OS level. the “store” allows easy transfer of values between them over erlang messaging.
Hot code reload works well and was foundational to the design. So you can reload the code and timers, integrals, etc run uninterrupted. There is also retentive values for storing between restarts.
If the new code doesn’t match the old code or doesnt run in a sandbox, the hot code reload is blocked.
Its a different way then traditional PLC, but the functionality should let you work pretty easily with running systems.
SR is the set reset flip flop. Basically a boolean state holder. Xignal takes care of finding a memory location for the SR so that if you add a second SR, it wont get mixed up.
I’m super excited about this I think its a novel thing both for Elixir and for the PLC world…
Contact me for more access… I dont want to go public just yet.
tallakt
Eg today I was working on realtime functionality using the
nanosleeppackage on hex.pm. Real time performance of Erlang on RT Linux is quite decent, on my Beaglebone Blue I get the following results. Short story 500 Hz scan time feasible on beaglebone for a small system, with little jitter:n0gg1n
Hey @tallakt,
first thank you for sharing your ideas with the community. I am currently working with Siemens TIA Portal and the software is really frustrating. So I’m glad to see people in this community who are also struggling with it and looking for better solutions
We are not using OPC-UA at work, so I can’t help in that regard.
But I wrote a Nerves System for the EC100 and would like to use it to control my heat pump based on energy production of the solar system at my home. It’s a really simple project, but maybe a good start to test out the Xignal library.
Also I’m waiting for the EM300 (which is a PLC based on linux and very similar to the EC100) to arrive and maybe Xignal can be extended to directly write/read from the IO cards.
This looks very promising
tallakt
I would be happy to write that with you if you want to try…
I realize nerves may be a good option as well, even considering it is much more mature. But Xignal is pretty darn cool too.
It would also be a chance to compare Nerves vs Xignal…
The only thing that would worry me a bit, if the heater is mostly protocol work its not a good match maybe
n0gg1n
Hmm I thought Xignal is a library which just runs on the beam? Then nerves would be just the “operating system” which delivers the basis and Xignal would be the application code.
tallakt
There is no Nerves in Xignal. The OS is Linux, with the Erlang virtual machine running the bytecode (BEAM).
The only common package I think is circuits for serial port communication. To compare the code bases, in Xignal (repeated):
An ported to Nerves by an ai chatbot:
I guess you could use Nerves to install a Xignal project on eg raspberry pi… I didnt look into that
n0gg1n
I think we are talking past each other. Nerves is just an OS based on Linux which directly boots into the BEAM. So you can add Xignal to your dependencies, write your Station module in lib and flash it to a RPi or similar. Would love to try that out if you could give me access to the library
tallakt
I think perhaps you are right. Nerves + Xignal can be a good match.
I was thinking about how Nerves can interface IO on the board pins. This is maybe something I would like to integrate into Xignal at one point, so far it didnt get priority. I probably should also review this in more detail to get an overview.
Also sorry for the AI generated code I posted without reading it through. It seems my AI had done a very thorough interpretation of the Xignal code which is probably not what someone who did not use Xignal would have done. They would have made a more barebones implementation without all the bells and whistles of Xignal (eg. the alarm xignal is comprehensive). So I asked it to make a new code saying: “what would the above Xignal code look like for someone not using Xignal”, then a few rounds of simplifications, leaving out OPC-UA and then getting this (which can probably still be improved upon, but is ok as an illustration):
n0gg1n
Ok I see. So Xignal is basically reimplementing the tick based approach from traditional plc IEC 61131-3. Any reason to rely on that? I understand that protocols like Modbus need to poll, but from there wouldn’t it make more sense to use Elixirs event driven approach? There is also a newer norm (IEC 61499) which is closer to the BEAM event model, have you looked into that?