ajhart
Hi

I'm very new to PLC programming and have a ton of questions. 😬
Thank you very much for a wonderful program!

Im currently working on a Generator ATS solution / project, as were the setup is quite simple. Generator needs to start after a certain time when main power fails and stop when main power restores, making use of Raspberry Pi Model 3 B, 8 Relay Module and MG995 Servo Motors.

The generator choke and boost leavers can be controlled using the servo motors. I have tried solenoids, but the stroke travel is to short.

I have tried to configure my own PWM using FBD TP, RS and TON functions, but did not work.

Untitled.png 
I have searched the net, forums, playing with python scripts ect, but have no idea how to create a PWM function that can output to %QW0.0 in OpenPLC Editor.
The other questions is, how can I add another PWM output for the second servo motor.

Here is the rest of the program for those interested:

Untitled1.png Untitled2.png 
I also have a problem with the 8 relay module where all relays outputs is active when program starts. When program stops, relays stay all active. How can I negate all outputs when PLC starts?

Any ideas and input will be very much appreciated.
Quote 0 0
thiagoralves
OpenPLC is not fast enough to generate 2ms PWM pulses in software, unless you make the main task run faster. However, on a Pi, having a task run in less than 1ms will be problematic. Therefore, the most appropriate way to generate a PWM signal is by using a PWM hardware unit that OpenPLC can configure and control. The Raspberry Pi has only one PWM hardware pin available, so there isn't a way to have more than one PWM output on the Pi.  You can try to multiplex this signal for the two servos, or use an Arduino as a slave device to control the servos.

Using PWM is quite simple, you just need to use an unsigned integer variable (UINT) located in %QW0. Whatever value you put on that variable will be translated as the duty cycle for the PWM on %QW0. The PWM on the Pi is preconfigured in balanced mode, which means that the frequency varies according to the duty cycle. This is the default mode for the broadcom chip. If you want to set a fixed frequency, you will have to modify the RaspberryPi driver for OpenPLC. I posted instructions on how to do that some time ago: https://openplc.discussion.community/post/qw0-0-frequency-8409246
Quote 0 0
ajhart
Thank you very much, I will give it a shot.
Do you have any advice on how I negate (high) all outputs when PLC starts and stops?
Quote 0 0
thiagoralves
For safety reasons a PLC must always start up and shutdown with outputs disabled. However, if you still want have them all active, you will have to modify the disableOutputs() function on main.cpp to have it write 1 instead of 0 to all buffers. For analog buffers, you would have to write 65535 for maximum output.
Quote 0 0
ajhart
Worked perfectly, thank you. I discovered that the 8 relay module is n low level trigger module. Currently exploring options for NPN OR GATE IC to convert it to a high level trigger.
Quote 0 0
ajhart
Back to the PWM, What value do I need to set the UINT to get 1,5 ms. I have tried a few values, but does not work. Untitled3.png 
I have also configured the /core/hardware_layer.cpp as suggested:

Untitled4.png 

Any advice will be greatly appreciated.
Quote 0 0
ajhart
I unfortunately cant get the servo to work, it does not matter what duty cycle value I give. I have run a coupe of python scrips and servo does work fine. Is there anyone that can give me a tutorial on how to setup a servo motor using OpenPLC.
Quote 0 0
thiagoralves
You gotta solve your math problem instead of just copying numbers from other people. You’re setting your PWM clock to 375, which might not be the right resolution if you want a 1.5ms pulse. I don’t have time now to solve your math problem for you, but just to let you thinking, with 375 on your PWM clock you’re generating 50 Hz cycles (total cycle duration is 1/50 = 20ms). Given that the resolution of the PWM on the OpenPLC is 65535, you do the math on how long your duty cycle must be for you to have a 1.5ms pulse. Ideally, you should have an oscilloscope to analyze the pulses you’re generating. This will make it a lot easier to solve your problem. Without it, it is like if you’re asking a blind person to paint a picture 
Quote 0 0
ajhart
Thank you for your responses thiagoralves...

Unfortunately I do not own a oscilloscope, that should come in very handy.
According to the data sheet, 20ms duty cycle (50Hz) should work perfect.
"The Raspberry Pi PWM clock has a base frequency of 19.2 MHz" and "OpenPLC uses pwmRange = 1024"
19200000 Hz / 1024 pwmRange / 50 Hz = 375 pwmClock

Im not completely sure what you meant by "resolution of the PWM on the OpenPLC is 65535"
Q1 - 19200000 Hz / 65535 pwmRange / 50 Hz = 5,85 pwmClock ?

As I mentioned above, using 50hz in python works fine, getting full 180 rotation between 2,8 % and 11

Untitled5.png  MG995-Graph.png

Calculating the Duty cycle % for pulses needed should be fairly easy:
(0,5ms pulse / 20 ms cycle) * 100 = 2,5 %
(1,5ms pulse / 20 ms cycle) * 100 = 7,5 %
(2,5ms pulse / 20 ms cycle) * 100 = 12,5 %

I have tried to apply a few UINT variables range between 3 and 11 using SFB but did not work.

Q2 - Does it translate the duty cycle % or the time?
Q3 - How do I input a decimal value?
Untitled6.png 

Q4 - Im not sure how to trigger the pwm output, is the SFB method Im using in above shown picture correct?
Q5 - Every time I configure hardware_layer.cpp and recompile hardware settings, the parameters goes away, so I configured hardware_layers/raspberrypi.cpp. Should that be fine?
Quote 0 0
thiagoralves
ajhart wrote:

Im not completely sure what you meant by "resolution of the PWM on the OpenPLC is 65535"
Q1 - 19200000 Hz / 65535 pwmRange / 50 Hz = 5,85 pwmClock ?

As I mentioned above, using 50hz in python works fine, getting full 180 rotation between 2,8 % and 11

Untitled5.png  MG995-Graph.png

Calculating the Duty cycle % for pulses needed should be fairly easy:
(0,5ms pulse / 20 ms cycle) * 100 = 2,5 %
(1,5ms pulse / 20 ms cycle) * 100 = 7,5 %
(2,5ms pulse / 20 ms cycle) * 100 = 12,5 %

I have tried to apply a few UINT variables range between 3 and 11 using SFB but did not work.

OpenPLC has 16 bit analog resolution in software, even though not all hardware boards support 16 bit analog outputs. The Raspberry Pi has a 10-bit PWM in hardware, so OpenPLC translates (multiplies) that to 16-bit internally so that the same code works on all supported platforms. If you need a 20ms PWM period, than 375 pwmClock is the right number for you. However, to control the duty cycle of this period, you will need to use a number from 0 to 65535, where 65535 is equal to 100% duty cycle. If you want a 2.5% duty cycle (0.5ms pulse) your UINT on %QW0 should be:
(65535*2.5)/100 = 1638.375

Since UINT only accept integers, you will have to round it down to 1638 and have some little error on it. As you can see, values between 3 and 11 on the PWM output will literally translate to zero on the output since OpenPLC works with a higher resolution than the Raspberry Pi hardware.
ajhart wrote:

Q2 - Does it translate the duty cycle % or the time?

I think I kinda answered that one on my explanation for Q1. But just to make it clear, it is neither time or duty cycle. OpenPLC uses a 16-bit value for all analog inputs and outputs. That number linearly represents the power used on the output, be it a true voltage output, current output or PWM output. The nuances about what kind of output is used is left to the platform where OpenPLC is running. 
ajhart wrote:

Q3 - How do I input a decimal value?
Untitled6.png 

You cannot put decimal (REAL) values on %QW0, as explained above.
ajhart wrote:

Q4 - Im not sure how to trigger the pwm output, is the SFB method Im using in above shown picture correct?

All you have to do is write a value on the %QW0 variable. You can either initialize the variable with the value you want (as you did before), or use MOVE, ADD, SUB, MUL, etc, blocks to put the value you want in there during run time.
ajhart wrote:

Q5 - Every time I configure hardware_layer.cpp and recompile hardware settings, the parameters goes away, so I configured hardware_layers/raspberrypi.cpp. Should that be fine?

That is the preferred file to modify if you want your changes to be permanent.
Quote 0 0
ajhart
Thank you very much! You have cleared up a lot of uncertainties. 😁 
Quote 0 0
ajhart
I Have tested given calculations, but does not work.

0 degree - uint 328   Stall fully clockwise over
90 degree - uint 998   Stall fully clockwise over 
180 degree - uint 1637   Stall fully clockwise over
uint 0   Stall fully clockwise over
uint 66536   Stall fully clockwise over

Not sure what is causing this....

Q1 - Would it be possible to execute this python script on Boolean trigger:

import pigpio
from time import sleep
# connect to the 
pi = pigpio.pi()
# loop forever
while True:
    pi.set_servo_pulsewidth(18, 0)    # off
    sleep(2)
    pi.set_servo_pulsewidth(18, 700) # position anti-clockwise
    sleep(2)
    pi.set_servo_pulsewidth(18, 1500) # middle
    sleep(2)
    pi.set_servo_pulsewidth(18, 2400) # position clockwise
    sleep(2)


Found this jitter free library by installing: sudo apt-get install pigpio python-pigpio python3-pigpio
Work very well.
Quote 0 0
thiagoralves
This is weird. Are you sure that there aren’t any libraries or other software interfering with the PWM pin? Are you able to control other pins with OpenPLC? About executing a script with a Boolean control, this is indeed possible. You can abuse the compiler pragmas to make OpenPLC execute system commands at any point on your program. This post explains better how to do it (check my last post on the thread):  https://openplc.discussion.community/post/command-exec-in-openplc-rpi-9707083
Quote 0 0
ajhart
The servo only turns fully clockwise over when OpenPLC is started. I have double checked any other activities. I will try the exec command options.

Thank you.
Quote 0 0
tim292stro
One of the things that got me on my first RPi hardware design was the factory pull-ups/pull-downs.  I didn't see anything in your code above declaring the pull-up/down configurations - perhaps it's my inexperience with the pigpio library (I always use the BCM2835 C-library for best speed).  What this would do however is that if you are active-high and have a pull up, you may not be driving low ever.

* EDIT, I do now see some pull-down configured - be carefull with polarity *

One thing you can do is to put an LED on the PWM circuit, so that you can see the brightness change with SW control.  It's not an o-scope, but it's cheap and easy and it'll do in a pinch.

One thing that occurs to me is that if you're using RC servos to actuate the throttle/choke - why not use an I2C to PWM servo drive board?  For $15USD, you can get a 16-channel 12-bit board that free-runs which means there's no RPi CPU load after value set - it's based on an NXP PCA9685 ($2.50 for the bare part if you spin your own PCB).

( https://www.adafruit.com/product/815 )

Another thing that occurs to me is that you seem to be using the RPi to control the engine RPMs - is this correct?  Is this an AC system?

I'm interested in your project as I'm about to start my own similar 3-phase Gen/UPS (using third party ATS by Asco) for a storage container-shop build.
Quote 0 0