Robin2
December 6, 2018, 12:33pm
1
I have created a struct like this
struct turnoutStruct {
byte servoPin;
unsigned long straightMicros;
unsigned long turnedMicros;
Servo tServo;
};
and initialized it like this (for testing)
turnoutStruct turnout[2] = {
{24,1300,1000},
{26,1301,1001}
};
and then I wrote this little function to print the values just to make sure it is being intialized properly
void setupTurnouts() {
for (byte n = 0; n < 2; n++) {
Serial.print(turnout[n].servoPin);
Serial.print(' ');
Serial.print(turnout[n].straightMicros);
Serial.print(' ');
Serial.print(turnout[n].turnedMicros);
Serial.println();
turnout[n].tServo.attach(turnout[n].servoPin);
turnout[n].tServo.writeMicroseconds(turnout[n].straightMicros);
Serial.println("done");
}
}
All this works fine.
However look at these two lines
turnout[n].tServo.attach(turnout[n].servoPin);
turnout[n].tServo.writeMicroseconds(turnout[n].straightMicros);
There is a huge amount of repetition of turnout[n]
Is there some simpler way I can express that code - maybe something like this
turnX = turnout[n];
turnX.tServo.attach(turnX.servoPin);
turnX.tServo.writeMicroseconds(turnX.straightMicros);
or even something simpler and more obvious?
I have done some Googling but it was ineffective, perhaps because I don't know the appropriate search term, or maybe there is no simpler way.
...R
How about a pointer or reference:
void setupTurnouts()
{
for (byte n = 0; n < 2; n++)
{
turnoutStruct *tsp;
turnoutStruct &tsr=turnout[n];
tsp=&turnout[n];
Serial.print(turnout[n].servoPin);
Serial.print(' ');
Serial.print(turnout[n].straightMicros);
Serial.print(' ');
Serial.print(turnout[n].turnedMicros);
Serial.println();
turnout[n].tServo.attach(turnout[n].servoPin);
turnout[n].tServo.writeMicroseconds(turnout[n].straightMicros);
tsp->tServo.attach(turnout[n].servoPin);
tsp->tServo.writeMicroseconds(turnout[n].straightMicros);
tsr.tServo.attach(turnout[n].servoPin);
tsr.tServo.writeMicroseconds(turnout[n].straightMicros);
Serial.println("done");
}
}
Juraj
December 6, 2018, 1:16pm
4
use reference. it will be optimized away
TurnoutStruct& item = turnout[n];
Servo& servo = item.tServo;
I would name the struct type with uppercase first letter.
I'd go full-OOP:
struct turnoutStruct {
byte servoPin;
unsigned long straightMicros;
unsigned long turnedMicros;
Servo tServo;
void begin() {
tServo.attach(servoPin);
tServo.writeMicroseconds(straightMicros);
}
};
turnoutStruct turnout[] = {
{24, 1300, 1000},
{26, 1301, 1001}
};
const uint8_t numTurnout = sizeof(turnout) / sizeof(turnout[0]);
void setupTurnouts() {
for (byte n = 0; n < numTurnout; n++) {
Serial.print(turnout[n].servoPin);
Serial.print(' ');
Serial.print(turnout[n].straightMicros);
Serial.print(' ');
Serial.print(turnout[n].turnedMicros);
Serial.println();
turnout[n].begin();
Serial.println("done");
}
}
void setup() {
Serial.begin(115200);
delay(1000);
setupTurnouts();
}
void loop() {}
Or:
struct turnoutStruct {
byte servoPin;
unsigned long straightMicros;
unsigned long turnedMicros;
Servo *tServo;
void begin() {
if (!tServo) {
tServo = new Servo;
if (tServo) {
tServo->attach(servoPin);
tServo->writeMicroseconds(straightMicros);
}
}
}
};
turnoutStruct turnout[] = {
{24, 1300, 1000, nullptr},
{26, 1301, 1001, nullptr}
};
const uint8_t numTurnout = sizeof(turnout) / sizeof(turnout[0]);
void setupTurnouts() {
for (byte n = 0; n < numTurnout; n++) {
Serial.print(turnout[n].servoPin);
Serial.print(' ');
Serial.print(turnout[n].straightMicros);
Serial.print(' ');
Serial.print(turnout[n].turnedMicros);
Serial.println();
turnout[n].begin();
Serial.println("done");
}
}
void setup() {
Serial.begin(115200);
delay(1000);
setupTurnouts();
}
void loop() {}
system
December 6, 2018, 1:48pm
6
Why not give the turnoutStruct struct (or class) methods to initialize and print itself? Then, it would be really simple.
void setupTurnouts()
{
for (byte n = 0; n < 2; n++)
{
turnout[n].init();
turnout[n].print();
}
}
As you don't need the index, you could use range-based for loop + auto specifier :
void setupTurnouts() {
for (auto& t : turnout) {
Serial.print(t.servoPin);
Serial.print(' ');
Serial.print(t.straightMicros);
Serial.print(' ');
Serial.print(t.turnedMicros);
Serial.println();
t.tServo.attach(t.servoPin);
t.tServo.writeMicroseconds(t.straightMicros);
Serial.println("done");
}
}
Robin2
December 6, 2018, 3:32pm
8
Thanks.
I had overlooked the idea of creating a class with methods. I will consider that. As there will be 10 or 12 turnouts that may be a good idea.
...R
Robin2
December 6, 2018, 9:36pm
9
I have arrived at the following using a Class which seems to work very neatly. Thanks again tor the hint.
// python-build-start
// action, upload
// board, arduino:avr:mega:cpu=atmega2560
// port, /dev/ttyACM0
// ide, 1.8.6
// python-build-end
#include <Servo.h>
class TurnoutClass {
private:
byte servoPin;
unsigned long straightMicros;
unsigned long turnedMicros;
char setting;
Servo tServo;
public:
TurnoutClass(byte p, unsigned long s, unsigned long t) {
servoPin = p;
straightMicros = s;
turnedMicros = t;
tServo.attach(servoPin);
straight();
}
void straight() {
tServo.writeMicroseconds(straightMicros);
setting = 'S';
}
void turned() {
tServo.writeMicroseconds(turnedMicros);
setting = 'T';
}
bool isServoAttached() {
return tServo.attached();
}
void showVals() {
Serial.print("Pin "); Serial.print(servoPin);
Serial.print(" Str "); Serial.print(straightMicros);
Serial.print(" Trn "); Serial.print(turnedMicros);
Serial.print(" Set "); Serial.print(setting);
}
};
TurnoutClass turnout[2] = {
{23,1300,1000},
{26,1301,1001}
};
void setup() {
Serial.begin(500000);
Serial.println("Starting ClassTest.ino");
Serial.println("Starting values");
for (byte n = 0; n <2; n++) {
turnout[n].showVals();
Serial.print(" Attached "); Serial.print(turnout[n].isServoAttached());
Serial.println();
}
Serial.println("Updated Setting");
turnout[0].turned();
turnout[0].showVals();
Serial.println();
}
void loop() {
}
...R
Robin2:
I had overlooked the idea of creating a class with methods.
The idea was staring you in the face. A struct is a class . The only difference is the default access modifier.
Which is how tServo came to be reasonably initialized. The compiler synthesized a default constructor for your turnoutStruct class.
TurnoutClass(byte p, unsigned long s, unsigned long t) {
...
tServo.attach(servoPin);
straight();
Do not touch the hardware until setup is called. Those calls to tServo.attach and straight need to be moved to a begin method which will (usually) be called from setup .
Robin2
December 6, 2018, 10:50pm
13
While having a galss of wnie I realized that the attach could not happen at compile time. This version works
// python-build-start
// action, upload
// board, arduino:avr:mega:cpu=atmega2560
// port, /dev/ttyACM0
// ide, 1.8.6
// python-build-end
#include <Servo.h>
class TurnoutClass {
private:
byte servoPin;
unsigned long straightMicros;
unsigned long turnedMicros;
char setting;
Servo tServo;
public:
TurnoutClass(byte p, unsigned long s, unsigned long t) {
servoPin = p;
straightMicros = s;
turnedMicros = t;
}
void straight() {
tServo.writeMicroseconds(straightMicros);
setting = 'S';
}
void turned() {
tServo.writeMicroseconds(turnedMicros);
setting = 'T';
}
bool isServoAttached() {
return tServo.attached();
}
void attach() {
tServo.attach(servoPin);
straight();
}
char direction() {
return setting;
}
void showVals() {
Serial.print("Pin "); Serial.print(servoPin);
Serial.print(" Str "); Serial.print(straightMicros);
Serial.print(" Trn "); Serial.print(turnedMicros);
Serial.print(" Set "); Serial.print(setting);
}
};
TurnoutClass turnout[2] = {
{A0,1400,1000},
{26,1301,1001}
};
void setup() {
Serial.begin(500000);
Serial.println("Starting ClassTest.ino");
Serial.println("Starting values");
for (byte n = 0; n <2; n++) {
turnout[n].attach();
turnout[n].showVals();
Serial.print(" Attached "); Serial.print(turnout[n].isServoAttached());
Serial.println();
}
Serial.println("Updated Setting");
turnout[0].turned();
turnout[0].showVals();
Serial.println();
}
void loop() {
if (turnout[0].direction() == 'S') {
turnout[0].turned();
}
else {
turnout[0].straight();
}
turnout[0].showVals();
Serial.println();
delay(2000);
}
...R
Robin2
December 6, 2018, 10:52pm
14
I have looked at the link but I don't understand what you are suggesting or why.
...R
Instead of this..
turnout[0].showVals();
Serial.println();
This...
Serial.println(turnout[0]);
Which is more intuitive and allows printing to other destinations like an LCD.
Robin2
December 6, 2018, 11:17pm
16
I think I see what you are getting at. The showVals() is only for debugging so not worth changing.
...R