Controlling a Toy Crane

I'm currently trying to write some code to control a toy tower crane.

I'm using a SainSmart Nano 3.0 (currently testing on a Uno v3) for the controller, and an ADAFRUIT Motor control shield.

The Crane has 3 x 6v DC motors (thankfully 3 caps on each motor already) 1 motor to rotate the crane, another to move the hook trolly back and forth, and the third to raise and lower the hook.

I have a bit of code written so far. Most the set up, though it seems quite a lot, to me at least (this is my first project outside of the "Getting Started with Arduino" by Massimo Banzi book).

I am trying to use the analog pins as digitalRead pins, I think I have it worked out correctly, but i'm not sure.

I have the "first" control completed. Using the example for turning a LED on and off from the "Getting Started" book page 49, and modifying it for two different "states"

Hopefully Some one can review the code and let me know if it will work, if I did something wrong, and maybe ways to improve upon it.

/*
My Attempt at controlling a crane with Arduino
Using analog pins 0 - 5 as input
pin 0 will rotate the crane CCW
pin 1 will rotate the crane CW
pin 2 will move the trolly out
pin 3 will move the trolly in
pin 4 will raise the hook
pin 5 will lower the hook
Motor Control is accomplished with the ADAFRUIT
Motor Control Shield
Motor 1 will control rotation
Motor 2 will control the Trolly
Motor 3 will control the hook
*/

#include <AFMotor.h>

// Set up the motors - name and channel

AF_DCMotor rotate(1, MOTOR12_64KHZ); // create motor #1 named rotate, 64KHz pwm
AF_DCMotor trolly(2, MOTOR12_64KHZ); // create motor #2 named trolly, 64KHz pwm
AF_DCMotor hook(3, MOTOR12_1KHZ); // create motor #2 named hook, 1KHz pwm

// Constants defining buttons (not sure if this is or will be needed)

// Variables to help debounce the buttons
// but# is the read value
// bou# is the debounce variable
// mov# is the movement of the motor
// 0 = stopped (Released)
// 1 = move

int but0 = 0;
int bou0 = 0;
int mov0 = 0;
int but1 = 0;
int bou1 = 0;
int mov1 = 0;
int but2 = 0;
int bou2 = 0;
int mov2 = 0;
int but3 = 0;
int bou3 = 0;
int mov3 = 0;
int but4 = 0;
int bou4 = 0;
int mov4 = 0;
int but5 = 0;
int bou5 = 0;
int mov5 = 0;

void setup() {
Serial.begin(9600);
Serial.println("Crane test!");
rotate.setSpeed(255);
trolly.setSpeed(255); // Motor speed 0-255
hook.setSpeed(255);
}

void loop() {
// Read the button inputs
but0 = digitalRead(A0);
but1 = digitalRead(A1);
but2 = digitalRead(A2);
but3 = digitalRead(A3);
but4 = digitalRead(A4);
but5 = digitalRead(A5);

//Check if there was a transition on button 0 rotate CCW
if ((but0 == HIGH) && (bou0 == LOW) && (bou1 == LOW)) {
mov0 = 1 - mov0;
delay(10);
}
bou0 = but0;

//Check if there was a transition on button 1 rotate CW
if ((but1 == HIGH) && (bou1 == LOW) && (bou0 == LOW)) {
mov0 = 1 - mov0;
delay(10);
}
bou1 = but1;

if ((mov0 == 1) && (mov1 == 0)) {
rotate.run(FORWARD); // rotate the crane CCW
} if ((mov1 == 1) && (mov0 == 0)) {
rotate.run(BACKWARD); // rotate the crane CW
} else {
rotate.run(RELEASE); // Stop crane rotation
}

}

Thank You in advance

You should not use pin 0 and 1 as they are used in the serial communication and hanging hardware off them can interfere with debugging and uploading code to the Arduino.

 //Check if there was a transition on button 0 rotate CCW
  if ((but0 == HIGH) && (bou0 == LOW) && (bou1 == LOW)) {
    mov0 = 1 - mov0;
    delay(10);
  }
  bou0 = but0;

You don't need a separate debounce delay for every button. If you read all the buttons at the same time (as you do) a single delay will cover them all. And this does not need to be an explicit delay() if the code in loop() takes long enough to run through.

In fact if you use different buttons for UP and for DOWN you probably don't need either debounce or delay.

If you do need a delay I would put the button read business in a separate function and create a wait period using millis() (not the delay() function) at the top of it something like this (copied from my own small test program)

void readButton() {
	if (curMillis - prevBtnMillis < 70) {
		return;
	}
	else {
		prevBtnMillis += 70;
	}
	
	curBtnState = digitalRead(7);
	if (curBtnState == LOW && prevBtnState == HIGH) {
		buttonPressed = true;
	}
	prevBtnState = curBtnState;
}

This code waits at least 70 msecs between button reads but if the 70ms has already been used up elsewhere it won't need to wait at all. And it does not hold up anything else during the 70 msecs.

...R

Grumpy_Mike:
You should not use pin 0 and 1 as they are used in the serial communication and hanging hardware off them can interfere with debugging and uploading code to the Arduino.

I'm not using a single pin between d1-d13, considering all but 4 over there are used by the motor controller shield. I used A0 for the analog 0 pin, is this not correct?

Robin2:
You don't need a separate debounce delay for every button. If you read all the buttons at the same time (as you do) a single delay will cover them all. And this does not need to be an explicit delay() if the code in loop() takes long enough to run through.

In fact if you use different buttons for UP and for DOWN you probably don't need either debounce or delay.

If you do need a delay I would put the button read business in a separate function and create a wait period using millis() (not the delay() function) at the top of it something like this (copied from my own small test program)

void readButton() {

if (curMillis - prevBtnMillis < 70) {
}




This code waits at least 70 msecs between button reads but if the 70ms has already been used up elsewhere it won't need to wait at all. And it does not hold up anything else during the 70 msecs.

...R

Thank you I'll check that out, at the very least removing the delays

So like I figured, way too much over thinking in my code

Here's my final working code

I left one delay in just for fun, 10 millisecond delay won't be noticed

Again I'm using the Analog Pins as Digital, so no I'm not using Digital Pin 1

/*
My Attempt at controlling a crane with Arduino
Using analog pins 0 - 5 as input
pin 0 will rotate the crane CCW
pin 1 will rotate the crane CW
pin 2 will move the trolly out
pin 3 will move the trolly in
pin 4 will raise the hook
pin 5 will lower the hook
Motor Control is accomplished with the ADAFRUIT
Motor Control Shield
Motor 1 will control rotation
Motor 2 will control the Trolly
Motor 3 will control the hook
*/

#include <AFMotor.h>

// Set up the motors - name and channel

AF_DCMotor rotate(1, MOTOR12_64KHZ); // create motor #1 named rotate, 64KHz pwm
AF_DCMotor trolly(2, MOTOR12_64KHZ); // create motor #2 named trolly, 64KHz pwm
AF_DCMotor hook(3, MOTOR12_1KHZ); // create motor #2 named hook, 1KHz pwm

// set button variables

int but0 = 0;
int but1 = 0;
int but2 = 0;
int but3 = 0;
int but4 = 0;
int but5 = 0;

void setup() {
rotate.setSpeed(255);
trolly.setSpeed(255); // Motor speed 0-255
hook.setSpeed(255);
}

void loop() {
but0 = digitalRead(A0);
but1 = digitalRead(A1);
but2 = digitalRead(A2); // Read the buttons
but3 = digitalRead(A3);
but4 = digitalRead(A4);
but5 = digitalRead(A5);

// Rotation control

if ((but0 == HIGH) && (but1 == LOW)) {
rotate.run(FORWARD);
Serial.println("Rotate CCW");
} if ((but1 == HIGH) && (but0 == LOW)) {
rotate.run(BACKWARD);
Serial.println("Rotate CW");
} if ((but1 == LOW) && (but0 == LOW)) {
rotate.run(RELEASE);
}

// Trolly control

if ((but2 == HIGH) && (but3 == LOW)) {
trolly.run(FORWARD);
Serial.println("Trolly Out");
} if ((but3 == HIGH) && (but2 == LOW)) {
trolly.run(BACKWARD);
} if ((but2 == LOW) && (but3 == LOW)) {
trolly.run(RELEASE);
}

// Hook Control

if ((but4 == HIGH) && (but5 == LOW)) {
hook.run(FORWARD);
} if ((but5 == HIGH) && (but4 == LOW)) {
hook.run(BACKWARD);
} if ((but4 == LOW) && (but5 == LOW)) {
hook.run(RELEASE);
}
delay(10);
}

So I've discovered an issue... Button 0 and Button 2 operate almost immediately, and simultaneously like I was hoping. Button 1 and Button 3 often take a second or two of inactivity from it's corresponding counterpart before it works, I haven't tested the other pair of buttons yet but I'd say it's safe to bet it's the same considering the code is the same through all three sets of buttons.

I was hoping some one might be able to see in the code in the previous post, something that I can improve upon.

Again it's three motors, their direction is controlled by 2 buttons each.

It makes it hard to read your code if you start a line with } and there is something else on the line. Normally a } should be on the line by itself.

I can't see anything obvious with your code, so I would look at the operation of that libary and see if it contains delays and is holding onto the code and not returning.

That is the problem with libaries you never know what they do.

I have had a look at the code in Reply #4 and it does not seem to be complete.

I suspect (guess) that the problem is that the button1 section runs some code rotate.run(RELEASE); even when no button is pressed (assuming HIGH = pressed). I don't know what that piece of code does as it is not included in your code.

Lose the delay(10).

In future please post your code using code tags, not quote tags.

...R

That is a libary call so it is not in the code, that is why I said what I said.

It might be a good thing if that call were made only when the buttons become low not every time thy are low, in other words do a state change for that condition.

Grumpy_Mike:
That is a libary call so it is not in the code, that is why I said what I said.

Sorry - I missed that.

...R

Hi,auto format will sort out the } edit. Using IDE 1.5.

Tom....... :slight_smile:

How are the buttons wired up? It could be that you have floating inputs.

See this for how to wire up inputs:-
http://www.thebox.myzen.co.uk/Tutorial/Inputs.html

Grumpy_Mike:
I can't see anything obvious with your code, so I would look at the operation of that libary and see if it contains delays and is holding onto the code and not returning.

That is the problem with libaries you never know what they do.

I have actually looked at the library, most of the code I understand at least to some extent, but not technically enough to spot issues like what you have mentioned.

The Library in use is the one from AdaFruit, for the mshield. I've attached the .h and .cpp files if anyone would like to review them

Grumpy_Mike:
How are the buttons wired up? It could be that you have floating inputs.

See this for how to wire up inputs:-
http://www.thebox.myzen.co.uk/Tutorial/Inputs.html

Thank you for the link, I had the switches wired up with pull-down resistors, I'll switch it, and my code, for pull-up resistors from the sites recommendations. I had noticed the necessity for the pins to go to ground for a low reading while I was building and testing the circuit. Had two switches wired, but not the other 4, and the code I have in there for debugging was spamming the other switches until I grounded them.

Grumpy_Mike:
It makes it hard to read your code if you start a line with } and there is something else on the line. Normally a } should be on the line by itself.

I was doing it to remind me it is associated with the if statement above... The book I'm using didn't mention the ability of "else if" only having an "else" statement.

At any rate, the "formatting" is only for human readability not machine readability, and shouldn't be effecting the function in any way. Rather amazes me how many posts were about that fact, and not why there's a bad lag on the odd numbered inputs.

librarry.txt (18.1 KB)

AFMotor.h (5.84 KB)

Ritlee:
Rather amazes me how many posts were about that fact, and not why there's a bad lag on the odd numbered inputs.

I'm amazed that you are amazed.

If it is not easy to read the code it is not easy to give advice about it. When code is hard to read it makes more sense to devote my time to another Thread where the user has taken the trouble to provide easy-to-read code.

One practical test would be to write a short piece of code that just calls the library function 100 or 1000 times and measures how long it takes by recording micros() before and after the FOR loop and prints the difference when the FOR loop is finished.

...R

I have actually looked at the library, most of the code I understand at least to some extent, but not technically enough to spot issues like what you have mentioned.

Yes I looked at the library code and could not see an issue.

So now you have made changes to your code what you do is to format it correctly ( not the format for forum option despite it's name ) and use the code tags not the quote tags to post your code, is is second to the end at the moment.
That way we can copy it onto our systems and have a look at it.