Rusty Programmer needs advice

Hi guys and gals, Its been a long time since I done much programming. I have however cobbled together some code trying to use the state principle. As you can see my code is version 1.97 as I couldnt post it up till I knew it worked. Well it almost works properly.

The concept was to use the basic DC motor control circuit and use a sine wave pattern to drive it allowing the user to pick betweeen 1 and 100 cycles in a minute. After validating the selection the motor cycle value the motor would run for 1 minute and then stop. The user would then be able to select another value and it would run again for a minute.

Issues I have had were intiger, unsigned long and float variables. Initialy the motor didnt run in a sine wave pattern because of trying to use to long a command Line 93 used to be FloatStepcount = float(StepCount/1000); this didnt work it only transposed the integer part of the equation so it was mostly 0.00 or 1.00 etc. I'd set a variable up as an integer instead of an unsigned long so my timer reset didnt used to work.

Here is my finished code, could you good people please peruse it and offer constructive critisism as to improvements.

//Sine wave motor driver ver 1.97
//J.Anslow 02/02/17

//setup variables
const int motorPin = 3; //pin to connect motor control to
int TimeDelay = 0; // time delay between each motor speed increase
int Amplitude = 1; // allow for strength alteration later version
int IntSinWave = 0;
int MotorChangeTime = 10;// for upddating motor speed every 10th of a second
int StepCount = 0;
int MappedChange = 0;

boolean DisplayMessageOnce = false; //for use in SetTimeDelay() to print message only once
boolean TimeDelaySet = false; //set to true to run SetTimeDelay() only once
boolean HasTimePassed = false;  //for use in ResetTimer()
boolean DoOnce = false;

unsigned long CurrentMillis = 0;
unsigned long PreviousMotorMillis = 0;
unsigned long SetStartTimer = 0; //for use in ResetTimer()

const float Pi = 3.142;
float FreqPerMin = 6; //set manually for now will allow for change in further version
float Omega = 0.00; //part of the sine wave formula
float FloatSinWave = 0.00;
float FloatStepCount = 0;


void setup()
{
  pinMode(motorPin, OUTPUT); //activate pin as an output
  Serial.begin(9600);  //activate serial monitor control for help debugging
}

void loop()
{
  if (TimeDelaySet)  //if the time delay value has not been set the main body of the program will not run.  SetTimeDelay() runs instead
  {
    //in this version we will attempt to run the motor from 20%(lowest value to start motor) to 100% using a sign wave pattern
    // this will run for 1 minute before stopping and resetting to initial state
    CurrentMillis = millis(); // sets a constant value to use in any further functions
    ResetTimer();
    if (DisplayMessageOnce && TimeDelaySet)
    {
      MotorSpeedChange();
    }
  }
  else
  {
    SetTimeDelay();
    PreviousMotorMillis = millis();
  }

}

void ResetTimer()
{
  if (SetStartTimer == 0)
  {
    SetStartTimer = millis();
  }
  else
  {
    if ((millis() - SetStartTimer) >= 60000)
    {
      SetStartTimer = 0;
      analogWrite(motorPin, 0);
      DisplayMessageOnce = false;
      TimeDelaySet = false;
      DoOnce = false;
      StepCount = 0;
      Serial.println("1 minute elapsed");
    }
  }
}

void MotorSpeedChange()
{
  if (!DoOnce)
  {
    float FreqPerSec = 0;
    FreqPerMin = float(TimeDelay);
    FreqPerSec = 1 / (60 / FreqPerMin);
    Serial.println(FreqPerSec);
    Omega = (2 * Pi) * FreqPerSec;
    DoOnce = true;
  }

  if (CurrentMillis - PreviousMotorMillis >= MotorChangeTime)
  {
    PreviousMotorMillis += MotorChangeTime;
    StepCount += MotorChangeTime;
    FloatStepCount = float(StepCount);  //had to change the int to a float first
    FloatStepCount = FloatStepCount / 1000; //then divide by the 1000 before it becomes an actual floating value
    FloatSinWave = Amplitude * sin(Omega * FloatStepCount);
    IntSinWave = int(FloatSinWave * 1000);
    MappedChange = map(IntSinWave, -1000, 1000, 50, 255);
    analogWrite(motorPin, MappedChange);
  }
}

void SetTimeDelay()
{
  if (!DisplayMessageOnce) // this checks to see if message has been printed
  {
    Serial.println("Input motor cycles: 1 to 100");
    DisplayMessageOnce = true; //this change ensures if statement does not run again
  }
  if (!TimeDelaySet) //checking for valid input
  {
    if (Serial.available()) //check to see if there has been an input
    {
      TimeDelay = Serial.parseInt(); //ensures only numerical values are passed
      if (TimeDelay >= 1 && TimeDelay <= 100)  // validates input
      {
        TimeDelaySet = true;  // setting to true stops SetTimeDelay() from being run again
        Serial.print(TimeDelay);
        Serial.print("   ");
        Serial.println("thank you for valid input");
      }
    }
  }
}

Also is there a some way I can check my variables and flow of my program other than putting Serial.print commands everywhere. would be nice and probably save me a lot of time.

I also noticed a small problem when running the motor over a 1 cycle per minute it did not seem to follow the sine curve properly seemed to have a couple of blips.

One last thing I used the power supply to plug into my breadboard. I didnt realise the jumpers altered the voltage a 3.3v and a 5v I was running my motor on the 3.3v side and i wondered why it was so slow :slight_smile: :o

I was also going to add a picture of my board set up but I couldnt figure out how to do this .

Sorry if Ive been slightly long winded.

jon_a:
Also is there a some way I can check my variables and flow of my program other than putting Serial.print commands everywhere. would be nice and probably save me a lot of time.

That is the usual way.

One last thing I used the power supply to plug into my breadboard. I didnt realise the jumpers altered the voltage a 3.3v and a 5v I was running my motor on the 3.3v side and i wondered why it was so slow

I don't understand. You probably need to post a diagram - but just pencil and paper, NOT Fritzing.

I also noticed a small problem when running the motor over a 1 cycle per minute it did not seem to follow the sine curve properly seemed to have a couple of blips.

I doubt if it is possible to comment on that without a much more detailed description because I can't test your code without your equipment.

...R

The attached picture is my circuit diagram and a picture of my board with the jumper pegs highlighted.

I do not see that the power supply for the motor is grounded to the Arduino.

You could more fully embrace the state principle by defining clear states and acting on the states in loop(). For example, your states could be waiting for input, preparing to run motor and running motor. Any setup code can be run before changing state, so you could eliminate flag variables like "doOnce". I think this would make your code a lot easier to read and maintain.

const int WAITING_STATE = 0;
const int STARTING_STATE = 1;
const int RUNNING_STATE = 2;

int state = WAITING_STATE;

void setup()
{

  /* prompt for input */
}

void loop()
{
  switch(state)
  {
  case WAITING_STATE:

    /* if there has been input, set state = STARTING_STATE */
    break;

  case STARTING_STATE:

    /* start motor, set state to RUNNING_STATE */
    break;

  case RUNNING_STATE:

    // if it's time to stop, prompt for input and set state = WAITING_STATE */
    break;

  default:
    break;

  }

}

PaulS:
I do not see that the power supply for the motor is grounded to the Arduino.

I'm confused at this statement

jon_a:
I'm confused at this statement

You appear to be supply the motor 5V, at the bottom. The ground side of that 5V supply must be connected to the Arduino ground.

Pretend that you are an electron. You are standing at the + side of the power supply. On that picture, trace the path to the non-existent ground side. Oh, wait, you can't do that. Well, current can't flow if there is not a complete path from + to - (ground).

Images from Reply #2 so we don't have to download them. See this Image Guide

...R

The 10 ohm resistor on the transistor base is way to low to do any good. You need to limit the base current to around 20mA for the safety of the output pin. 180 or 220 would be safe choices.

FloatSinWave = Amplitude * sin(Omega * FloatStepCount);
IntSinWave = int(FloatSinWave * 1000);
MappedChange = map(IntSinWave, -1000, 1000, 50, 255);
analogWrite(motorPin, MappedChange);

Why not just:

analogWrite(motorPin, 152.5 + 102.5 * Amplitude * sin(Omega * FloatStepCount)  );

Amplitude*sin(x) is +/- 1, times 102.5 is +/- 102.5, plus 152.5 is the range 50 to 255. Let the compiler do the job of converting those floats to integers.

Another issue is that output from the pin is not a constant coltage - it is pulse-width modulated. Even if you switch it through a transistor, a pulse-width modulated signal is going to do horrendous things if you try to run it through a motor coil. I imagine you need some sort of smoothing capacitor network after the transistor, or just do what everyone else does and purchase a DC motor driver module.

Why not just

Because the local variables make it easy to debug. Complex code like yours is OK when you KNOW that the calculations are performed correctly. It is terrible when it doesn't work, and you can't figure out why.

@PaulS the gnd pin of the arduino is connected to the -ve rail on the breadboard it does however look like the red cable is attached to iy but it is not. There is definitley grounding going on.

@Blue Eyes thank you for that I will have a look at the switch statement and try and fit it in. I will also look at my variable naming policy.

@Robin2 thanks for the link to the image guide it'll come in real handy.

@groundfungus thanks for that improvement on my circuit. I just followed the diagram set out by elegoo.com for a basic motor control.

@PaulMurratCbr thanks for the coding tip. I split it down because of the issue with int and float variables and to trouble shoot it. I'll try implementing your code. in V2.00 there will be the option to set low and high motor speeds. I have also just recieved a dc motor module I got a dual h bridge L298N as I wish to run 24v motors eventually.

Thanks again guys n gals for your input it has been recieved greatfuly. No doubt over the coming months you'll see a lot of help me posts as I have a project in mind. Which the way my ind works may end up an epic adventure.

Just FYI for the future.

I got a dual h bridge L298N as I wish to run 24v motors eventually.

The L298 is ancient technology. It is very inefficient as it drops over 2V at 2A (4W of power) . So 10V of your supply makes it to the motor and the rest is wasted as heat. There are many modern MOSFET output drivers that are much more efficient. Polulu has a wide range.