I am working on a project in which I need to change the speed of servo motors. The hardware I am using is an Arduino Mega 2560 board and I am using Servo.h library to control servos. Servo rotates from o to 180 degree. I am using 12 servo motors in the project and have to control them simultaneously. Is there a way?
You can use delay() function in a while or for loop
Example:
Servo s;
s.attach(9);
for(int i=0 ; i<180 ; i++)
{
s.write(i);
delay(10); //10 milisecond
}
If they all are the same degree, try this code below.
At the very top (Not between any "{}"s):
#include <Servo.h>
Servo S1;
Servo S2;
Servo S3;
Servo S4;
Servo S5;
Servo S6;
Servo S7;
Servo S8;
Servo S9;
Servo S10;
Servo S11;
Servo S12;
Put this in Setup:
S1.attach(1);
S2.attach(2);
S3.attach(3);
S4.attach(4);
S5.attach(5);
S6.attach(6);
S7.attach(7);
S8.attach(8);
S9.attach(9);
S10.attach(10);
S11.attach(11);
S12.attach(12);
You need to change the pin numbers.
Just put this anywhere (Not between any "{}"s):
void TurnServos(int toDegree){
servosAt = S1.read;
if(servosAt == toDegree){
}
if(servosAt > toDegree){
while(S1.read > toDegree){
int currentToDegree = S1.read - 1;
S1.write(currentToDegree);
S2.write(currentToDegree);
S3.write(currentToDegree);
S4.write(currentToDegree);
S5.write(currentToDegree);
S6.write(currentToDegree);
S7.write(currentToDegree);
S8.write(currentToDegree);
S9.write(currentToDegree);
S10.write(currentToDegree);
S11.write(currentToDegree);
S12.write(currentToDegree);
delay(10); //Adjust this to make it faster or slower.
}
}
if(servosAt < toDegree){
while(S1.read < toDegree){
int currentToDegree = S1.read + 1;
S1.write(currentToDegree);
S2.write(currentToDegree);
S3.write(currentToDegree);
S4.write(currentToDegree);
S5.write(currentToDegree);
S6.write(currentToDegree);
S7.write(currentToDegree);
S8.write(currentToDegree);
S9.write(currentToDegree);
S10.write(currentToDegree);
S11.write(currentToDegree);
S12.write(currentToDegree);
delay(10); //Adjust this to make it faster or slower.
}
}
}
void ClearServos(){
int startDegree = 90; //Change this number to anything you want.
S1.write(startDegree);
S2.write(startDegree);
S3.write(startDegree);
S4.write(startDegree);
S5.write(startDegree);
S6.write(startDegree);
S7.write(startDegree);
S8.write(startDegree);
S9.write(startDegree);
S10.write(startDegree);
S11.write(startDegree);
S12.write(startDegree);
}
How to use this:
In setup before you do anything with servos but after the part I told you to put in setup, use ClearServos(); to prepare the servos to be used. (This probably isn't necessarily, but I don't know what happens when you use S1.read without changing it and if the servos are at different positions, it will fix problems. It can be avoided if it won't cause problems, but I think you should use it if you can.) All of them will turn to 90 degrees. (90 degrees can be changed with the variable startDegree in void ClearServos.)
To turn them, use TurnServos(90);. 90 is the degree you want it to turn to.
Haven't tested this because I don't have a Mega or 12 servos. Please comment if you notice any errors since this is huge. I spent a lot of time on this so I hope I helped. :)
Maybe you can put some resistors in series to your servo's VCC pin, before your servo motor to decrease the voltage across; thus slowing it. However, this will cause your servo's to be "constant" speed.
An alternative could be to put a transistor in between your servo VCC connection and set PWM on base pin to regulate current (to regulate speed), but that would cost you an extra pin per servo if you're not using a multiplexer in between; and could make your design a little more complicated.
delayMicroseconds(value) closest to 90-null is slowest for 360 servos both pan and carriage on my timelapse rig, shoot move shoot, in time with the mechanical shutter clicker (mini standard servo).
in Servo library WriteMicroseconds(...) function sets servo speed.
for more information please click
Related
I am new to Arduino and Esp32 programming. I need to connect PCA9685 controller to ESP-32 cam to be able to control multiple servo motors but the SCL and SDA pins are occupied by the UART control board.
I searched for this and found something related to Wire.h library and wire.begin() and TwoWire but unable to implement it.
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN 150 // This is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX 600 // This is the 'maximum' pulse length count (out of 4096)
#define USMIN 600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX 2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates
// our servo # counter
uint8_t servonum = 0;
void setup() {
Wire.begin();
Wire.begin(2,15,100000); // this is to map new SCL and SDA pins to 2,15
Serial.begin(9600);
Serial.println("8 channel Servo test!");
pwm.begin();
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates
delay(10);
}
// You can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise!
void setServoPulse(uint8_t n, double pulse) {
double pulselength;
pulselength = 1000000; // 1,000,000 us per second
pulselength /= SERVO_FREQ; // Analog servos run at ~60 Hz updates
Serial.print(pulselength); Serial.println(" us per period");
pulselength /= 4096; // 12 bits of resolution
Serial.print(pulselength); Serial.println(" us per bit");
pulse *= 1000000; // convert input seconds to us
pulse /= pulselength;
Serial.println(pulse);
pwm.setPWM(n, 0, pulse);
}
void loop() {
pwm.setPWM(0, 0, 250);
}
Here is the test code that I am trying to run.
I got the implementation idea from https://randomnerdtutorials.com/esp32-i2c-communication-arduino-ide/
There are a few problems that I encounter along with no response from the code-
When PCA9685 is connected to esp32-cam and I try to upload the code, it doesn't work and gives fatal error.
When the reset button is pressed before upload the built-in flash blinks. This is presented as a problem because while trying to upload the code without PCA9685 attached, the code is uploaded without any fatal error and there is no 'flash blink'.
I tried a code from the same website mentioned above that looks for I2C devices and prints their address. It shows no devices even though the servo controller is connected to it.
PS- I am an absolute beginner in this field.
Currently, my code below turns on the motor, delays for a bit then starts again. This is all being done in the clockwise direction, however how can I write my code so it can turn counter-clockwise?
int motorPin = 3;
void setup()
{
pinMode(motorPin, OUTPUT);
}
void loop()
{
startStopMotor(135);
delay(1000);
startStopMotor(0);
delay(1000);
}
void startStopMotor(int speed){
analogWrite(motorPin, speed);
}
By the code you share i'am guessing you are running a low power 5v dc motor... but you should edit your answer to give us what type of hardware you are using. This is not an answer but an idea of what you should be looking for... Basically on the motor i suppose you have, you have pin 1 and pin 2. Pin 1 is connected to a PWM signal and pin 2 is connected to ground. This configuration allows you to run your motor clock'wise. To run your motor counter clock'wise you need to invert the direction of the current basically have pin 1 connected to ground and pin 2 connected to a PWM signal.
Now there are multiple ways of doing this, i am unsure of the exact code to do this on an arduino but your pin 1 and 2 will be connected each to a PWM pin. In the code you will need to tell the arduino to put Pin 1 or 2 as a pullDown pin which basically mimics a ground thus telling the direction the other pin will output a PWM
this is not example code but it will give you an idea of what it should look like
void loop(){
//move clock'wise
pin1.pullup();
pin2.pulldown();
analogWrite(pin1, 180);
//move counterclock'wise
pin2.pullup();
pin1.pulldown();
analogWrite(pin2, 180);
}
I am painfully new to arduino so keep that in mind,
while experimenting with a volt meter sketch with a resistor divider (100k and 10k resistor) then I tried to connect a 5v power supply (regulated off board) I doubt it was the voltage due to the divider but I do not know about the current. what i didn't realize was I had not powered it on and got the infamous smell I the quickly disconnected it. after that i tried testing it again (this mainly took place on the analog 0 pin) the board seems to function fine except for the analog pins they will now read ~200 and will not work correctly in my other programs like a ohm meter this could be normal i don't know but i do know that it is not working anymore so any explanation is appreciated
when i say its not functioning i mean my sketches aren't working but it might help you to know my (not exactly mine) sketch
int analogPin= 0;
int raw= 0;
int Vin= 5;
float Vout= 0;
float R1= 1000;
float R2= 0;
float buffer= 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
raw= analogRead(analogPin);
if(raw)
{
buffer= raw * Vin;
Vout= (buffer)/1024.0;
buffer= (Vin/Vout) -1;
R2= R1 * buffer;
Serial.print("Vout: ");
Serial.println(Vout);
Serial.print("R2: ");
Serial.println(R2);
delay(1000);
}
}
so when i test it with the intended circuit from here
by default (no resistor) it returns around 3900 and when i attach a 330 resistor i get 3500
so overall can applying that is in the firts part damage the analog pins functionality and if not what couldve happend and if i can fix it
i hope that covers everything if i am forgetting something let me know
thank you
ps i am aware of other questions with returning wrong values but they do not answer any of my questions so please be accommodating
I don't understand how multiple PWM outputs are supposed to work. Look at the pic.
In the first(1) case we are using short signal width which would be close to motor staying still. In this case, as can be seen, short pulses follow each other, so does the code.
motor1.writeMicroseconds(shortWidth);
motor2.writeMicroseconds(shortWidth);
motor3.writeMicroseconds(shortWidth);
motor4.writeMicroseconds(shortWidth);
when motor4 ended it's output, motor1 starts it's pulse again causing non-problem consequent pulses.
In the second(2) case pulse is wider which corresponds to setting motor speed close to maximum. After motor1 finishes generating width, it's time for motor2 to generate one. But when it does, motor1's period comes to end and it has to start generate width again, but arduino is busy generating pulse of motor2.
How does PWMs work in this case?
You may want to look directly at the code of Servo.h and Servo.cpp. But two things to help understanding:
The servo does not react to PWM (pulse width modulation - pulse
duration versus cycle duration but the PDM (pulse duration
modulation - absolute time value). This means the servo does not go
to 0 when pulse has 0 duration, it goes to middle range (90°) when pulse
is 1.5 ms, it goes towards minimum position (0°) when
pulse is 1 ms and it goes to maximum position (180°) when pulse duration
goes to 2 ms. Total cycle is always around 20 ms. To be more precise, it generally
does not fully reach 0° and 180° and the min time is 0.5 ms and the max time
is around 2.5 ms, but this is beyond the specification of most servos.
Several servos are controlled by a single timer (usually timer_1
on Arduino). The timer is programmed when you do Servo.write(value),
then the hardware generates the pin change at the right time.
You can try the following code:
#include <Servo.h>
Servo myServo1;
Servo myServo2;
const int servo1Pin = 9;
const int servo2Pin = 10;
void setup(){
// attach servo to pin
myServo1.attach(servo1Pin);
myServo2.attach(servo2Pin);
}
void loop(){
myServo1.write(15); //set servo to 15°
myServo2.write(45); //set servo to 45°
delay(1000); //wait 1 second
myServo1.write(90); //set servo to 90°
myServo2.write(90); //set servo to 90°
delay(1000); //wait 1 second
myServo1.write(165); //set servo to 165°
myServo2.write(135); //set servo to 135°
delay(1000); //wait 1 second
}
I am trying to attach a servo on an Arduino (branded) Robot but not sure whhich pin to use for the bellow code.
Most people seem to recommend to use pin 9 and 10 to control the servo for arduino Unos.
However, I can't use Pin 9 because that is already used as the Slave Select pin for the LCD.
I have tried attaching it to pins TKD0-TKD3 by calling them pins 19-22 in myservo.attach(). The code runs but the servo doesn't rotate and only gets hot and/or twitches.
Could the problem be something other than incorrect pin connection?
Thanks,
-M
I have been referencing these for the Control board pin mapping:
http://arduino.cc/en/Main/Robot)
http://fabcirablog.weebly.com/blog/grappling-with-the-arduino-robot-control-board
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int pos = 0;
void setup()
{
myservo.attach(19); // attaches the servo on pin 9 to the servo object
}
void loop()
{
for(pos = 0; pos < 60; pos += 1)
{
myservo.write(pos);
delay(15);
}
for(pos = 60; pos>=1; pos-=1)
{
myservo.write(pos);
delay(15);
}
}
You have this robot, right?
Arduino Robot
And you are using a classic servo (3 pins, yellow red and black cable)? If so.... Watch out. According to the schematic, the pinout of the connector on the board (e.g. TKD0) is
+5V
AD1
GND
While usually servos have
DATA
+5V
GND
So.. you have to make a short cable to invert the pins.
If that's not the problem.. Are you sure that 19 is the right number for the pin? I can't find references, but i suggest you to call it TKD0 (which is probably a macro defining the right pin), as arduino designers suggest you.