Hi,
I am using 12 motors to control 6 pan tilt mechanism:
with servo g9.
the pan tilt uses to adjust the position of 5 mirrors and one laser.
in my dreams it will create a few shapes in the space with smoke.
I created two codes, maybe later I will combine them.
one for building the cues and one for playing them.
the inspiration was this video:
and I used the same schematics which is pretty straight forward..
the main difference I made is:
- connecting the power and ground of two servos which are on the same mirror
- I extended all of the wires (common voltage, common ground, signal tilt, signal pan for every mirror - pan-tilt system) to 1 meter long.
- I use 5v 10amp to power 12 sg9 which should be sufficient.
I will add videos and pictures later this week, my main question is:
How can i improve the reliability of the system?
and in more detail:
Sometimes when i change in one degree the servo motor doesn't respond, why?
my options (will be happy to hear your opinions):
- secure the pan-tilt heads better to the ground with weight and masking tape etc.
- maybe using the writeMicroseconds() instead of the pwm logic, and connect the servo motors to individual different pins on the esp32 (i heard this function is more accurate and provide a better resolution of control)
- giving up on the stand they stand on and do them fixed to the ground
- changing motors
the code:
- the code for building the cues:
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// [62, 28, 110, 123, 35, 103, 30, 30, 127, 75, 50, 90, 0, 0, 0, 0]
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
#define SERVOMIN 140 // minimum pulse length count (out of 4096)
#define SERVOMAX 590 // maximum pulse length count (out of 4096)
int servoAngles[17]; // Array to store angles for each servo and delay time
void setup() {
pinMode(13, OUTPUT);
Serial.begin(115200);
Serial.println("32 channel Servo test!");
board1.begin();
board1.setPWMFreq(60); // Analog servos run at ~60 Hz updates
// Initialize all servo angles to zero
for (int i = 0; i < 17; i++) {
servoAngles[i] = 0;
}
}
void loop() {
digitalWrite(13, HIGH);
if (Serial.available() > 0) {
String command = Serial.readStringUntil('\n'); // Read command from serial
if (command.startsWith("print")) { // Check if command is "print"
printServoAngles();
} else if (command.startsWith("delay")) { // Check if command is "delay"
int delayTime = command.substring(command.indexOf(' ') + 1).toInt();
servoAngles[16] = delayTime;
} else {
Serial.print("received command.. moving...");
// Parse servo number and angle
int servoNumber = command.substring(0, command.indexOf(' ')).toInt();
int angle = command.substring(command.indexOf(' ') + 1).toInt();
if (angle >= 0 && angle <= 180 && servoNumber >= 0 && servoNumber < 16) {
board1.setPWM(servoNumber, 0, angleToPulse(angle)); // Set servo position
servoAngles[servoNumber] = angle; // Update stored angle
Serial.print("Servo ");
Serial.print(servoNumber);
Serial.print(" set to angle ");
Serial.println(angle);
} else {
Serial.println("Servo number or angle out of range");
}
}
}
// Wait for the servo to reach the desired position
delay(500);
}
int angleToPulse(int ang) {
int pulse = map(ang, 0, 180, SERVOMIN, SERVOMAX);
return pulse;
}
void printServoAngles() {
Serial.print("Servo angles array: [");
for (int i = 0; i < 16; i++) {
Serial.print(servoAngles[i]);
if (i < 15) {
Serial.print(", ");
}
}
Serial.println("]");
Serial.print("Delay time: ");
Serial.println(servoAngles[16]);
}
- the code for playing the cues:
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver board1 = Adafruit_PWMServoDriver(0x40);
#define SERVOMIN 140 // minimum pulse length count (out of 4096)
#define SERVOMAX 590 // maximum pulse length count (out of 4096)
// Define servo positions
int servoAngles[] = {83, 60, 85,142, 45, 80, 0, 90, 115, 55, 58, 70, 0, 0, 0, 0,
95, 62, 3, 125, 100, 98, 90, 90, 114, 55, 90, 70, 0, 0, 0, 0};
int numServoAngles = sizeof(servoAngles) / sizeof(servoAngles[0]);
// Define array for moving times between queues
unsigned long movingTimes[] = {2000, 2000, 2000,1000}; // Example: 1s from 0 to 1, 1.5s from 1 to 2, 2s from 2 to 0
unsigned long moveStartTime;
unsigned long startAngle = 90;
unsigned long j = 0; // Global variable for servo position index
bool play = false;
void setup() {
pinMode(13, OUTPUT);
Serial.begin(115200);
Serial.println("32 channel Servo test!");
board1.begin();
board1.setPWMFreq(60); // Analog servos run at ~60 Hz updates
for (int k = 0; k < 16; k++) {
board1.setPWM(k, 0, angleToPulse(startAngle));
}
}
void loop() {
if (Serial.available() > 0) {
String command = Serial.readStringUntil('\n'); // Read command from serial
if (command.startsWith("play")) { // Check if command is "play"
moveStartTime = millis(); // Record the start time
digitalWrite(13, HIGH);
play = true;
} else if (command.startsWith("stop")) { // Check if command is "stop"
// Stop playing servo angles
// You can add additional logic here if needed
digitalWrite(13, LOW);
play = false;
}
}
if (play) {
playServoAngles(); // Update servo angles continuously
}
}
int angleToPulse(int ang) {
int pulse = map(ang, 0, 180, SERVOMIN, SERVOMAX);
return pulse;
}
int pulseToAngle(int ang) {
int pulse = map(ang, SERVOMIN, SERVOMAX, 0, 180);
return pulse;
}
void playServoAngles() {
unsigned long progress = millis() - moveStartTime; // Calculate progress
if (j < numServoAngles / 16) {
if (progress <= movingTimes[j]) {
for (int k = 0; k < 16; k++) {
// Get current and next angle for the servo
int currentAngle = angleToPulse(servoAngles[k + j * 16]);
int nextAngle;
if (j + 1 < numServoAngles / 16) {
nextAngle = angleToPulse(servoAngles[k + (j + 1) * 16]);
} else {
nextAngle = angleToPulse(servoAngles[k]);
}
if(k==0 or k==1){
Serial.print("the moving time is: ");
Serial.println(movingTimes[j]);
Serial.print("and i am going from: ");
Serial.print(pulseToAngle(currentAngle));
Serial.print(" to: ");
Serial.println(nextAngle);
}
// Calculate the angle based on progress
long angle = map(progress, 0, movingTimes[j], currentAngle, nextAngle);
// Set servo position
board1.setPWM(k, 0, angle);
}
} else {
j++;
moveStartTime = millis(); // Reset move start time for next position
}
} else {
j = 0; // Reset j to start from the first position
}
}
