I'm sure this is a very basic question but despite spending a good few hours searching I'm having no luck finding an answer.
I'm looking at controlling model railway turnouts using servos, a Mega and PCA9685s. The problem I have is that some scripts use the angle of the servo (i.e. 0 - 180) and some use position (1000 - 2000 i.e. pulse width).
The sketch below is my starting point. It's a turnout calibration sketch used by a YouTuber called Rob on his Little Wicket Railway videos (note: the calibration is running on a Nano linked to a PCA9685):
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates
uint8_t servonum = 0; // address of servo to be calibrated
String readString;
int pos;
void setup() {
Serial.begin(9600);
pos = 1500; // Initial position
pwm.begin();
pwm.setOscillatorFrequency(25000000);
pwm.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
Serial.println("Servo calibration");
Serial.println("Use this to calibrate your servo to find the range of movement required");
Serial.println("The servo should start close to the centre of the range");
Serial.println("Type a value followed by a + to move in one direction or a valu followed by a - to move in the other direction");
Serial.println("For example 100+ to 200-");
Serial.println("To move to a specific location use strings like 900x or 1800x for new servo position");
Serial.println("Move the servo to find the required range for whatever you're operating.");
Serial.println("Servos min and max can vary, try the 1000 - 2000 range to start with.");
Serial.println("WARNING: Exceeding the max range could damage the servo.");
Serial.println();
pwm.writeMicroseconds(servonum, pos);
Serial.println("Centre point:");
Serial.println(pos);
delay(10);
}
void loop()
{
while (Serial.available()) {
char c = Serial.read(); //gets one byte from serial buffer
readString += c; //makes the string readString
delay(2); //slow looping to allow buffer to fill with next character
}
if (readString.length() > 0) {
if (readString.indexOf('x') > 0) {
pos = readString.toInt();
}
if (readString.indexOf('+') > 0) {
pos = pos + readString.toInt();
}
if (readString.indexOf('-') > 0) {
pos = pos - readString.toInt();
}
pwm.writeMicroseconds(servonum, pos);
Serial.println(pos);
readString = ""; //empty for next input
}
}
This works perfectly well but when I found a sketch for moving the turnouts at a more realistic speed it was written in terms of the servo angle rather than the position.
So I thought I'd have a go at editing the original. It can't be that hard......
I subbed in "angle" for "pos" and having read this:
https://www.circuitbasics.com/controlling-servo-motors-with-arduino/
I tried subbing "write" for "writeMicroseconds".
This gave me an error message;
'class Adafruit_PWMServoDriver' has no member named 'write'; did you mean 'write8'?
I tried subbing in 'write8' but this did not appear to be recognised.
This is my sketch as it stands. I'd be most grateful if anyone could point me in the "write" direction (or point out any stupid mistakes).
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// #include <Servo.h> // added to see if it would allow the use of "write" but it didn't work
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates
uint8_t servonum = 0; // address of servo to be calibrated
String readString;
int angle; // subbed in angle for pos wherever it was found in the sketch
void setup() {
Serial.begin(9600);
angle=170; // Initial position (changed from pos=1500)
pwm.begin();
pwm.setOscillatorFrequency(25000000);
pwm.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
Serial.println("Servo calibration");
Serial.println("Use this to calibrate your servo to find the range of movement required");
Serial.println("The servo should start close to the centre of the range");
Serial.println("Type a value followed by a + to move in one direction or a value followed by a - to move in the other direction");
Serial.println("For example 100+ to 200-"); // This needs editing - and any line of text referencing position
Serial.println("To move to a specific location use strings like 900x or 1800x for new servo position");
Serial.println("Move the servo to find the required range for whatever you're operating.");
Serial.println("Servos min and max can vary, try the 1000 - 2000 range to start with.");
Serial.println("WARNING: Exceeding the max range could damage the servo.");
Serial.println();
pwm.write(servonum, angle);
Serial.println("Centre point:");
Serial.println(angle);
delay(10);
}
void loop()
{
while (Serial.available()) {
char c = Serial.read(); //gets one byte from serial buffer
readString += c; //makes the string readString
delay(2); //slow looping to allow buffer to fill with next character
}
if (readString.length() >0) {
if(readString.indexOf('x') >0) {
angle = readString.toInt();
}
if(readString.indexOf('+') >0) {
angle = angle + readString.toInt();
}
if(readString.indexOf('-') >0) {
angle = angle - readString.toInt();
}
pwm.write(servonum, angle); //write subbed in for writeMicroseconds
Serial.println(angle);
readString=""; //empty for next input
}
}
If you've made it this far, thanks!