Arduino Code Question

Two axis stepper control via joystick

Anything that doesn't fit anywhere else below.

Moderators: Calilasseia, ADParker

Arduino Code Question

#1  Postby theropod » Jun 27, 2018 1:17 am

I have built what I call a junk Alt Az mount because the entire apparatus is mostly fabricated from cast off parts. I have used stepper motors salvaged from dead printers to drive the two axis of movement, and used an Arduino Nano to send pulse signals to two Easy Driver breakout boards. I have a small analog joystick/thumbstick I am using to derive resistance values the Arduino in turn uses to control the driver boards via a digital pulses.

I would like to generate a pulse speed in proportion to the resistance values. Say I only want to bump my scope a few steps in a particular direction, or quickly slew across the sky to a new target, I want the stepper speed to be in direct respond to the joystick movemt proportionally.

My current solution works, but not as I envisioned, and for the life of me I cannot seem to visualize a code that achieves my ideal. My current code only uses the joystick movements as indicators of direction (east/west, up/down) and relies on the down switch of the joystick (think Sony PS2 Thumb controller using two variable resistors) to employ the “case” and “break” statements to call different delays between the “on” (HIGH) and “off” (LOW) signals sent to the drivers.

Below is the code I have managed to cobble together I offer up in order to help explain how utterly lost I am.

Code: Select all
// sketch for driving DIY alt-az
// June, 2018

// define which pins do what

  #define step_pinx 2 // D2 is step signal pin for X axis
  #define dir_pinx 3 // D3 is direction control pin for X axis
  #define x_pin A0 // analog input from joystick for X axis
  #define y_pin A1 // analog input from joystick for Y axis
  #define joy_switch 6 // joystick switch INPUT PULLUP
  #define step_piny 5 // D5 is step signal pin for Y axis
  #define dir_piny 4 // D4 is direction control pin for Y axis
  int step_speed = 5; // stepper speed higher is slower


void setup() {
  delay(1000); // 1 second delay to allow easy drivers to power up
  pinMode(joy_switch, INPUT_PULLUP);
  pinMode(dir_pinx, OUTPUT);
  pinMode(step_pinx, OUTPUT);
  pinMode(dir_piny, OUTPUT);
  pinMode(step_piny, OUTPUT);
 

}

void loop() {
  //
if (!digitalRead(joy_switch)){ // if joystick switch is clicked
  delay(500); // debounce delay
  switch(step_speed) { // check speed value and change
    case 1:
    step_speed=5; // slow
    break;
    case 3:
    step_speed=1; // fast speed
    break;
    case 10:
    step_speed=2.5; // medium speed
    break;
  }
}

if(analogRead(x_pin)>712){ //if joystick moved left
}
  else
    digitalWrite(dir_pinx, LOW); // move motor cockwise
    digitalWrite(step_pinx, HIGH); //send step signal X axis
    delay(step_speed); // delay set by joystick switch case above
    digitalWrite(step_pinx, LOW); // stop step signal X axis
    delay(step_speed); // set above

if(analogRead(y_pin)>712){ //if joystick moved up
}
  else
    digitalWrite(dir_piny, LOW); // move motor up
    digitalWrite(step_piny, HIGH); //send step signal Y axis
    delay(step_speed); // delay set by joystick switch case above
    digitalWrite(step_piny, LOW); // stop step signal Y axis
    delay(step_speed); // set above

if(analogRead(x_pin)<312){ //if joystick moved right
}
  else
    digitalWrite(dir_pinx, HIGH); // move motor countercockwise
    digitalWrite(step_pinx, HIGH); //send step signal X axis
    delay(step_speed); // delay set by joystick switch case above
    digitalWrite(step_pinx, LOW); // stop step signal X axis
    delay(step_speed); // set above
   
if(analogRead(y_pin)<312){ // if joystick moved down

  else
    digitalWrite(dir_piny, HIGH); // move motor down
    digitalWrite(step_piny, HIGH); //send step signal Y axis
    delay(step_speed); // delay set by joystick switch case above
    digitalWrite(step_piny, LOW); // stop step signal Y axis
    delay(step_speed); // set above
  }


Below is what I have built. This is a test to see if the gear trains, all stuff headed to the junk heap, would hold position without power, which it happily does. The only hardware purchased was the up/down shaft bearings and the nuts and bolts holding everything together. My goal here is to mount this to my barn door tracker running from a different Arduino and Easy Driver, and have a 3 axis German Equatorial Mount. After fighting a defective ball head for nearly a year this will provide a much more robust means to lock on to a target. Now if I can only figure out how to make the steppers do things the way I really want.

4C14CB1F-7F5B-42EA-8D08-7485CAEA734D.jpeg
Junk Alt Az
4C14CB1F-7F5B-42EA-8D08-7485CAEA734D.jpeg (1.46 MiB) Viewed 1505 times


Thanks all.

RS
Sleeping in the hen house doesn't make you a chicken.
User avatar
theropod
RS Donator
THREAD STARTER
 
Name: Roger
Posts: 7529
Age: 66
Male

Country: USA
United States (us)
Print view this post

Ads by Google


Re: Arduino Code Question

#2  Postby Calilasseia » Jun 27, 2018 12:46 pm

I'm really puzzled about the coding of your IF statements.

Take for example, this one:

Code: Select all
if(analogRead(x_pin)>712){ //if joystick moved left
}
  else
    digitalWrite(dir_pinx, LOW); // move motor cockwise
    digitalWrite(step_pinx, HIGH); //send step signal X axis
    delay(step_speed); // delay set by joystick switch case above
    digitalWrite(step_pinx, LOW); // stop step signal X axis
    delay(step_speed); // set above



That IF statement, as coded, does nothing if the specified condition is true, and instead, executes the code you specify if the condition is false. Is that what you actually wanted? Oh, and you've missed off the braces in the ELSE clause, which means that only the first statement after the ELSE will be part of your conditional statement!
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#3  Postby Calilasseia » Jun 27, 2018 12:50 pm

Here's how you write that code block, if you want those instructions to be executed if the condition is true:

Code: Select all
if(analogRead(x_pin)>712)
{
    digitalWrite(dir_pinx, LOW); // move motor cockwise
    digitalWrite(step_pinx, HIGH); //send step signal X axis
    delay(step_speed); // delay set by joystick switch case above
    digitalWrite(step_pinx, LOW); // stop step signal X axis
    delay(step_speed); // set above
}
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#4  Postby Calilasseia » Jun 27, 2018 12:54 pm

Here's how you go about coding an IF ... ELSE in C, for future reference:

Code: Select all
if (condition)
{
//Everything inside this pair of braces will be executed, if the condition is true ...

}
else
{
//Everything inside this pair of braces will be executed, if the condition is false ...

}



If you need multiple conditions, you can do this:

Code: Select all
if (condition1)
{
//Everything in this pair of braces is executed if condition1 is true ...

}
else if (condition2)
{
//Everything in this pair of braces is executed if condition2 is true ...

}
else if (condition3)
{
//Everything in this pair of braces is executed if condition3 is true ...

}
else
{
//Everything in this pair of braces is executed, if all three conditions are false ...

}


This should solve a large number of your current coding woes.
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#5  Postby theropod » Jun 27, 2018 1:01 pm

Ah ha! Thanks mighty blue one! I will give this a go later today. Yardwork before the heat becomes deadly awaits.

RS
Sleeping in the hen house doesn't make you a chicken.
User avatar
theropod
RS Donator
THREAD STARTER
 
Name: Roger
Posts: 7529
Age: 66
Male

Country: USA
United States (us)
Print view this post

Re: Arduino Code Question

#6  Postby Calilasseia » Jun 27, 2018 1:02 pm

Oh, by the way, were those values 312 and 712 for your analogue reads chosen to implement a "dead zone" for the joystick, so your motors aren't triggered by non-static analogue data when the joystick is centred?
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#7  Postby theropod » Jun 27, 2018 4:42 pm

Whew, yard work not finished but I am finished with it, for today. At 10:30 the temperature had already reached 94° F.

Yes, the idea is to create a dead zone. I did confirm that the joystick returns values within those specs via the serial monitor. When I recover from my sweat fest I will fire up the IDE and make some changes, and report my progress. I may expand that null area a bit more to better control unwanted input. I will definitely alter the “if” “else” statements as per your guidance.

My biggest issue with this is still how to use those analog values to derive a pulse train proportional to input. Perhaps just writing a shit ton of these “if” “else” statements to refine the degrees of input values would accomplish this.

Still, thanks very much.

RS
Sleeping in the hen house doesn't make you a chicken.
User avatar
theropod
RS Donator
THREAD STARTER
 
Name: Roger
Posts: 7529
Age: 66
Male

Country: USA
United States (us)
Print view this post

Ads by Google


Re: Arduino Code Question

#8  Postby Calilasseia » Jun 27, 2018 5:20 pm

First question ... do you know the extreme values that are returned by your joystick controller?

Only if those values are, say, in the range 0 to 1000 inclusive, then one way you could have your joystick determine the speed of movement is as follows:

Code: Select all

//First, define the dead zone constants ...

#define DEADZONE_LEFT 712
#define DEADZONE_RIGHT 312
#define DEADZONE_UP 712
#define DEADZONE_DOWN 312

//Now define joystick limit constants (edit these if your values differ from the ones I've chosen):

#define LIMIT_LEFT 1000
#define LIMIT_RIGHT 0
#define LIMIT_UP 1000
#define LIMIT_DOWN 0


//Now, for your code, you do this for joystick left ...

if (analogReady(x_pin) > DEADZONE_LEFT)
{
//First, we use the joystick output to compute the step speed. In this code block, I'll assume that the x_pin value
//is between DEADZONE_LEFT and LIMIT_LEFT as defined above. Since LIMIT_LEFT is greater than DEADZONE_LEFT,
//we compute the following:

   scale = (LIMIT_LEFT - DEADZONE_LEFT) / 10;   //Scale factor for division
   step_speed = (x_pin - DEADZONE_LEFT) / scale;   //Converts your joystick left value into a step speed between
                  //0 and 10

   if (step_speed < 0.5)
      step_speed = 0.5;         //Do this to make sure that when you're out of the dead zone,
                  //your joystick movement actually results in movement!

//Now we actually perform your movement as you intended, but now, that movement will be linearly dependent on your joystick position!

   digitalWrite(dir_pinx, LOW); // move motor clockwise
   digitalWrite(step_pinx, HIGH); //send step signal X axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(step_pinx, LOW); // stop step signal X axis
   delay(step_speed); // set above

}


//Now you do this for joystick right ...

if (analogReady(x_pin) < DEADZONE_RIGHT)
{
//First, we use the joystick output to compute the step speed. In this code block, I'll assume that the x_pin value
//is between DEADZONE_RIGHT and LIMIT_RIGHT as defined above. Since LIMIT_RIGHT is less than DEADZONE_RIGHT,
//we compute the following:

   scale = (DEADZONE_RIGHT - LIMIT_RIGHT) / 10;   //Scale factor for division
   step_speed = (DEADZONE_RIGHT - x_pin) / scale;   //Converts your joystick right value into a step speed between
                  //0 and 10

   if (step_speed < 0.5)
      step_speed = 0.5;         //Do this to make sure that when you're out of the dead zone,
                  //your joystick movement actually results in movement!

//Now we actually perform your movement as you intended, but now, that movement will be linearly dependent on your joystick position!

   digitalWrite(dir_pinx, HIGH); // move motor anti-clockwise
   digitalWrite(step_pinx, HIGH); //send step signal X axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(step_pinx, LOW); // stop step signal X axis
   delay(step_speed); // set above

}


//Now you do this for joystick up ...

if (analogReady(y_pin) > DEADZONE_UP)
{
//First, we use the joystick output to compute the step speed. In this code block, I'll assume that the y_pin value
//is between DEADZONE_UP and LIMIT_UP as defined above. Since LIMIT_UP is greater than DEADZONE_UP,
//we compute the following:

   scale = (LIMIT_UP - DEADZONE_UP) / 10;   //Scale factor for division
   step_speed = (x_pin - DEADZONE_UP) / scale;   //Converts your joystick left value into a step speed between
                  //0 and 10

   if (step_speed < 0.5)
      step_speed = 0.5;         //Do this to make sure that when you're out of the dead zone,
                  //your joystick movement actually results in movement!

//Now we actually perform your movement as you intended, but now, that movement will be linearly dependent on your joystick position!

   digitalWrite(dir_piny, LOW); // move motor clockwise
   digitalWrite(step_piny, HIGH); //send step signal Y axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(step_piny, LOW); // stop step signal Y axis
   delay(step_speed); // set above

}


//Now you do this for joystick down ...

if (analogReady(y_pin) < DEADZONE_DOWN)
{
//First, we use the joystick output to compute the step speed. In this code block, I'll assume that the y_pin value
//is between DEADZONE_UP and LIMIT_UP as defined above. Since LIMIT_UP is less than DEADZONE_UP,
//we compute the following:

   scale = (DEADZONE_UP - LIMIT_UP) / 10;   //Scale factor for division
   step_speed = (DEADZONE_UP - x_pin) / scale;   //Converts your joystick right value into a step speed between
                  //0 and 10

   if (step_speed < 0.5)
      step_speed = 0.5;         //Do this to make sure that when you're out of the dead zone,
                  //your joystick movement actually results in movement!

//Now we actually perform your movement as you intended, but now, that movement will be linearly dependent on your joystick position!

   digitalWrite(dir_piny, HIGH); // move motor anti-clockwise
   digitalWrite(step_piny, HIGH); //send step signal X axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(step_piny, LOW); // stop step signal X axis
   delay(step_speed); // set above

}



If this works as intended, then moving your joystick will result in movement of your stepper motors that is mostly linear. Apart from the exit from the dead zone, where there'll be a small region where the step speed is 0.5, and then it'll transition to higher values, the more you move the joystick, and from that point on will do so in in a linear fashion.

Before trashing your old code, save it so you can return to it if needed, and try the above. Oh, and I've also changed some of the movements to anti-clockwise, because I suspect that's what you intended. If you need to switch them around because they're the wrong way round, that's just a matter of changing the clockwise/anti-clockwise statements to suit your desired movement. :)
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#9  Postby theropod » Jun 27, 2018 7:55 pm

Ah ha moment!

Laying in our bedroom under the full output of the air conditioner, and about to engage in REM sleep, but I see what you did there.

Let me hack away at the IDE and get back to you. Thanks again.

RS
Sleeping in the hen house doesn't make you a chicken.
User avatar
theropod
RS Donator
THREAD STARTER
 
Name: Roger
Posts: 7529
Age: 66
Male

Country: USA
United States (us)
Print view this post

Re: Arduino Code Question

#10  Postby theropod » Jun 27, 2018 10:55 pm

When the compiler reaches this section of code:

Code: Select all
"  scale = (LIMIT_LEFT - DEADZONE_LEFT) / 10;   //Scale factor for division
   step_speed = (x_pin - DEADZONE_LEFT) / scale;   //Converts your joystick left value into a step speed between
                  //0 and 10"


it throws the error message. "error: 'scale' was not declared in this scope".

I think I will settle for what is working because I don't want to consume any more of your time with such a trivial matter. That and I just have to face the fact that C is beyond me.

RS
Sleeping in the hen house doesn't make you a chicken.
User avatar
theropod
RS Donator
THREAD STARTER
 
Name: Roger
Posts: 7529
Age: 66
Male

Country: USA
United States (us)
Print view this post

Re: Arduino Code Question

#11  Postby theropod » Jun 28, 2018 1:41 am

Revised statement:
Frankly I am far too distracted by the eminent downfall of the USA to concentrate on implementing code. All I could think of when the IDE threw the error was how quickly the best principles of America have gone down the pipes. I couldn’t even speculate on what was really wrong with the code, or experiment with solutions. I just saved Cali’s code to a new file and sat there in a stunned state of fear and loathing staring at my desktop picture.

RS
Sleeping in the hen house doesn't make you a chicken.
User avatar
theropod
RS Donator
THREAD STARTER
 
Name: Roger
Posts: 7529
Age: 66
Male

Country: USA
United States (us)
Print view this post

Re: Arduino Code Question

#12  Postby Cito di Pense » Jun 28, 2018 3:55 am

theropod wrote:When the compiler reaches this section of code:

Code: Select all
"  scale = (LIMIT_LEFT - DEADZONE_LEFT) / 10;   //Scale factor for division
   step_speed = (x_pin - DEADZONE_LEFT) / scale;   //Converts your joystick left value into a step speed between
                  //0 and 10"


it throws the error message. "error: 'scale' was not declared in this scope".

I think I will settle for what is working because I don't want to consume any more of your time with such a trivial matter. That and I just have to face the fact that C is beyond me.

RS


scale is just a combination of constants you already #define-d. Either #define it as a convenience constant in the same block with your LIMIT and DEADZONE stuff or declare it as a variable, with a type, so you can create storage for it, probably where you declare step_speed. I'm guessing the stepper motor just uses integer values, one step at a time. :thumbup:
Хлопнут без некролога. -- Серге́й Па́влович Королёв

Translation by Elbert Hubbard: Do not take life too seriously. You're not going to get out of it alive.
User avatar
Cito di Pense
 
Name: Fay Smask
Posts: 29222
Age: 23
Male

Country: The Heartland
Mongolia (mn)
Print view this post

Re: Arduino Code Question

#13  Postby Calilasseia » Jun 28, 2018 4:13 am

Ah, of course. A little detail I forgot to mention.

C compilers require you to declare all variables that you are using. I forgot to put a declaration for 'scale' in the code, thinking you'd hit on that and insert it yourself. While I'm on this subject, here's another feature of C to take on board, centring upon how to declare variables.

You're already familiar with the fact that each variable has a type, and that the declaration takes the general form:

<varable_type> <variable_name>

examples thereof being:

int counter;
float newtons_g;

and in your code, you've also demonstrated that you're familiar with the fact that you can include an initialisation step in your declaration, such as:

int counter = 0;
float newtons_g = 6.6E-11;

assuming of course that your compiler supports floating point artihmetic above. :)

However, you have a choice of where to define your variables. If you want a variable to be available to every function in your code, you declare (and possibly initialise) that variable outside of all of your functions, as you did in your original code with the statement:

int step_speed = 5;

If, on the other hand, you only need a variable to be available to a particular function, then you declare it inside the function, as follows:

Code: Select all
myfunction()
{
int scale = 0;

//Rest of your function code goes here

}



The beauty of this is twofold. First, this allows you to have local variables known only to a particular function, as and when you need them. Second, it means you can use the same name for two different local variables in two different functions, and the compiler will recognise that they're local to each function, and treat them as distinct. Of course, this means that you need to make sure your local variables don't have names that clash with your global variables defined outside all of your functions!

Oh, I also assumed that step_speed in your code had to be bigger in order to make your motors run faster, which I now realise was an error, because you're using it as a delay counter. Which means the calculations for step_speed in my code need to be changed accordingly.

Incidentally, if you're looking for a decent book on C programming, the one I bought was the original - The C Programming Language by Brian W. Kernighan & Dennis M. Ritchie. These authors designed the C programming language in the first place, so their book is the 'go to' reference source for C as it was first defined. Later revisions (ANSI C, etc) and your particular compiler's idiosyncrasies you can cover after having a browse through this book. Likely to be expensive, so a library copy might be the way to go here.

In the meantime, leave this with me, because I'm actually having some fun with this, even though I'm using you as a remote debugger! :D
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#14  Postby Calilasseia » Jun 28, 2018 4:22 am

Oh, almost forgot!

The #define statement is actually part of what's known as the 'C preprocessor', which simply remembers lists of strings and their substitutes, then hunts through your code looking for the first string in the statement, and substituting it with the second string in the statement in your source code before passing the lot to the compiler proper. It's the way in which constants are supplied to C programs. So when you have:

#define LIMIT 10

in your code, the C preprocesssor looks for code such as:

Code: Select all
if (x < LIMIT)
{
//Whatever
}


and substitutes '10' for 'LIMIT' before that code is passed to the compiler.

By convention, C programmers (of which I used to be one) used UPPER CASE for constants defined using #define, and lower case for variables in variable declarations, because if made the code easier to read and understand - C source code does tend to have a hieroglyphic look to it when displayed!
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#15  Postby Calilasseia » Jun 28, 2018 4:55 am

On reflection, given what I've learned about what your code is supposed to achieve, it's actually better to parcel that computation into its own function assuming your compiler supports the usual C standard of functions with a return value. Here's what the revised code looks like:

Code: Select all

//This function takes a joystick value in 'val', the deadzone value in 'dz', and the extreme limit in 'lim'.
//Returns your desired step speed value.

setspeed(int val, int dz, int lim)
{
//First declare some necessary variables ...

float scale = 0;
int upper = 0;
int lower = 0;
int result = 0;
int dir = 0;

//Now work out which of 'dz' and 'lim' is larger. We then set 'upper' and 'lower' accordingly. We also set the 'dir' variable
//to +1 if lim > dz, or -1 if lim < dz. This is so that we can use 'dir' to correctly map our end result onto a positive range for
//the step speed calculation, regardless of which way round the arguments are. :)

if (lim > dz)
{
   upper = lim;
   lower = dz;
   dir = 1;
}
else
{
   upper = dz;
   lower = lim;
   dir = -1;
}

//Now begin the calculation. Note the use of (float) in the first statement. This is a CAST. It means 'transform the data from whatever type it currently is,
//to a floating-point data type before performing the calculation'.

scale = ( (float) ((upper - lower)) / 9);

//Now map your joystick value onto the range 0 - 9 inclusive (you'll see why in a moment ...). Again, we use a cast to convert the result back to an int when
//we're finished ...

result = (int) (( (float) (val - lower) * scale) * dir);

//Now map onto the range 10 to 1 backwards:

result = 10 - result;

//Now multiply this by a scale factor in case it's needed. Use #define SPEED_SCALE 1 outside the function to create the scale speed, and if you need to increase
//this value because things are moving too fast, you can always increase it after testing!

result = result * SPEED_SCALE;

return(result);
}


//Now, in your IF statements in the other function, you can do this, with the appropriate #define constants I created earlier:

if (analogReady(x_pin) > DEADZONE_LEFT)
{
   step_speed = setspeed(x_pin, DEADZONE_LEFT, LIMIT_LEFT)

//Now we actually perform your movement as you intended, but now, that movement will be linearly dependent on your joystick position!

   digitalWrite(dir_pinx, LOW); // move motor clockwise
   digitalWrite(step_pinx, HIGH); //send step signal X axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(step_pinx, LOW); // stop step signal X axis
   delay(step_speed); // set above

}

//Repeat as appropriate for the other IF statements!



Whether this will work depends upon what features your compiler supports, but if it supports the full K&R standard, then the above should compile without error, and then you can see if it all works!
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Ads by Google


Re: Arduino Code Question

#16  Postby theropod » Jun 28, 2018 2:44 pm

OK I am beginning to come to grips with this, but the Arduino compiler has some quarks unique to it, and operates on a bastardized version of C. The specific complier can found on the following site. Further references spring from this page.

https://www.arduino.cc/en/Main/Software

Also each variety of Arduino has it’s own idiosyncratic specs, and some have less, or more, pins with which to interact with the physical world. I have selected the Nano for the small footprint and low cost. Most people use prototyping “punch” boards where jumper wires are inserted to make connections to peripheral devices. Since I have some skills with delicate soldering, and logical wire routing abilities, those boards hold little interest for me.

I had the notion that I needed to define the term “scale” but my mind just wasn’t into it yesterday. The direction my country is headed is quite distracting to say the least. Add in our Africa hot summers, which are the most challenging part of the year for our off grid lifestyle, and my creativity goes into the shitter.

Back when I took coding relatively seriously I used the 80’s version of Microsoft BASIC, and although the software was primitive by the standards of full fledged C the pathway to solutions was more clear. Granted my brain was far more flexible 40+ years ago than today, so there is a very high likelihood my current confusion, and distraction, have combined into brain lock.

I fully agree that a detailed reference source, in print form, would be a huge help. Sure, I could browse the online references provided by the Arduino CC, and address the issue in the associated forum. The trouble is the forum is infested with smart asses that would rather score points for being obtuse than actually helping, and my learning style is geared more toward printed media (a hold over from my days at college when highlighting and note taking was a thing).

I hate being inept at anything, which I know is a personal issue, and coding in C exposes just how clueless I really am. I really do want to understand the issues at hand, so I deeply appreciate the help being offered here.

I plan on mounting another attack on this maze of terms later today and apply the latest advice.

RS
Sleeping in the hen house doesn't make you a chicken.
User avatar
theropod
RS Donator
THREAD STARTER
 
Name: Roger
Posts: 7529
Age: 66
Male

Country: USA
United States (us)
Print view this post

Re: Arduino Code Question

#17  Postby Calilasseia » Jun 28, 2018 3:10 pm

Ah, the joys of a non-standard compiler - or not, as the case may be!

Oh, by the way, another of those conventions that held in the past, but which may have been tossed into the bin in later incarnations of the language, was this. The compiler treated 'int' as the default type for functions, unless you preceded the function name with the type it was to return. So if you need a function that returns a float, you have to write this:

Code: Select all
float myfunction(arg1, arg2)
{
//Do whatever here

return(float_value); //or whatever your return value is called at this point ...
}


However, for functions that didn't return a value, the initial K&R C compiler didn't provide explicit syntactic clues that this was the case. We had to wait for the later ANSI C standard, to introduce the keyword 'void', which basically meant "returns nothing", so that more modern C compilers have functions that are defined as follows:

Code: Select all
void myfunction()
{
//Do whatever here

}


The Arduino compilers appear to understand the use of 'void', from what I can gather.

Likewise, if your function arguments are something other than type 'int', then this has to be declared too, viz:

Code: Select all
float myfunction(float arg1, arg2) //function taking 2 float arguments, returning a float
{
float retval; //declare the return value here as a local variable, and compute it shortly ...

// ...

return(retval); //return the computed value once done ...
}


You can, of course, explicitly type-specify every argument to make things especially clear, viz:

Code: Select all
//Function returning a float value. Takes two float arguments, an int argument, and a char argument ...

float myfunction(float arg1, float arg2, int arg3, char arg4)
{
//Do whatever

}


However, one area where the Arduino compilers appear to depart from standard versions of C, is this. Standard C compilers looked for a function called 'main', which contained your main application, within which you called all the other functions that handled the bits and pieces of your application. Arduino compilers appear to treat the function 'loop' in the same manner as other compilers treat 'main', but there may be some other quirks to deal with, such as whether or not arguments are allowed to be passed to the loop() function as they are in main() on standard compilers. This feature was present to allow command line arguments to be passed to C programs back in the 1970s, before GUIs existed.
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#18  Postby Calilasseia » Jun 28, 2018 3:24 pm

Found this language reference online. Interesting. Apparently the Arduino compiler doesn't support 'struct' or 'extern', which is a fairly serious omission, but one that's probably permissible for a single board microcontroller environment. But it does support a brace of other features, and appears to support everything I've covered above at first glance.
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Re: Arduino Code Question

#19  Postby theropod » Jun 28, 2018 6:53 pm

After messing about with the example code I figured out nearly all issues, and now complies correctly. The trouble I now face is that the "Y" axis motor (LEFT-RIGHT) now goes into a full tilt spin when the Y axis is tilted even slightly to the left. I am apparently missing some basic feature of the software driving that motor. The X axis (UP-DOWN) is working but proportional speed is still not correct for either motor. Also the motors produce a hum as if they are active constantly. Below is the code after tweaking for some time.
Code: Select all
//Biaxial stepper driver 6/2018

#define x_pin A0 // analog input from joystick for X axis UP-DOWN
#define y_pin A1 // analog input from joystick for Y axis LEFT-RIGHT
#define step_pinx 2 // digital output pin 2 is step signal pin for X axis UP-DOWN
#define dir_pinx 3 // digital output pin 3 is direction control pin for X axis UP-DOWN
#define joy_switch 6 // digital control pin joystick switch INPUT PULLUP
#define step_piny 5 // digital output pin 5 is step signal pin for Y axis LEFT-RIGHT
#define dir_piny 4 // digital output pin 4 is direction control pin for Y axis LEFT-RIGHT

  // the following used to compute step signal speed

int scale=0; // sets initial value of "scale" at zero
int step_speed=0; // sets initial value of "step_speed" at zero

  //Define the dead zone constants
   
int DEADZONE_LEFT=540; // analog Y axis pin  A0 dead zone LEFT
int DEADZONE_RIGHT=540; // analog Y axis pin A0 dead zone RIGHT
int DEADZONE_UP=580; // analog X axis pin A1 dead zone UP
int DEADZONE_DOWN=580; // analog X axis pin A1 dead zone DOWN

  //Define the limit zone constants
   
int LIMIT_LEFT=1000; // max analog input UP X axis
int LIMIT_RIGHT=100; // min analog input DOWN X axis
int LIMIT_UP=1000; // max analog input LEFT Y axis
int LIMIT_DOWN=100; // min analog input RIGHT Y axis
int xPosition = 0;
int yPosition = 0;
int buttonState = 0;

void setup() {
  Serial.begin(9600);
  delay(1000); // 1 second delay to allow easy drivers to power up
  pinMode(dir_pinx, OUTPUT);
  pinMode(step_pinx, OUTPUT);
  pinMode(dir_piny, OUTPUT);
  pinMode(step_piny, OUTPUT);
  pinMode(joy_switch, INPUT_PULLUP); // not used in this example
}

void loop() {
  xPosition = analogRead(x_pin); // Provide feedbback to joystick input UP-DOWN
  yPosition = analogRead(y_pin); // Provide feedback to joystick input LEFT-RIGHT
  buttonState = digitalRead(joy_switch); // Provide feedback joystick button action
  Serial.print("X=UP-DOWN: ");
  Serial.print(xPosition);
  Serial.print(" | Y=LEFT-RIGHT: ");
  Serial.print(yPosition);
  Serial.print(" | Button: ");
  Serial.println(buttonState);
 
  //X analog input controls up-down movement
  //joystick UP

  if(analogRead(x_pin) > DEADZONE_UP)
  {
    //use the joystick output to compute the step speed UP

  scale=(LIMIT_UP - DEADZONE_UP) / 10;   //Scale factor for division
  step_speed=(x_pin - DEADZONE_UP) / scale;   //Converts your joystick UP value into a step speed between
                      //0 and 10

       if(step_speed < 0.5)
          step_speed = 0.5;         //Do this to make sure that when you're out of the dead zone,
                      //your joystick movement actually results in movement!

  // movement will be linearly dependent on your joystick position

       digitalWrite(dir_pinx, LOW); // send motor signal ON axis UP
       digitalWrite(step_pinx, HIGH); //send step signal X axis
       delay(step_speed); // delay set by joystick computation above
       digitalWrite(step_pinx, LOW); // send motor signal OFF axis UP
       delay(step_speed); // set above

    }


  //X analog input controls up-down movement
  //joystick DOWN
    if(analogRead(x_pin) < DEADZONE_DOWN)
    {
    //First, we use the joystick output to compute the step speed. In this code block, I'll assume that the x_pin value
    //is between DEADZONE_RIGHT and LIMIT_RIGHT as defined above. Since LIMIT_DOWN is less than DEADZONE_DOWN,
    //we compute the following:

       scale=(DEADZONE_DOWN - LIMIT_DOWN) / 10;   //Scale factor for division
       step_speed=(DEADZONE_DOWN - x_pin) / scale;   //Converts your joystick DOWN value into a step speed between
                      //0 and 10

       if(step_speed < 0.5)
          step_speed = 0.5;         //Do this to make sure that when you're out of the dead zone,
                      //your joystick movement actually results in movement!

    // movement will be linearly dependent on your joystick position!

       digitalWrite(dir_pinx, HIGH); // send motor signal ON axis DOWN
       digitalWrite(step_pinx, HIGH); //send step signal X axis
       delay(step_speed); // delay set by joystick computation above
       digitalWrite(step_pinx, LOW); // send motor signal OFF axis DOWN
       delay(step_speed); // set above

    }

  //Y analog input controls left-right movement
  // joystick LEFT

    if(analogRead(y_pin) > DEADZONE_LEFT)
    {
    // use the joystick output to compute the step speed LEFT

       scale = (LIMIT_LEFT - DEADZONE_LEFT) / 10;   //Scale factor for division
       step_speed = (x_pin - DEADZONE_LEFT) / scale;   //Converts your joystick left value into a step speed between
                      //0 and 10

       if(step_speed < 0.5)
          step_speed = 0.5;         //Do this to make sure that when you're out of the dead zone,
                      //your joystick movement actually results in movement!

    // movement will be linearly dependent on your joystick position!

       digitalWrite(dir_piny, LOW); // send motor signal ON axis LEFT
       digitalWrite(step_piny, HIGH); //send step signal Y axis LEFT
       delay(step_speed); // delay set by joystick computation above
       digitalWrite(step_piny, LOW); // send motor signal OFF axis LEFT
       delay(step_speed); // set above

    }

  //Y analog input controls left-right movement
  //joystick RIGHT

    if(analogRead(y_pin) < DEADZONE_RIGHT)
    {
    //First, we use the joystick output to compute the step speed. In this code block, I'll assume that the y_pin value
    //is between DEADZONE_UP and LIMIT_UP as defined above. Since LIMIT_UP is less than DEADZONE_UP,
    //we compute the following:

       scale = (DEADZONE_RIGHT - LIMIT_RIGHT) / 10;   //Scale factor for division
       step_speed = (DEADZONE_RIGHT - x_pin) / scale;   //Converts your joystick RIGHT value into a step speed between
                      //0 and 10

       if(step_speed < 0.5)
          step_speed = 0.5;         //Do this to make sure that when you're out of the dead zone,


    //Now we actually perform your movement as you intended, but now, that movement will be linearly dependent on your joystick position!

       digitalWrite(dir_piny, HIGH); // send motor signal ON axis RIGHT
       digitalWrite(step_piny, HIGH); //send step signal X axis
       delay(step_speed); // delay set by joystick computation above
       digitalWrite(step_piny, LOW); // send motor signal OFF axis RIGHT
       delay(step_speed); // set above

}
}



RS
Sleeping in the hen house doesn't make you a chicken.
User avatar
theropod
RS Donator
THREAD STARTER
 
Name: Roger
Posts: 7529
Age: 66
Male

Country: USA
United States (us)
Print view this post

Re: Arduino Code Question

#20  Postby Calilasseia » Jun 28, 2018 7:30 pm

Having a rethink about this, to make things tidier, here's my attempt at the full program ...

Code: Select all

//********** INITIAL DEFINITIONS **********

// define which pins do what

#define STEP_PINX 2 // D2 is step signal pin for X axis
#define DIR_PINX 3 // D3 is direction control pin for X axis
#define X_PIN A0 // analog input from joystick for X axis
#define Y_PIN A1 // analog input from joystick for Y axis
#define STEP_PINY 5 // D5 is step signal pin for Y axis
#define DIR_PINY 4 // D4 is direction control pin for Y axis

//Define deadzone constants

#define DEADZONE_LEFT 712
#define DEADZONE_RIGHT 312
#define DEADZONE_UP 712
#define DEADZONE_DOWN 312

//Define joystick movement limits

#define LIMIT_LEFT 1000
#define LIMIT_RIGHT 0
#define LIMIT_UP 1000
#define LIMIT_DOWN 0

//Here, define a speed scale in case the motors
//move faster than anticipated.
//Start with a value of 1, but this can be changed
//if needed once the whole thing works!

#define SPEED_SCALE = 1;

//Define this global variable

int step_speed = 5; // stepper speed higher is slower


//********** SETUP ROUTINE **********

//Now the setup routine ...

void setup()
{
delay(1000); // 1 second delay to allow easy drivers to power up

pinMode(DIR_PINX, OUTPUT);
pinMode(STEP_PINX, OUTPUT);
pinMode(DIR_PINY, OUTPUT);
pinMode(STEP_PINY, OUTPUT);

//End setup() function
}


//********** FUNCTION setspeed() **********

//Define the setspeed() function that is called
//within the loop() function to determine the
//stepper motor speed ...

//This function takes the following arguments:

//[1] val = joystick value;
//[2] dz = deadzone value
//[3] lim = extreme limit for joystick movement
//Returns your desired step speed value.

int setspeed(int val, int dz, int lim)
{
//First declare some necessary variables ...

float scale = 0;
float precomp = 0;
int upper = 0;
int lower = 0;
int result = 0;
int dir = 0;
int tmp = 0;


//Now work out which of 'dz' and 'lim' is larger
//We then set 'upper' and 'lower' accordingly. We
//also set the 'dir' variable //to +1 if lim > dz, or
//to  -1 if lim < dz. This is so that we can use 'dir'
//to correctly map our end result onto a positive
//range for the step speed calculation, regardless
//of which way round the arguments are. :)

if (lim > dz)
{
   upper = lim;
   lower = dz;
   dir = 1;
}
else
{
   upper = dz;
   lower = lim;
   dir = -1;

//End if/else (lim > dz)
}

//Now begin the calculation. Make things tidier by
//precomputing everything that can be done in integers,
//before peforming the final conversion to float.
//NOTE: the Arduino compiler provides explicit conversion
//functions, so we can use those instead of casts!

tmp = upper - lower;
scale = float(tmp/ 9);

//Now map your joystick value onto the range
//0-9 inclusive (you'll see why in a moment ...).
// Again, we convert the result back to an int when
//we're finished. This computation maps your
//joystick value on to the range 0-9, with 0
//corresponding to just outside the dead zone, and
//9 corresponding to the extreme edge movement
//of the joystick.

tmp = (val - lower) * dir;
precomp = float(tmp) * scale;
result = int(precomp);

//Now map onto the range 10 to 1 backwards.
//Because your step_speed variable is a delay,
//and you want the delay to be LONGER for
//small joystick movements, and SHORTER
//for large joystick movements, we now reverse
//the above 0-9 mapping to achieve this effect.
//Now, small joystick movements will generate
//a 10, and large joystick movements a 1, with
//appropriate values between for intermediate
//movements. :)

result = 10 - result;

//Now multiply this by a scale factor in case it's needed. Use #define SPEED_SCALE 1 outside the function to create the scale speed, and if you need to increase
//this value because things are moving too fast, you can always increase it after testing!

result = result * SPEED_SCALE;

return(result);

//End setspeed() function
}


//********** LOOP FUNCTION **********

//Now we move on to the loop() function, which will look like this:

void loop()
{

//Test for joystick left:

if (analogReady(X_PIN) > DEADZONE_LEFT)
{
   step_speed = setspeed(X_PIN, DEADZONE_LEFT, LIMIT_LEFT)

   //Now we actually perform your movement as you intended,
   //but now, that movement will be linearly dependent on
   //your joystick position!

   digitalWrite(DIR_PINX, LOW); // move motor clockwise
   digitalWrite(STEP_PINX, HIGH); //send step signal X axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(STEP_PINX, LOW); // stop step signal X axis
   delay(step_speed); // set above

//End if (X_PIN > DEADZONE_LEFT)
}

//Now test for joystick right ...

if (analogReady(X_PIN) < DEADZONE_RIGHT)
{
   step_speed = setspeed(X_PIN, DEADZONE_RIGHT, LIMIT_RIGHT)

   //Now we actually perform your movement as you intended,
   //but now, that movement will be linearly dependent on
   //your joystick position!

   digitalWrite(DIR_PINX, HIGH); // move motor anti-clockwise
   digitalWrite(STEP_PINX, HIGH); //send step signal X axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(STEP_PINX, LOW); // stop step signal X axis
   delay(step_speed); // set above

//End if (X_PIN < DEADZONE_RIGHT)
}

//Now test for joystick up:

if (analogReady(Y_PIN) > DEADZONE_UP)
{
   step_speed = setspeed(Y_PIN, DEADZONE_UP, LIMIT_UP)

   //Now we actually perform your movement as you intended,
   //but now, that movement will be linearly dependent on
   //your joystick position!

   digitalWrite(DIR_PINY, LOW); // move motor clockwise
   digitalWrite(STEP_PINY, HIGH); //send step signal X axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(STEP_PINY, LOW); // stop step signal X axis
   delay(step_speed); // set above

//End if (Y_PIN > DEADZONE_UP)
}

//Now test for joystick down ...

if (analogReady(Y_PIN) < DEADZONE_DOWN)
{
   step_speed = setspeed(Y_PIN, DEADZONE_DOWN, LIMIT_DOWN)

   //Now we actually perform your movement as you intended,
   //but now, that movement will be linearly dependent on
   //your joystick position!

   digitalWrite(DIR_PINY, HIGH); // move motor anti-clockwise
   digitalWrite(STEP_PINY, HIGH); //send step signal X axis
   delay(step_speed); // delay set by joystick computation above
   digitalWrite(STEP_PINY, LOW); // stop step signal X axis
   delay(step_speed); // set above

//End if (Y_PIN < DEADZONE_DOWN
}

//End loop() function
}



The comments in the code should make things clear, but there's a couple of points I want to add here. I tend to put comments on certain end braces of my code, to remind me that I've hit the end of an IF statement (which is VERY useful if you have a number of nested IFs!), or I've reached the end of a function definition. I usually write a bare bones IF statement, with the comment on the last brace, then fill in the details of the IF once the comment is in place, so that every time I insert another IF in a nested IF, I can keep track of which IF I'm working on when debugging. Likewise, writing a bare bones function definition such as:

Code: Select all
function myfunction()
{

//End function
}


then filling in the details, ensures I never have dangling braces that screw up compilation. Which comes in VERY handy when you start working on long programs!

Now, I don't know in advance if all of this is going to work, but if you have a debugger on hand and can trace the code, then you'll be able to see it in operation, and see what I intended to happen, even if it doesn't actually behave that way, and you'll be able to correct any of my mistakes that you hit along the way.

Meanwhile, addressing some of your issues above from your latest compilation ... I mistakenly computed step_speed to be small for small joystick movments, and large for large josytick movements in my original first attempt, which this latest version now corrects, and reverses the step_speed value correctly. As to why your y axis is misbehaving while your x axis is not misbehaving, it might be worth checking independently what values your joystick is generating for that axis, in case I have the limit and deadzone values completely screwed.

And with that, I'll return to my JavaScript! :)
Signature temporarily on hold until I can find a reliable image host ...
User avatar
Calilasseia
RS Donator
 
Posts: 22035
Age: 58
Male

Country: England
United Kingdom (uk)
Print view this post

Next

Return to General Science & Technology

Who is online

Users viewing this topic: No registered users and 1 guest