Go Down

Topic: RC controlled Stepper Motors (Read 786 times) previous topic - next topic

LightningAC

I am trying to build a robot that uses 2 stepper motors (4-wires) with a l298n motor driver each and powered by an arduino mega 2560. I am using a FlySky FS-T4B RC Transmitter (4 channels) with a FS-R6B Receiver. My goal is to have the steppers spin continuous rotations with the RC Transmitter changing the speed of the motors. I am using the AccelStepper library to adjust the speed of the motors.

The Problem:
Every time a new signal comes in (which is constantly), the motors try to adjust, but just stutter step through the continuous rotations. This occurs with the pulseIn function. I know I should use interrupts, but I am more of a builder than a programmer, and I can't seem to incorporate interrupts with the stepper motor program. Could someone try to help me with this?

Pinout:
RC Receiver:
Channel 1 (Right Stick Horizontal) -> Mega Digital pin 53 (1010 - 1890) (Low and High values of each stick with the centered position at 1500)
Channel 2 (Right Stick Vertical) -> Mega Digital pin 52 (1080 - 1930)
Channel 3 (Left Stick Vertical) -> Mega Digital pin 51 (1140 - 1830)
Channel 4 (Left Stick Horizontal) -> Mega Digital pin 50 (1050 - 1940)

Stepper1 -> (2,3,4,5)
Stepper2 -> (10,11,12,13)

You probably won't need my program because I am basing this off of the MultiStepper example of the AccelStepper library with the modified pinouts.

Thank you for anyone who might be able to help me with this project.

vinceherman

#1
Apr 02, 2018, 02:49 pm Last Edit: Apr 02, 2018, 02:49 pm by vinceherman
Could someone try to help me with this?
Yes.  This entire board is full of people who enjoy doing just that.
Quote
You probably won't need my program because I am basing this off of the MultiStepper example of the AccelStepper library with the modified pinouts.
No.  We do need to see your code.  Even if I knew which example you modified, I would need your modifications.

Post your code.  Use code tags.  And you are right, this is likely a timing issue.  I do not like pulsein for RC receiver decoding.

jremington

As you are discovering, stepper motors are a very poor choice for robot locomotion. They waste power and are very difficult to control with RC.

For the wheels, continuous rotation servos would be a much better choice.

LightningAC

#3
Apr 02, 2018, 09:58 pm Last Edit: Apr 02, 2018, 10:05 pm by LightningAC
Thank you for your responses.

As you are discovering, stepper motors are a very poor choice for robot locomotion. They waste power and are very difficult to control with RC.

For the wheels, continuous rotation servos would be a much better choice.
Regarding this, I will say I am building a BB8 robot which would eventually need to be self-balancing and I found many successful examples of self-balancing robots using stepper motors. Additionally, the motors need to have a lot of torque in order to spin the ball as it has to spin a large support beam (diameter of like 11in which is basically the wheel in this case), which I believe stepper motors might have the advantage there (feel free to correct me if I am wrong, however, I have gone with stepper motors so there is nothing else that can be changed here). Stepper motors also are more precise for my needs.


Quote
No.  We do need to see your code.  Even if I knew which example you modified, I would need your modifications.

Post your code.  Use code tags.  And you are right, this is likely a timing issue.  I do not like pulsein for RC receiver decoding.
Here is my code:
Code: [Select]

#include <AccelStepper.h>
#include <MultiStepper.h>

AccelStepper stepper1; // Defaults to Accelstepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
AccelStepper stepper2(AccelStepper::FULL4WIRE, 10, 11, 12, 13);


#define rcPin1 6   // Pin 8 Connected to CH1 of Transmitter;
#define rcPin2 7   // Pin 9 Connected to CH2
#define rcPin3 8   
#define rcPin4 9


int ch1 = 0;  // Receiver Channel 1 PPM value
int ch2 = 0;  // Receiver Channel 2 PPM value
int ch3 = 0;
int ch4 = 0;

int motorSpeed = 0;

void setup()

    stepper1.setMaxSpeed(500.0);
    stepper2.setMaxSpeed(500.0);
    stepper1.setSpeed(motorSpeed);
    stepper2.setSpeed(motorSpeed);   
  pinMode(rcPin1, INPUT); // 4 channels are listed here, but only channel 3 is being used for now
  pinMode(rcPin2, INPUT);
  pinMode(rcPin3, INPUT);
  pinMode(rcPin4, INPUT);

  Serial.begin(9600);
}

void loop()
{
  ch1 = pulseIn(rcPin1, HIGH, 20000);  // (Pin, State, Timeout), Right Stick Horizontal
  ch2 = pulseIn(rcPin2, HIGH, 20000);  // Right Stick Vertical
  ch3 = pulseIn(rcPin3, HIGH, 20000);  // Left Stick Vertical
  ch4 = pulseIn(rcPin4, HIGH, 20000);  // Left Stick Horizontal
  Serial.println(ch3);
   
      motorSpeed = map(ch3, 1080, 2000, 0, 500); //maps the receiver values to a range for the stepper motors
      stepper1.setSpeed(motorSpeed);
      stepper2.setSpeed(motorSpeed);
      Serial.print("Stick Up, Speed: ");
      Serial.println(motorSpeed);
      stepper1.runSpeed(); //continuous rotations to run the mapped speed
      stepper2.runSpeed();
      delay(100);
     
  }



vinceherman

Code: [Select]
delay(100);
I am pretty sure that this is not desirable in the loop of a self balancing robot.
I am also pretty sure that you want to change over your pulsein to interrupts.
What have you tried with that?  Leave your steppers out of it.  Just read the receiver channels and display the results to the serial monitor.
Some light reading.
http://playground.arduino.cc/Code/ReadReceiver
http://rcarduino.blogspot.com/2012/01/how-to-read-rc-receiver-with.html
http://rcarduino.blogspot.co.uk/2012/04/how-to-read-multiple-rc-channels-draft.html





LightningAC

Thank you for these resources, I will do some reading through these as soon as I get the chance to.

TomGeorge

Regarding this, I will say I am building a BB8 robot which would eventually need to be self-balancing and I found many successful examples of self-balancing robots using stepper motors.
Hi,
I think you will find BB8 is self balancing, but does not need any software to do it.
It uses the fact that most of its frame mass, and so its center of gravity, is below the center of its sphere volume.
Its motors support the frame inside the sphere.
It moves by trying to drive the frame up the inside of the sphere,  by driving two motors positioned 90deg to each other.
So no self balancing software is needed.
Even with power turned OFF he cannot  fall over, he is a sphere, his "head" will always be upper most, due to magnetic attraction between his "head" and a pole above the frame inside its body being near the sphere upper surface.
A beautiful concept, beautifully executed.
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
Tom... :)
Everything runs on smoke, let the smoke out, it stops running....

LightningAC

#7
Apr 08, 2018, 05:05 pm Last Edit: Apr 08, 2018, 05:53 pm by LightningAC
Update: So I found this video by SparkFun detailing how to use an RC transmitter to control a robot. They used a transmitter very similar to mine and the exact same receiver. Code below.https://www.youtube.com/watch?v=u0Ft8SB3pkw&t=93s
It works in the sense that the motors move forward and backwards, the only problem with this is that I can't seem to change the speed of my motors.

Another thing is one stepper motor all of a sudden just stopped moving. I did not change anything and this just randomly happened. It sort of vibrates or does one step forward then back constantly and I can't seem to figure out the problem with that. I tried using the working driver, it still does the same thing. I tried a program where I know it works, and it still does the vibrating thing. I have concluded that the problem has to be within the motor it self, is there any way to fix it? or must I just purchase another one?

Anyways, I will not continue any progression until summer when I am out of school. I'm gonna need some time off to focus on schoolwork and not frustrate myself through trying to work on this. But feel free to provide help whenever as it is always appreciated.

Code: [Select]

#include <AccelStepper.h>;



// Controller pins
const int CH_2_PIN = 52;

// Motor driver pins
AccelStepper stepper1;
AccelStepper stepper2(AccelStepper::FULL4WIRE, 10, 11, 12, 13);


// Parameters
const int deadzone = 20;  // Anything between -20 and 20 is stop


void setup() {

    stepper1.setMaxSpeed(500.0);
    stepper2.setMaxSpeed(500.0);
 
    Serial.begin(9600);
}

void loop() {

  // Read pulse width from receiver
  int ch_2 = pulseIn(CH_2_PIN, HIGH, 25000);

  // Convert to PWM value (-255 to 255)
  ch_2 = pulseToPWM(ch_2);

  // Drive motor
  drive(ch_2, ch_2);
      // Set speed
    stepper1.setSpeed(ch_2);
    stepper2.setSpeed(ch_2);
  stepper1.runSpeed();
  stepper2.runSpeed();
  Serial.println(ch_2);
  delay(5);
}

// Positive for forward, negative for reverse
void drive(int speed_a, int speed_b) {

  // Limit speed between -255 and 255
  speed_a = constrain(speed_a, -500, 500);
  speed_b = constrain(speed_b, -500, 500);



}

// Convert RC pulse value to motor PWM value
int pulseToPWM(int pulse) {
 
  // If we're receiving numbers, convert them to motor PWM
  if ( pulse > 1000 ) {
    pulse = map(pulse, 1200, 1800, -500, 500);

  } else {
    pulse = 0;
  }

  // Anything in deadzone should stop the motor
  if ( abs(pulse) <= deadzone ) {
    pulse = 0;
  }

  return pulse;
}

PaulS

Code: [Select]
// Positive for forward, negative for reverse
void drive(int speed_a, int speed_b) {

  // Limit speed between -255 and 255
  speed_a = constrain(speed_a, -500, 500);
  speed_b = constrain(speed_b, -500, 500);



}

You changed the values in the arguments that were passed by value. The caller has no idea that you did that, so you might as well not have done that.

Quote
// If we're receiving numbers, convert them to motor PWM
As opposed to elephants or grapefruit?

What the heck else would you be receiving?

Code: [Select]
  // Convert to PWM value (-255 to 255)
  ch_2 = pulseToPWM(ch_2);

That is NOT what that code does.

Before you try to use data that you do not KNOW is good, the FIRST thing to do is to make sure that it is good. Why are you not doing that?
The art of getting good answers lies in asking good questions.

LightningAC

#9
Apr 09, 2018, 02:13 pm Last Edit: Apr 09, 2018, 02:32 pm by LightningAC
All I did was take the code made by SparkFun and changed some things. To be honest, I wasn't quite sure what I was doing. But all of the comments were left there by SparkFun.

PaulS

All I did was take the code made by SparkFun and changed some things. To be honest, I wasn't quite sure what I was doing. But all of the comments were left there by SparkFun.
The code on the site linked to in the video looks quite different from your code.

For instance, the pulseToPWM() code on the linked site does constrain the PWM value to the range -255 to 255. Your code does not. Hence the comment in the Sparkfun code is correct. The comment in your code is wrong.

In the drive() function in the linked site's code, the constrained values are actually used. In your code, they are thrown away.
The art of getting good answers lies in asking good questions.

LightningAC

The reason I removed that was because I was trying to take the values to change the speed of the stepper motors (the max speed being 500). I am by no means good at coding, I just try to find parts that I might be able to change and try to learn that way.

Go Up