Loads of progress! 13/1/2009
Well, where to start...
Since my last update I've updated my RS485 interface to use a 555 timing circuit to control the transmit enable, as per my comments before Christmas (here). There seems to be no reliable way of telling how many bytes are in the UART fifo in windows, or Linux, accept for hard timing loops, which seems pretty crappy on a non real-time OS. The hardware solution is tidy, and effective.
I also added a couple of LED's and a dip switch to my test 16F628 RTU, and did some major tidy-up work on the pic code. I broke it down into a number of include files to make it more portable between devices, and to separate the modbus protocol code from the I/O updates.
I'm now not too sure if I'll release the RTU code, as it's in assembly it's a bit more, well, personal, than C or php somehow. If you're an assembly fan like me you'll know what I mean.
Sometime in the next couple of weeks I'll make my final decision about what my target device will be, I'm leaning towards the 16F688 because it's tiny, and the idea is appealing. My entire modbus RTU protocol stack fits in well under 1k(word) of program memory on the pic, so as long as the device has enough ram I'm in business, and the smaller the chip, the cheaper the whole thing can be at the end of the day.
With the RS485/modbus working well enough to do some real testing work, and some LED's to flash I set about looking for a soft PLC. When I last searched I didn't really find anything in the open source space that was mature enough and provided the type of functionality I'm looking for.
Enter Classicladder. I'm sure I looked at it earlier in the year and it didn't support modbus, but it certainly does now. The project is mature, complied easily on two PC's I've tested it on and has 99% of the functionality I want.
Most importantly for an open source project, the code base is easy to follow, and the main developer appears from his forum posts to be open to new ideas. Because of those two things I'm confident I can add the extra bits of functionality to classicladder that I want for my projects.
Not only does classic ladder support modbus slaves for distributed I/O, but it also runs a modbus TCP slave internally, which means you can use it to feed an HMI/SCADA system as well. Two thumbs up for classicladder!
I did find one minor bug in classicladder, in the modbus master code, but outside that it's run my blinky LED test ladder (in the screen shot) for about 2 weeks solid on an old celeron laptop in the shed, talking happily to the RS485 connected RTU.
There are some nice looking HMI/SCADA packages around, lintouch and and visual seemed like good contenders, but don't feel very mature, and from my casual investigation seem to be too complex to implement for what I want to do.
So, off to 'proof of concept' land we go, with a working soft plc in the form of classicladder, my RTU and a vague plan. That vague plan is to have a web accessible HMI/Scada platform which I can use to ineract with the PLC (classicladder) which in turn is controlling my RS485 connected RTU(s) which then talk to the real world.
This is what I came up with, sorta:
Two small C programs using libmodbus to talk modbus TCP to the slave built into classicladder. One called 'poller' polls the boolean and register variables from classicladder, and the other 'setcoil' sets coils within classicladder which are linked to the boolean variables. Later on I'll have a 'setregister' to modify registers in classicladder for setpoints and timer constants etc.
Living on the web server are two distinct bits of php code, one which builds the dynamic javascript/AJAX code for the user interface, and the other a more conventional admin interface to configure inputs and outputs to be controlled or monitored.
The first test version of the HMI has two 'buttons' one of which was clickable to update a boolean (Coil) in classicladder and the other a non-clickable one which reflected the status of a second boolean value.
The '18.75' is the temperature sensed by a Dallas DS18B20 connected to a spare pin on the 16F628 in the RTU, the 6 is an 'internal' counter to classicladder and the wee bar graph is a graphical representation of he temperature.
Clicking on a wee power button icon and getting an LED to change on the RTU gave me a smile that lasted for about six hours. Much geekish glee can be had from such simple things!!!
My cunning plan is to write a set of AJAX 'widgets' which can be configured to appear at X,Y coordinates in a browser, then create a 'backdrop' image in a drawing package for them to live on top of.
The admin interface simply allows you to configure the widgets, scale factors and location etc. for display.
I've got all of the mechanics working, there is just some refinement required in the PHP/AJAX to classicladder step of the plan.
In this test the javascript requests an update of all the widgets from the web server (php/apache) every 5 seconds, which is fine for the web server, but this results in six simultaneous calls to classicladder which is quite inefficient, and classicladder runs out of sockets (if that's the right term) in it's tcp modbus slave code if you have more than two end user web clients connected.
To fix that problem I'm going to look into using a sequential update from classicladder into some shared memory tables between the poller code and the php/AJAX engine.
Rendering the graph in php and passing it as a PNG will have to be replaced with client-side graphics rendering in javascript as the update causes an annoying 'blink' of the bar every 5 seconds which would become very disracting if you had more than one or two graphs in your interface layout.
My AJAX code also needs some work as it has issues with Internet Explorer, and there is currently zero data validation in the interface which would obviously be a major issue in a real environment, but I'm quite excited about the progress, even if I do say so myself :-). 99% of my testing has been done in Firefox 3.0 under Linux at this stage.
For historical graphing I'll use 'logger' to scrape data from classicladder into a database, and then provide mouseover or click-link access to point history in the interface. I may even integrate the shared memory poller functionality into logger, although I've not yet investigated the possibility of using shared memory between 'C' and php code, I've only ever done it between processes developed in the same language. Sounds like a challenge.
And that, as they say, is that... Onwards and upwards.