Programming for Realistic Semaphore Control using PCA 9685

I considered that but decided to make things more explicit which is helped by the struct members having names

1 Like

Interesting. I'd embed the name in the struct, if I felt it had to have a name. Again, YMMV.
Of course, that means you don't use the names explicitly in the program.

I agree, see post #10

1 Like

What, me, re-read upthread? Naah. I'll take your word for it. Sorry about that!

No problem !

The problem with that is that the I2C bus that connects the PCA9685 to the Uno was not designed for long distances.

HDMI includes an I2C channel (for reading "device info" from the monitor/etc. ) That implies that I2C will work over pretty significant distances, at least with "moderately well designed" cables. Five to ten meters...

Thanks, for that. I'll give it a try later.

Not going to pretend to understand half of what's going on there I'll have to do a bit of reading up on stuct I guess

I am assuming the Loop code is written in such a way that it means I dont have to have the code present for each connection i.e. by virtue of the data it's checking all of the pinNumbers and then acting on the associated pwmChannel when there is a LOW or HIGH?
Can I ask is it the line for (int s = 0; s < signalCount; s++) that facilitates this? 's' is simply used as a reference and each time the loop runs 's' increases by 1? Until it reaches 'signalCount'?

What is the purpose of this line byte signalCount = sizeof(signals) / sizeof(signals[0]); ? What reference / purpose do the '[]' have after 'signals'?

The amount of code in loop() is reduced by using a for loop

or (int s = 0; s < signalCount; s++)

to iterate through the array of structs that contains the data for each signal. When s is 0 the data for signal 0 in the array is accessed, when s is 1 then the data for signal 1 in the array is accessed

This brings us to

byte signalCount = sizeof(signals) / sizeof(signals[0]);

This calculates the number of signals in the array by dividing the total number of bytes used by the array by the size of its first element. The number of signals in the array is used later as the limit for the value of s in the for loop

By doing it this way you can add as many signals as you like to the array in this list

signalData signals[] = {
    { 3, 200, 120, 0 },
    { 4, 190, 104, 1 },
};

without the need to change any code in loop(), or anywhere else for that matter

Please feel free to ask more questions if you have them

1 Like

Thanks for the help @UKHeliBob and the option to keep bothering you with more Qs! That's very kind and it's very helpful!

Let me see if I understand correctly then:
sizeof(signals) - counts the number of pieces of data in the entire array?
sizeof(signals[0]) - counts the pieces of data in the array at line 0?
So the [] refer to a line in the array?
s < signalCount - stops the increment, will this stop short of the last line?

Close, but no cigar !

sizeof(signals)  

The total number of bytes used by the array of enums. The data items in the enum do not have to be of type byte. For instance, if you need an int value then each of them would take 2 bytes on an AVR processor so this needs to be allowed for

sizeof(signals[0])

The total number of bytes in a single level of the array

Dividing the total number of bytes used by the array by the number of bytes used by one of its levels gives the number of levels in the array

s < signalCount

The array index starts at 0 so an array with 2 entries with have one indexed as 0 and another indexed as 1 and signalCount would equal 2 in this case

We need to access levels 0 and 1 so we read each level using the for loop while s is less than 2, ie 0 or 1

We do not stop short of the last level in the array as that level is number 1

1 Like

(with apologies, an earlier draft of a reply to westfw was in buffer, but I neglected to start a new response when I wrote the following)

possibly, better worded as "...a single element..."
The key concept here is arrays are uniform. Each element of an array occupies the same number of bytes, so sizeof(array)/sizeof(array[0]) reliably tells us how many elements are in the array; that they are found at index values 0...(size-1) is just because array indexing is done that way in C.

1 Like

Brill!

The rabbit holes you find to take yourself down eh... I only wanted a trainset :joy:

Looking forward to uploading that later and giving it a shot then. Provided I get it right that'll leave me the PCA9685 distance problem to solve... worst case scenario that means separate servo wiring... no big deal...

and then on to the realistic movement... :grimacing:

Just tried this @UKHeliBob and I'm still getting that strange pulsing behaviour on the 1st servo which speeds up with a button press... no response from the 2nd servo?

Right, I added a 1000 delay after the else part of the loop and it is repeating the 'write danger'...

writing danger 104 to pwm channel 1

writing danger 120 to pwm channel 0

writing danger 104 to pwm channel 1

writing danger 120 to pwm channel 0

writing danger 104 to pwm channel 1

... in the serial monitor.

But this only seems to be talking to servo 1 (in pins 0) hence the wobble. Any ideas?

Another silly mistake on my part

The code was always writing to channel 0 in the for loop, but not any more !

#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver signalBoard01 = Adafruit_PWMServoDriver(0x40);

#define SERVOMIN 100  // this is the 'minimum' pulse length count (out of 4096)

#define SERVOMAX 710  // this is the 'maximum' pulse length count (out of 4096)

struct signalData
{
    byte pinNumber;
    byte clear;
    byte danger;
    byte pwmChannel;
};

signalData signals[] = {
    { 3, 200, 120, 0 },
    { 4, 190, 104, 1 },
};

byte signalCount = sizeof(signals) / sizeof(signals[0]);

void setup()
{
    Serial.begin(115200);
    pinMode(signals[0].pinNumber, INPUT_PULLUP);
    pinMode(signals[1].pinNumber, INPUT_PULLUP);

    Serial.println("GingerAngles Signal Control!");

    signalBoard01.begin();
    signalBoard01.setPWMFreq(50);  // Analog servos run at ~60 Hz updates
}

void loop()
{
    for (int s = 0; s < signalCount; s++)
    {
        if (digitalRead(signals[s].pinNumber) == LOW)
        {
            signalBoard01.setPWM(signals[s].pwmChannel, 0, signals[s].clear);
            Serial.print("writing clear ");
            Serial.print(signals[s].clear);
            Serial.print(" to pwm channel ");
            Serial.println(signals[s].pwmChannel);
        }
        else
        {
            signalBoard01.setPWM(signals[s].pwmChannel, 0, signals[s].danger);
            Serial.print("writing danger ");
            Serial.print(signals[s].danger);
            Serial.print(" to pwm channel ");
            Serial.println(signals[s].pwmChannel);
        }
    }
    Serial.println();
    delay(10);
}

Hopefully I have got it right this time ,,,

1 Like

Perfect! That seems to have sorted that issue thank you.

I have added 2 more servos to pins 4 and 5 and have those working. This is great - really easy to set the servo position by updating the struct!

Once I get to pin 13 on the Uno what are my options for additional switches then? Can I also use pins 0, 1 and 2 or are they for something special? Can the analog inputs be used as digital inputs? I presume there are add on boards that allow more inputs?

Whew, that is a relief. It could have been working some time ago if I didn't make silly mistakes :grinning:

Data driven coding wins the day

Keep away from pins 0 and 1 as they are used by the Serial interface but you can use the analogue pins on the Uno to drive servos as they double up as digital pins

1 Like

Dont worry, I'm here a lot quicker with your help than without that's for sure!

How are the analog pins addressed in the coding? A1, A2? Do they have the PULLUP capability as well?

Just use the names printed on the board, ie A0, A1, A2 etc as you suggest and, yes, they support INPUT_PULLUP

1 Like

Next step, throw all that customization into EEPROM, and make your code generic by reading the configuration at startup... One code, multiple locations, no problem.