Trouble with DC motor direction change

So I’m using an absolute encoder and a motor from a cars windshield whipper to move back and forth in a 120 degree arc between 60 and 180. Now I’ve been able to get it to go one direction until it reaches a certain point then stop, and by changing pin 8 from HIGH to LOW or vise versa I can change direction, but whenever I try to make it so it changes direction at a certain point the motor either does nothing at all, or spings in the same direction continuously

changing direction is just changing pin 8 to HIGH or LOW, I’ve gotten it to go to a certain encoder location and stop, but any attempt to have it change direction and it, well see above complaint.

/* FullCode is broken into 5 sections for easier trubbleshooting. 
 *  Section 1 is for the Setup, program variables, definitions, library callouts, etc. 
 *  Section 2 is for the absolute encoder
 *  Section 3 is for the whipper motor 
 *  Section 4 is for the stepper motor
 */


//Section 1

#include <SPI.h>
 
#define CS 3 //Chip or Slave select 
 
uint16_t ABSposition = 0;
uint16_t ABSposition_last = 0;
uint8_t temp[2];    //This one.
 
float deg = 0.00;
float tempDeg;
char x;
int count = 10;
float stop1 = 120.0;
float stop2 = 0.0;
short dir = 1;
char tempCar;

//For Section 4
  #include <Tic.h>

  TicI2C tic;


void setup() {
 

  
  // Setup part for Section 2
  pinMode(CS,OUTPUT);//Slave Select
  digitalWrite(CS,HIGH);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  Serial.begin(115200);
  Serial.println("starting");
  Serial.flush();
  delay(2000);
  SPI.end();
  //------------

  // Setup part for Section 3  
  pinMode(8, OUTPUT); //set direction pin as output, dir
  pinMode(11, OUTPUT); //set enable pin as output, pwm  


  // Setup part for Section 4
  //Note, the setup for section 4 contained a lot of comments that I removed to save space
  //refer to original program for extra troubleshooting help

  Wire.begin();

  // Give the Tic some time to start up.
  delay(20);

  tic.exitSafeStart();

  //  This next part centers the whipper motor


  //This next part is just to stop the program from starting before you want it to. 
   loop();
}

void resetCommandTimeout()
{
  tic.resetCommandTimeout();
}

void delayWhileResettingCommandTimeout(uint32_t ms)
{
  uint32_t start = millis();
  do
  {
    resetCommandTimeout();
  } while ((uint32_t)(millis() - start) <= ms);
}



void loop() {
  



driveDC();

  
}

// Sections 2: encoder 


  uint8_t SPI_T (uint8_t msg)    //Repetive SPI transmit sequence
{
   uint8_t msg_temp = 0;  //vairable to hold recieved data
   digitalWrite(CS,LOW);     //select spi device
   msg_temp = SPI.transfer(msg);    //send and recieve
   digitalWrite(CS,HIGH);    //deselect spi device
   return(msg_temp);      //return recieved byte
}
 
  float AbsEncoder(){
   uint8_t recieved = 0xA5;    //just a temp vairable
   ABSposition = 0;    //reset position vairable
   
   SPI.begin();    //start transmition
   digitalWrite(CS,LOW);
   
   SPI_T(0x10);   //issue read command
   
   recieved = SPI_T(0x00);    //issue NOP to check if encoder is ready to send
   
   while (recieved != 0x10)    //loop while encoder is not ready to send
   {
     recieved = SPI_T(0x00);    //cleck again if encoder is still working 
     delay(2);    //wait a bit
   }
   
   temp[0] = SPI_T(0x00);    //Recieve MSB
   temp[1] = SPI_T(0x00);    // recieve LSB
   
   digitalWrite(CS,HIGH);  //just to make sure   
   SPI.end();    //end transmition
   
   temp[0] &=~ 0xF0;    //mask out the first 4 bits
    
   ABSposition = temp[0] << 8;    //shift MSB to correct ABSposition in ABSposition message
   ABSposition += temp[1];    // add LSB to ABSposition message to complete message
    
   if (ABSposition != ABSposition_last)    //if nothing has changed dont wast time sending position
   {
     ABSposition_last = ABSposition;    //set last position to current position
     deg = ABSposition;
     deg = deg * 0.08789;    // aprox 360/4096
     Serial.println(deg);     //send position in degrees
   }   
 
   delay(10);    //wait a bit till next check
  return(deg);
  }




// Section 3: Dc wiper motor

  void driveDC(){
      float deg = encoder_read();
      Serial.println(deg);
      if (encoder_read() > 120.0){
        digitalWrite(8,HIGH);
        analogWrite(11,30);
      }
      else{
        analogWrite(11,0);
      }
 
  }
  



//reading encoder
float encoder_read() {
//float deg;
uint16_t ABSposition = 0;
uint16_t ABSposition_last = 0;
uint8_t temp[2];    //This one.
 
uint8_t recieved = 0xA5;    //just a temp vairable
   ABSposition = 0;    //reset position vairable
   
   SPI.begin();    //start transmition
   digitalWrite(CS,LOW);
   
   SPI_T(0x10);   //issue read command
   
   recieved = SPI_T(0x00);    //issue NOP to check if encoder is ready to send
   
   while (recieved != 0x10)    //loop while encoder is not ready to send
   {
     recieved = SPI_T(0x00);    //cleck again if encoder is still working 
     delay(2);    //wait a bit
   }
   
   temp[0] = SPI_T(0x00);    //Recieve MSB
   temp[1] = SPI_T(0x00);    // recieve LSB
   
   digitalWrite(CS,HIGH);  //just to make sure   
   SPI.end();    //end transmition
   
   temp[0] &=~ 0xF0;    //mask out the first 4 bits
    
   ABSposition = temp[0] << 8;    //shift MSB to correct ABSposition in ABSposition message
   ABSposition += temp[1];    // add LSB to ABSposition message to complete message
    
   if (ABSposition != ABSposition_last)    //if nothing has changed dont wast time sending position
   {
     ABSposition_last = ABSposition;    //set last position to current position
     deg = ABSposition;
     deg = deg * 0.08789;// aprox 360/4096

    //forward_flick( stop1, deg); 
     
     Serial.println(deg);     //send position in degrees
   }   
 return(deg);
   delay(10);    //wait a bit till next check

}

What is a " windshield whipper"? Are you using a windshield wiper motor? I have one in my motor junk box and it is a normal 12 volt DC motor that runs one direction and when the polarity of the DC connection is reversed, it runs the other direction. It also is connected to gears and a crank to move the wiper arm back and forth. The motor does not stop immediately when power is removed.

What EXACTLY are you using in you project?

Paul

Paul_KD7HB:
What is a " windshield whipper"? Are you using a windshield wiper motor? I have one in my motor junk box and it is a normal 12 volt DC motor that runs one direction and when the polarity of the DC connection is reversed, it runs the other direction. It also is connected to gears and a crank to move the wiper arm back and forth. The motor does not stop immediately when power is removed.

Paul

Yes, I meant wiper, my spelling has always been bad, I apologize. (thank God for spell check). Anyway, we're working on an apparatus that will perform a fly fishing cast for people in wheelchairs. We basically have an inverted pendulum on a cart (if you don't know what that is, I recommend looking it up...its really cool). We have a track push and pull a frame holding the wiper motor, the wiper motor will swing the rod in a 120 degree arc back and forth while the stepper drives the track, moving the frame back and forth in time with the swings.

I'm not dealing with the stepper motor yet, that was more or less working last I fought with it, you may have seen some references to it in my code if I forgot to delete them but I'm ONLY working on the wiper motor at the moment. To what you said about changing the polarity, that is what pin 8 does, I don't have trouble reversing the direction, I just have trouble reversing direction consistently and when I want it to. We have blue masking tape on the shaft so we can easily see such things.

Have you actually printed out the values in your float variables. I am suspicious you are not getting the values you think you have. I am amazed to see the contortions you have to use float when all the sensor values are integers.

Paul

      if (encoder_read() > 120.0){
        digitalWrite(8,HIGH);
        analogWrite(11,30);
      }
      else{
        analogWrite(11,0);
      }

An issue:

When encoder_read() gets larger than 120, the direction is reversed. I have not found where the other end (0 ?) is handled.

A state variable is needed. This could be something as simple as a boolean variable that indicates whether the direction is 60 to 80 or 80 to 60, and the tests (if/else statements) have to be appropriate for the direction. I would be inclined to use an enum but this may be too challenging for a beginner.

I wonder what is on pin 11?

vaj4088:

      if (encoder_read() > 120.0){

digitalWrite(8,HIGH);
        analogWrite(11,30);
      }
      else{
        analogWrite(11,0);
      }




An issue:

When encoder_read() gets larger than 120, the direction is reversed. I have not found where the other end (0 ?) is handled.

A state variable is needed. This could be something as simple as a boolean variable that indicates whether the direction is 60 to 80 or 80 to 60, and the tests (if/else statements) have to be appropriate for the direction. I would be inclined to use an enum but this may be too challenging for a beginner.

I wonder what is on pin 11?

Hi, thanks. I sorta understood your explanation, as you said it might be a bit tough for a beginner. On pin 11, it controls the speed. I tested it at 20 in stead of 30, it just goes slower.

to answer your first question, it isn't. In the iteration of the program that I posted, for now I'm just trying to get it to consistently stop at 120 then change direction. I figure once I accomplish that, getting it to stop at 0 should just be a matter of altering what I have. My first attempts to get it to do it all at once didn't go anywhere so I broke the problem into smaller steps.

So like I said, I kind of understood what you said you think we need to do but, do you think you could expand on that? For now I might try just using int's since you pointed out we're using them where they aren't needed. That might solve some of our problems. I know technically it shouldn't but I have actually dealt with hardware that was actually that picky.

Paul_KD7HB:
Have you actually printed out the values in your float variables. I am suspicious you are not getting the values you think you have. I am amazed to see the contortions you have to use float when all the sensor values are integers.

Paul

The floats are because we are converting the values the encoder gives to degrees using the diameter of the
shaft. I suppose we could skip that part, but I think it would be extra work.

I was thinking along the lines of this untested pseudo-code:

boolean goingForward = true ; // Declare this with other global variables, ahead of and outside of
                              // setup() and loop().

.
.
.


//
// In the place where you check limits...
//
if (goingForward) {
  if (encoder_read() > 120.0) {
    goingForward = false ;
    <set direction reverse>
    <set appropriate reverse speed>
  }
}else {
  if (encoder_read() < 0.0) {
    goingForward = true ;
    <set direction forward>
    <set appropriate forward speed>
  }
}

There still remains the issue of starting this properly within setup(). You may not need to do anything, this code tends to be self-correcting.

vaj4088:
I was thinking along the lines of this untested pseudo-code:

boolean goingForward = true ; // Declare this with other global variables, ahead of and outside of

// setup() and loop().

.
.
.

//
// In the place where you check limits…
//
if (goingForward) {
  if (encoder_read() > 120.0) {
    goingForward = false ;
   
   
  }
}else {
  if (encoder_read() < 0.0) {
    goingForward = true ;
   
   
  }
}




There still remains the issue of starting this properly within setup(). You may not need to do anything, this code tends to be self-correcting.

I have considered that but have yet to try it, I’ll try it later. I’m wondering if the problem might be in the encoder code though. Well, I’ll try it and see what happens, thanks. In the mean time, please post again if you think of something.

Conceptually all you need is

  if (position < LIMIT1)
    direction = HIGH ;
  else if (position > LIMIT2)
    direction = LOW ;

assuming LIMIT2 > LIMIT1.
Then drive the various output pins appropriately. The sense of direction has to right for this to work of course.

Your original code forget to set the direction at one of the limits.

I'm using an absolute encoder

?

MarkT:
Conceptually all you need is

  if (position < LIMIT1)

direction = HIGH ;
  else if (position > LIMIT2)
    direction = LOW ;



assuming LIMIT2 > LIMIT1.
Then drive the various output pins appropriately. The sense of direction has to right for this to work of course.

Your original code forget to set the direction at one of the limits.

Thanks what has me stumped is that Ive pretty much tried exactly that. I don’t have it in the code I posted because at the moment I’m just trying to get it to got one direction than stop consistently. vaj4088 suggested I use boolean values to change direction in stead of 1 and -1 like I was trying to earlier. I’ll be trying that and a few other suggestions posted by you and a few other wonderful people tomorrow. I can only do so much with the code at home because the hardware is at the university and kinda needs to stay there, lol. Tomorrow I’ll have a few hours to mess with it so I’ll see if I can make what you guys gave me work.

An int should have worked. It is just that a boolean is easier to understand, and an enum is even easier.

Too bad that we did not get to see the original code, but breaking things down into smaller pieces should help. Of course, the smaller pieces are best if they are the BEST small pieces. I might have chosen an encoder piece and a motor piece but that is just me.

Thank you all for your help. It turns out the problem was the encoder. The encoder was freaking out when it hit zero no matter which direction it was coming from. That was why it refused to change direction mid code because the encoder would get confused as to which direction was which upon reaching 0.0. It would than either do nothing or continue doing in the direction it knew. We physically moved the 'zero' point for the encoder so that that the 120 degree arc we need is no where near 0. They then wrote a code that worked and was EXACTLY what I had originally............AAAAAARRRRGGGG........anyway, we know why it wasn't working now. Thank all of you for your help.