I am using Arduino UNO and I have 5 MG995 servo motors. But when i test the machine using 1 servo motor, it does not work.
My connections are not wrong. Ports are okay but i don't know why it doesn't work.
My code for one servo motor.
#include<Servo.h> // include server library
Servo ser; // create servo object to control a servo
int poser = 0; // initial position of server
int val; // initial value of input
void setup() {
Serial.begin(9600); // Serial comm begin at 9600bps
ser.attach(9);// server is connected at pin 9
}
void loop() {
if (Serial.available()) { // if serial value is available
val = Serial.read();// then read the serial value
if (val == 'd') { //if value input is equals to d
poser += 1; //than position of servo motor increases by 1 ( anticlockwise)
ser.write(poser);// the servo will move according to position
delay(15);//delay for the servo to get to the position
}
if (val == 'a') { //if value input is equals to a
poser -= 1; //than position of servo motor decreases by 1 (clockwise)
ser.write(poser);// the servo will move according to position
delay(15);//delay for the servo to get to the position
}
}
}
There isn't anything very obvious wrong with the code, as long as you press d more than a so poser stays in range.
to test your hardware, run one of the examples such as sweep.
you should put in limits for poser so it stays between 0 and 180
try also lighting a led when 'a' or 'd' is received so you know that is working
Related
I am using a zumo bot with a reflectance sensor used to follow a black line. I want to use an arduino to make the zumo bot stop once it gets a certain distance from an obstacle.
I have an ultrasonic sensor (HC-SR04) which ive connected to the bot.
Both of these tasks work independently but once i merge the code together(so it follows the line aswell as stoping when it detects an object using the ultrasonic sensor), it doesn't work properly.. (the zumo bot no longer follows the line)
I THINK it is to do with the pulsein() function blocking any other tasks but not sure.
My code is below. Can anyone help please?
#include <ZumoShield.h>
ZumoBuzzer buzzer;
ZumoReflectanceSensorArray reflectanceSensors;
ZumoMotors motors;
Pushbutton button(ZUMO_BUTTON);
int lastError = 0;
// This is the maximum speed the motors will be allowed to turn.
// (400 lets the motors go at top speed; decrease to impose a speed limit)
const int MAX_SPEED = 400;
#define echoPin A4
#define trigPin A5
// defines variables
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement
void setup()
{
reflectanceSensors.init();
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
// Initialize the reflectance sensors module
// Wait for the user button to be pressed and released
button.waitForButton();
// Turn on LED to indicate we are in calibration mode
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
// Wait 1 second and then begin automatic sensor calibration
// by rotating in place to sweep the sensors over the line
delay(1000);
int i;
for(i = 0; i < 80; i++)
{
if ((i > 10 && i <= 30) || (i > 50 && i <= 70))
motors.setSpeeds(-200, 200);
else
motors.setSpeeds(200, -200);
reflectanceSensors.calibrate();
// Since our counter runs to 80, the total delay will be
// 80*20 = 1600 ms.
delay(20);
}
motors.setSpeeds(0,0);
// Turn off LED to indicate we are through with calibration
digitalWrite(13, LOW);
// Wait for the user button to be pressed and released
button.waitForButton();
Serial.begin(9600); // // Serial Communication is starting with 9600 of baudrate speed
Serial.println("Ultrasonic Sensor HC-SR04 Test"); // print some text in Serial Monitor
Serial.println("with Arduino UNO R3");
}
void loop()
{
unsigned int sensors[6];
// Get the position of the line. Note that we *must* provide the "sensors"
// argument to readLine() here, even though we are not interested in the
// individual sensor readings
int position = reflectanceSensors.readLine(sensors);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin HIGH (ACTIVE) for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Our "error" is how far we are away from the center of the line, which
// corresponds to position 2500.
int error = position - 2500;
// Get motor speed difference using proportional and derivative PID terms
// (the integral term is generally not very useful for line following).
// Here we are using a proportional constant of 1/4 and a derivative
// constant of 6, which should work decently for many Zumo motor choices.
int speedDifference = error / 4 + 6 * (error - lastError);
lastError = error;
// Get individual motor speeds. The sign of speedDifference
// determines if the robot turns left or right.
int m1Speed = MAX_SPEED + speedDifference;
int m2Speed = MAX_SPEED - speedDifference;
if (m1Speed < 0)
m1Speed = 0;
if (m2Speed < 0)
m2Speed = 0;
if (m1Speed > MAX_SPEED)
m1Speed = MAX_SPEED;
if (m2Speed > MAX_SPEED)
m2Speed = MAX_SPEED;
motors.setSpeeds(m1Speed, m2Speed);
//if (distance <20){
// motors.setSpeeds(0,0);
// }
////////////////////////////////////////////
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
// Displays the distance on the Serial Monitor
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
} ```
Of course pulseIn is blocking function. Arduino project is open source, you can easily check source code
Here is C equivalent countPulseASM function which does measurement.
unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops)
{
unsigned long width = 0;
// wait for any previous pulse to end
while ((*port & bit) == stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to start
while ((*port & bit) != stateMask)
if (--maxloops == 0)
return 0;
// wait for the pulse to stop
while ((*port & bit) == stateMask) {
if (++width == maxloops)
return 0;
}
return width;
}
If you need measure pulse length in non blocking way, use hw counters.
My servo only starts to "change" (that is what the code tells me anyway) when it is set for 180 degrees.
I've tried searching the website as well as Google, but this seems to be something that has to do very specifically with writing to Servo in an advanced non-repeatable kind of way.
The code that changes the servo is:
#include <SoftwareSerial.h>
#include <Servo.h>
const int rxPin = 12;
const int txPin = 13;
SoftwareSerial bluetooth (rxPin, txPin);
Servo myServo;
boolean canMove = true;
int rotation = 0;
int currentRotation = 0;
void setup() {
Serial.begin(9600); // Begins Serial communication
bluetooth.begin(9600);
myServo.attach(11); // Sets a servo on pin 11
}
void loop() {
// put your main code here, to run repeatedly:
// Checks if Serial has something to read
if (bluetooth.available() > 0) {
rotation = bluetooth.read(); // Reads it and sets it to an integer
}
currentRotation = myServo.read();
if (currentRotation != rotation) {
Serial.println("Current Rotation:");
Serial.println(currentRotation);
Serial.println("Set to:");
Serial.println(rotation);
for (int i = currentRotation; i < rotation; i++) {
Serial.println("Writing to servo");
myServo.write(i);
}
}
}
There is a Processing program that sends the data to the Arduino, but I can perfectly see that the numbers are coming in in the Arduino's Serial Monitor (they vary from 0 to 180)
After doing this the only thing that shows up in the Serial Monitor is:
Current Rotation:
93
Set to:
0
Current Rotation:
93
Set to:
0
Current Rotation:
93
Set to:
0
Current Rotation:
93
Set to:
0
Current Rotation:
93
Set to:
0
over and over. The servo just twitches back and forth. The only time it changes (the number to set to comes from the Processing program) is when the number it is set to be 180. Then it moves even more back and forth and says:
Current Rotation:
179
Set to:
180
Writing to servo
Current Rotation:
179
Set to:
180
Writing to servo
over and over. What is going on and how can I fix it? Cheers, and thanks for the help!
There are some problems with your code:
You don't need to read current servo value, just save the last gave value.
Moving a servo step by step is not a good option as it may have some error for movement. You need to find a dynamic delay based on a threshold of movement. For example, suppose that your max delay time for the servo to fully move from 0 to 180 is 2 seconds, so if you need to move the servo for 90 degrees you need 1 second delay.
You just need to move your servo when a new data came so set servo when new data comes.
Remember to set max_delay based on your servo.
#include <SoftwareSerial.h>
#include <Servo.h>
const int rxPin = 12;
const int txPin = 13;
SoftwareSerial bluetooth(rxPin, txPin);
Servo myServo;
boolean canMove = true;
int rotation = 0;
int currentRotation = 0;
// how much time takes servo to move
int move_delay = 0;
// maximum time for changing servo state from lowest to highest value
const int max_delay = 2;
void setup()
{
Serial.begin(9600); // Begins Serial communication
bluetooth.begin(9600);
myServo.attach(11); // Sets a servo on pin 11
}
void loop()
{
// put your main code here, to run repeatedly:
// Checks if Serial has something to read
if (bluetooth.available() > 0)
{
rotation = bluetooth.read(); // Reads it and sets it to an integer
Serial.print("New value: ");
Serial.println(rotation);
Serial.print("Current Rotation: ");
Serial.println(rotation);
if (currentRotation != rotation)
{
Serial.println("Setting new value");
// find a proper delay
move_delay = (max_delay / 180) * (abs(rotation - currentRotation)) * 1000;
myServo.write(rotation);
delay(move_delay);
currentRotation = rotation;
}
}
}
I've coded with Python before however, I am in the process of learning C and from what I have been told Arduino is quite similar to C in some aspects (at least with coding). I noticed that my when I run the code on my robot it jolts due to the quick changes in PWM. So I'd like some guidance as to how to do an if statement on Arduino because I am trying to increase/decrease the PWM in increments.
//On Roboclaw set switch 1 and 6 on. // <-- what does this refer to?
//mode 2 option 4 // <-- my note based on user manual pg 26
#include <Servo.h>
Servo myservo1; // create servo object to control a Roboclaw channel
Servo myservo2; // create servo object to control a Roboclaw channel
//int pos = 0; // variable to store the servo position //<-- left-over from arduino ide servo sweep example?
void setup()
{
myservo1.attach(9); // attaches the RC signal on pin 5 to the servo object (Left Motor)
myservo2.attach(11); // attaches the RC signal on pin 6 to the servo object (Right Motor)
}
void loop()
{
//forward
myservo1.writeMicroseconds(1000);
myservo2.writeMicroseconds(1000);
delay(2000);
//backward
myservo1.writeMicroseconds(2000);
myservo2.writeMicroseconds(2000);
delay(2000);
//left
myservo1.writeMicroseconds(1500);
myservo2.writeMicroseconds(1000);
delay(2000);
//right
myservo1.writeMicroseconds(1000);
myservo2.writeMicroseconds(1500);
delay(2000);
}
Ok, whenever you write a different value to the servo it will move to that position as fast as possible. So you will need to move your servo step by step.
For this task, however, you will not be able to use delays, since they block the processor. You will need to mimic the "blink with no delay" example (i.e. using the millis() function to do something when time passes by.
The acceleration control simply moves 1° every X milliseconds (in this case 6ms, which makes a full movement - 180° - last for about one second). Every X milliseconds, so, the uC moves 1° in the direction of a target position. In the other code you should just set the target to your desired position and you are done.
Here is the code I wrote. Let me know if it works for you
#include <Servo.h>
Servo myservo1;
Servo myservo2;
unsigned long prevMillisAccel = 0, prevMillisAction = 0;
uint8_t servo1_target;
uint8_t servo2_target;
uint8_t currAction;
#define TIME_FOR_ONE_DEGREE_MS 6
void setup()
{
myservo1.attach(9)
myservo2.attach(11);
prevMillisAccel = millis();
prevMillisAction = millis();
servo1_target = 0;
servo2_target = 0;
myservo1.write(0);
myservo2.write(0);
currAction = 0;
}
void moveServoTowardsTarget(Servo *servo, uint8_t target)
{
uint8_t pos = servo->read();
if (pos > target)
servo->write(pos-1);
else if (pos < target)
servo->write(pos+1);
}
void loop()
{
unsigned long currMillis = millis();
if (currMillis - prevMillisAccel >= TIME_FOR_ONE_DEGREE_MS)
{
prevMillisAccel += TIME_FOR_ONE_DEGREE_MS;
moveServoTowardsTarget(&myservo1, servo1_target);
moveServoTowardsTarget(&myservo2, servo2_target);
}
if (currMillis - prevMillisAction >= 2000)
{
prevMillisAction += 2000;
currAction = (currAction + 1) % 4;
switch(currAction)
{
case 0: // forward
servo1_target = 0;
servo2_target = 0;
break;
case 1: // backward
servo1_target = 180;
servo2_target = 180;
break;
case 2: // left
servo1_target = 90;
servo2_target = 0;
break;
case 3: // right
servo1_target = 0;
servo2_target = 90;
break;
}
}
}
PS. I used the write function instead of the writeMicroseconds because you can read the value you wrote. If you really need to use writeMicroseconds (which is pretty useless in my opinion, since servo precision is less than 1°, so write is more than sufficient) just store the target as a uint16_t and store also the last set value (and use that instead of the read function)
I have some code controling an old analoge servo and all is working fine.
But when I got a new digital servo, it will not hold position, but return to 0.
Please help, what is needed?
Here is the basic code basen on Sweep:
#include <Servo.h>
Servo myservo;
int pos = 0;
void setup()
{
myservo.attach(A1);
}
void loop()
{
for(pos = 0; pos <= 180; pos++) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}
Right after your for loop put:
while(1);
Before the closing bracket of the loop()
This will stop the program at that point and not keep running your for loop which declares pos = 0 each time.
I see that this question was a bit unpresice.
But I found out that there are one other way of controling a servo, and that is by using writeMicroseconds instead of myservo.write(90).
myservo.writeMicroseconds(1500); //
http://arduino.cc/en/Reference/ServoWriteMicroseconds
I am new to Arduino and trying to just create a simple application so a servo goes forward 50 degrees when a button is pushed(not continuous) and when let go of it will go back 50 degrees. For some reason my servo just keeps running. What should I do to debug this.
#include <Servo.h>
Servo myservo; // creating myservo object
int buttonPin = 2;
int servoPin = 3;
int buttonState = 0; // set buttonState
void setup()
{
myservo.attach(servoPin);
pinMode(buttonPin, INPUT);
}
void loop()
{ buttonState = digitalRead(buttonPin); // read and save to the variable "buttonState" the actual state of button
if (buttonState == HIGH)
myservo.write(50); else
myservo.write(0);
}
You should use the Bounce library library to catch the edge's you are looking for. Your script as written is continuously updating the PWM with 50 or 0. It is never getting a chance to actually do it. Hence you only want to update it on a change; either depress or release.
I have not tested the below. It does compile and is a simple hack from the examples and your above.
#include <Servo.h>
#include <Bounce.h>
#define BUTTON 2
#define servoPin 3
#define LED 13
Servo myservo; // create servo object to control a servo
Bounce bouncer = Bounce( BUTTON, 5 );
void setup() {
pinMode(BUTTON,INPUT);
pinMode(LED,OUTPUT);
digitalWrite(LED, HIGH);
myservo.attach(servoPin);
}
void loop() {
if ( bouncer.update() ) {
if ( bouncer.fallingEdge()) {
myservo.write(50);
digitalWrite(LED, LOW);
} else if ( bouncer.risingEdge()) {
myservo.write(0);
digitalWrite(LED, HIGH);
}
}
// foo bar...
}
I am going to take a wild guess that you have a continuous rotation servo. These servos have the position feedback from the potentiometer removed/disconnected so when you apply any rotation to the servo it will continuously spin thinking that it is not yet at the desired position. These servos have three control positions: off (likely 90 degrees) clockwise (anything larger than 90) and counterclockwise (anything less than 90). Some do allow you to control speed as well (I think the VEX one you cite having may be one - look up the spec sheet).
I might have my no movement value wrong (it may not be 90) and my counter/clockwise reversed, but I am almost certain this is your issue. Basically your motor is not what you think it is :)
myServo.writeMicroseconds(1500);
This will make it stop if its not broken and its a continuous digital servo.