Pages: [1]   Go Down
Author Topic: Arduino servo and dc controlling.  (Read 2326 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
I would like to ask if there is a reason why by using Servo.h the analogWrite command for the motor PWM control is not working. To be more specific i need to control a servo position and a DC motor's speed and direction. This program will be applied to a boat. The program is receiving values from the serial port and then translating them to integer values. For servo 0-180 and motor from 100-255 (it requires a lot of A). Now for some reason the program when receives command for the motor at first it starts ok. But after servo is initialized the motor stops working. The pins that are used are servo pin 3, motor direction1 pin 11, motor direction2 pin 8, motor speed pin 9. Arduino 0017 is used. Does anyone knows why this happens?
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17259
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Does anyone knows why this happens?

I don't think anyone could have a clue unless you first post your code. Use the # button to embed your program and see if anyone here can help you.

Lefty
« Last Edit: February 04, 2010, 08:51:15 am by retrolefty » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the answer. Here is the code. Still needs some cleanup and commenting.
Code:
#include <Servo.h>

int speedPinA= 9 ;
int dir1PinA = 11;
int dir2PinA = 8;
Servo rudder;



int speed=255;
char sp;//This is the speed variable  for the motors
char selection; //This is the received command
unsigned int dir=0;
unsigned int angle=0;
char pos[3]={NULL};

void setup()
{
  Serial.begin(9600); //setup the serial port to 9600bps
  
  //seting the pins options
  pinMode(dir1PinA, OUTPUT);
  pinMode(dir2PinA, OUTPUT);
  pinMode(speedPinA,OUTPUT);
  rudder.attach(3);
  


 //
 }
void loop()
{
  for (int i=0;i<3;i++){
    pos[i]=NULL;
  }
  
  if (Serial.available()>0){ //check if something was received
  
          selection=Serial.read(); //store it to inbyte
          
          switch (selection){
          case 's':{
          
                    if (Serial.available()>0)  {                
                    pos[0]=Serial.read();}
                    Serial.write("first");
                     if (Serial.available()>0)  {
                    pos[1]=Serial.read();}
                     Serial.write("second");
                     if (Serial.available()>0)  {
                    pos[2]=Serial.read();
                   Serial.write("third");}
                    
                     Serial.write("Servo");
                  if (pos[1]==NULL && pos[2]==NULL){
                     Serial.write("-1 digit:");
                    angle=atoi(&pos[0]);}
                    
                   else if (pos[2]==NULL){
                       Serial.write("-2 digits:");
                        angle=atoi(&pos[0])*10+atoi(&pos[1]);}
                      
                   else if (pos[0]!=NULL && pos[1]!=NULL && pos[2]!=NULL) {
                  
                        angle=atoi(&pos[0])*100+ atoi(&pos[1])*10 +atoi(&pos[2]);
                             Serial.write("-3 digits:");}
                            
                      Serial.print(angle,DEC);
                    ruddermove(angle);
                    break;
                    }
          case 'm':{
            Serial.write("Motor");
                                
                    dir=Serial.read();
                    Serial.write(dir);
                  
                    speed=Serial.read();
                    
                   Serial.write(speed);
                   analogWrite(speedPinA,speed);
                    motor(dir);
                    
                    
               }
          
 
  Serial.flush();
              
}
          }}


void motor(int dir){

    switch (dir){
    case 49:{
    
             digitalWrite(dir1PinA, LOW);
             digitalWrite(dir2PinA, HIGH);

             Serial.write("right");
             break;}
    case 50:{//if the received command is 2 in ASCII code start spinning
            digitalWrite(dir1PinA, HIGH);
            digitalWrite(dir2PinA, LOW);
            Serial.write("left");
            break;}
  
    case 48:{//if the received command is 0 in ASCII code stop
            digitalWrite(dir1PinA,LOW);
            digitalWrite(dir2PinA, LOW);
            Serial.write("stop");
            }
      }
  
}
void ruddermove(unsigned int angle){

  rudder.write(angle);
  
}

Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Which version of the IDE are you using? There have been some changes to the servo library for various versions of the IDE.

Why are you flushing the serial buffer?

In the motor function, there are cases for 48, 49, 50. Strange numbers for the cases. What do they mean? '0', '1', and '2' would make a lot more sense. Even better, though, would have been to subtract '0' from all the values before calling the motor function, passing it 0, 1, or 2.

Better than that, though, would be to add these to the top of the code
Code:
#define STOP 0
#define RIGHT 1
#define LEFT 2
and use these in the case statements.

Whatever you do, make the comments match the code. Much easier to debug when the code matches the comments.

In loop, you check that there is serial data available each time before read. That's good. But, suppose there is a slowdown in serial communication. You check that there is a byte for selection. There is, so you read it. Then, you check for a byte for pos[0]. There is, so you read it. Then, you check for a byte for pos[1]. Suppose there isn't. You skip reading a value for pos[1], which stays NULL. The byte has arrived by now, so you read it into pos[2].

What was supposed to be something like s72 has become 's', '7', NULL, '2'.

You then take action based in 's', '7'.

Whatever is sending data should send something like '<', 's', '7', '2', '>'. Now the string has a defined start and stop value, and you can read the data in a (much shorter) while loop, storing the characters between the '<' and the '>' in adjacent positions in an array. Knowing that the first character is a character, and that subsequent characters are digits also allows you to ignore invalid data.

Garbled transmissions, like '<', 's', '7', '&', '<', 's', '8', '4', '>' can be handled correctly.
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 11
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The Servo library disables PWM use on pins 9 and 10: http://arduino.cc/en/Reference/Servo
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for your answers. You have pointed to me some stuff that it would take me hours to solve. I have now finally solved the problem with the servo angle of movement. Now as for the problem with the motor i don't know what should i do, since i am using a motor controller shield not configurable about the speed pins. The are pre-configured to 9 and 10 from the factory. This is my code commented and clean.
Code:
#include <Servo.h>

#define Forward 50
#define Reverse 49
#define mstop  48

//----------------
int speedPinA= 9 ;
int dir1PinA = 11;
int dir2PinA = 8;

unsigned int dir=0;
unsigned int angle=0;

//---------------
Servo rudder;

char selection; //This is the received command
char pos[3]={NULL}; //This is the received angle string

//--------------------------------------------------------
void setup()
{
  Serial.begin(9600); //setup the serial port to 9600bps
  
  //seting the pins options
  pinMode(dir1PinA, OUTPUT);
  pinMode(dir2PinA, OUTPUT);
  pinMode(speedPinA,OUTPUT);
  
  rudder.attach(3);
  


 //
 }
void loop()
{
  
  
  for (int i=0;i<3;i++){
    pos[i]=NULL; //Initialize values to 0
  }
  
if (Serial.available()>=0){
  
          selection=Serial.read(); //store it to inbyte
          
          switch (selection){
          case 's':{ //servo is selected
          
                    waitmsg();         //wait for value
                    pos[0]=Serial.read(); //store the first digit to the 1st char of the string
                  
                   waitmsg();//wait for value
                    pos[1]=Serial.read();//store the first digit to the 2nd char of the string
                  
                    waitmsg();//wait for value
                    pos[2]=Serial.read(); //store the first digit to the 3rd char of the string
              
                    angle=conv(pos[0])*100+ conv(pos[1])*10 +conv(pos[2]); //convert the number to integer decimal. each digit represents the hundrends, tenths and units respectively
                      
                     rudder.write(angle); //move the rudder
                    break; //exit the switch statement
                    }
                    
          case 'm':{  
                    waitmsg();        //wait for value
                    dir=Serial.read();//read the direction
                  
                    digitalWrite(speedPinA,HIGH); //set the motor pin to high
                    motor(dir); //write the direction of the motor
                    
               }
            
          }
         }
        }

//-------------------------------FUNCTION DECLARATION POINT-------------------------------------------------------------

/*this procedure reads the direction of the motor and according to the received value
(0=Stop, 1=Reverse,2=Forward) the motor moves*/
void motor(int dir){

    switch (dir){
    case Reverse:{//Start motor spinning
    
             digitalWrite(dir1PinA, LOW);
             digitalWrite(dir2PinA, HIGH);
             break;}
                          
    case Forward:{//Start motor spinning
            digitalWrite(dir1PinA, HIGH);
            digitalWrite(dir2PinA, LOW);
             break;}
  
    case mstop:{//Stop motor spinning
            digitalWrite(dir1PinA,LOW);
            digitalWrite(dir2PinA, LOW);
            }
      }
  
}
//-----------------------------------------------------------------------------------------------------------------------

//this function converts ascii characters to integer values
int conv(char num){
    
  if (num>=48 && num<=57){ //check if the char is in the corresponding values between 48 and 57 (0-9)

    return ( num-'0'); //return the integer value from char-48
  }
  else{ //this is not a valid char number
    return 0;
  }
}


//--------------------------------------------------------------------------------------------------------------------------
//this is a loop in order to wait from the serial port a value to be read. If the value is received the it exits the loop
void waitmsg(){
  while(Serial.available()<=0){}    
}
Everything is working fine but the speed controlling of the motor is missing. The motor is just start spinning at maximum speed. In order to add motor speed control functionality i just need to read the speed variable from the serial and to analogwrite the motor speed pin. I just dont know yet how to enable those pins.... Does anyone have any idea?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What motor controller shield are you using?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

i am using this: http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&item=160374483318&ssPageName=ADME:X:AAQ:US:1123 ( not trying to sell anything. i just need help)
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
digitalWrite(speedPinA,HIGH); //set the motor pin to high

That sets the speed. HIGH jams the throttle to the floor.

Code:
digitalWrite(speedPinA, 75); //set the motor speed to 75/255 of full throttle

Easy on the throttle...

Write whatever value you like, from 0 to 255. There are practical limits to the speed control. You may not get any motion until you get above some value, and you are unlikely to detect a difference between say 189 and 190.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

PaulS by Digitalwrite the output can be either HIGH or LOW not some value from 0-255. Values are only used in analogwrite (for PWM) which right now is disabled by the Servo.h library. My question is there a way to remove the pin 9-10 disabling from the library, or even other similar library that doesn't have this cons?
Logged

London
Offline Offline
Faraday Member
**
Karma: 10
Posts: 6248
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
My question is there a way to remove the pin 9-10 disabling from the library, or even other similar library that doesn't have this cons?

analogWrite is implemented in Arduino using Timers to generate the PWM signal. The pins associated with a timer is fixed into the design of the Arduino chip and can't be changed.  The Arduino Servo library uses the 16 bit timer which is fixed to pins 9 and 10, so using the Servo code prevents these pins from being available to analog write.

There are a couple of workarounds.

You can use a software servo library that does not use a timer but does require that your sketch call a refresh function at least once every 50ms (ideally 20ms)
See: http://www.arduino.cc/playground/ComponentLib/Servo

If calling the explicit refresh is inconvenient, I posted a library here that uses timer2 (pins 3 and 11 are disabled). This Servo library distributed with Arduino is more capable and efficient than  ServoTimer2 but  this library will free up pins 9 and 10.

The thread is here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230479947
You can download the library from here: http://www.arduino.cc/playground/uploads/Main/ServoTimer2.zip.
Logged

Pages: [1]   Go Up
Jump to: