Jump to content

Firmware


jayjay23

Recommended Posts

the logic, at least to my brain says - if sector is less than 6, then add one, else, if sector = 6, then sector = 1, which would mean instead of returning 6, it would return one.

 

if I am wrong, my code will still return the same result as your code, it just does it a little differently.  I'm pretty sure I'm right... (but I have been wrong before)

I think my change is either the same as or better than.  Couldn't hurt to try.

 

Other than that the code seems solid.  I didn't look at the individual cases closely, if the motor moved properly for the most part on the original code, I would guess it's right.  Skipping case 6 (or 1 when decrement) would probably still result in the motor moving, but moving to the wrong position, and not being in sync.

Looking at your code it's the only explanation for the sound and vibration you are seeing.

 

can you give it a shot and upload the result?  I'm most interested in vibration and the noises it makes rather than actually balancing.

Edited by chriscalandro
Link to comment
Share on other sites

I don't see anything wrong with the original increment/decrement_sector -functions. 

unsigned int increment_sector (unsigned int sector)
{
  if (sector < 6)
  {
    sector++;
  }

  else // sector = 6
  {
    sector = 1;
  }

  return sector;
}

If you pass in 6 (or above), it will fall into the else-block and return 1, otherwise the first if()-block will catch it (even if it's 0), and increment it by one before returning it.

 

unsigned int decrement_sector (unsigned int sector)
{
  if (sector > 1)
  {
    sector--;
  }
  else // sector = 1
  {
    sector = 6;
  }

  return sector;
}

Similarly here, passing in value above 1 will decrement the value before returning it, otherwise it will return 6 (for 0 or 1).

  • Upvote 1
Link to comment
Share on other sites

Is this still about the wheel "jolting" back and forth while trying to maintain balance? Didn't the motor control work before just fine (ie. just running it forwards and backwards)? I'd expect the problem to be the PID-loop or too high motor output then, but that's just guessing... I did notice that my robot did similar motions when the PID was off (overshooting corrections). Have you tried to raise the motor output more gradually?

 

Link to comment
Share on other sites

That is exactly what I suggested.  If my suggested error actually works fine, then I don't see any issue with the motor driver software.

As suggested earlier in the thread, start with a P multiplier of 0 and slowly increase.

a low number should give really sloppy balance, a high number should over-calculate....

  • Upvote 1
Link to comment
Share on other sites

I tried many values on the PID. I started with 0 for I and D.

The system should get to a state to make the motor stopped and I just tried that situation but the motor is not stopped... I feel the motor control is not good enough. Something is missing... I feel that the step between each sector is to big and so is not possible to stop the motor in the middle space which make not possible to stop and fine control the wheel.

This is the motor running/incrementing sector every second:

 

Edited by electric_vehicle_lover
Link to comment
Share on other sites

I think the P value is the one you want to mess with, on my robots that is usually where I started.

 

While I don't know a lot about brush less motors I do know a bit about stepper motors, which seem to be very similar.  On stepper motors you can do microstepping.  Does this translate to brushless DC motors?

Link to comment
Share on other sites

I fixed I and D to zero and just tested the P.

Microstepping, I never read something about brushless - every application note just refers the 6 steps. But yes, the original firmware seems to have high  resolution control. But the signals seems easy to understand and I tried to mimic them. I looked at the signals of 2 different generic EUCs, that I documented on the wiki.

 

Link to comment
Share on other sites

Quickly skimming through the code in Github, I noticed this:

duty_cycle = (current_error + integral_term + derivative_term);
duty_cycle *= KP;  //<--  * 200.0 ?

motor_set_duty_cycle ((int) duty_cycle);


Then in the pwm-control (where that call finally goes):

 

void pwm_set_duty_cycle (int value)
{
//#define DUTY_CYCLE_MAX_VALUE    1000 //
//#define DUTY_CYCLE_MIN_VALUE    -999 //
#define DUTY_CYCLE_MAX_VALUE    200 //
#define DUTY_CYCLE_MIN_VALUE    -200 //

 

Maybe I'm misreading this, as I don't have a clear picture of the entire code-base and details, but wouldn't that suggest that if the total error output of PID is over 1.0, it always shoots the PWM to the max value?

 

   
   
   
  • Upvote 1
Link to comment
Share on other sites

4 minutes ago, chriscalandro said:

The link I posted describes what I guess is really the equivalent of microstepping.  It breaks the 6 steps down into 360 steps to turn the square wave into more of a sine wave.

Thanks for the link, definitely have to look up implementing this at some point. Currently my 3-phase driver is in pieces, as I earlier had to take one of the breadboards for another project, then rebuilt the parts I had dismantled, did some mistake and ended up frying one of my Arduinos... whoopsie :D

Edited by esaj
Link to comment
Share on other sites

@esaj, in the end, the duty-dycle value should be a minimum. I did a code to make duty-dycle at minimum positive and after negative, in loop and expecting the motor to be blocked/stopped and it didn't worked.

I will now look to the sine wave @chriscalandro did mention!! I want first to be ale to control the motor with high resolution. I think I need to be able to run very slow and with high resolution the motor.

Link to comment
Share on other sites

Here is the actual code.  It's written for arduino, but it seems it would be easy to port it to the ST.

 

duty cycle should be driven dynamically, per winding as part of the stepping, not as an overall value.  That is our mistake.  Suddenly BLDC motors make sense to me...

 

const int EN1 = 5;
const int EN2 = 6;
const int EN3 = 7;
 
const int IN1 = 9;
const int IN2 = 10;
const int IN3 = 11;
 
 
// SPWM (Sine Wave)
//const int pwmSin[] = {127, 138, 149, 160, 170, 181, 191, 200, 209, 217, 224, 231, 237, 242, 246, 250, 252, 254, 254, 254, 252, 250, 246, 242, 237, 231, 224, 217, 209, 200, 191, 181, 170, 160, 149, 138, 127, 116, 105, 94, 84, 73, 64, 54, 45, 37, 30, 23, 17, 12, 8, 4, 2, 0, 0, 0, 2, 4, 8, 12, 17, 23, 30, 37, 45, 54, 64, 73, 84, 94, 105, 116 };
 
 
/// SVPWM (Space Vector Wave)
//const int pwmSin[] = {128, 147, 166, 185, 203, 221, 238, 243, 248, 251, 253, 255, 255, 255, 253, 251, 248, 243, 238, 243, 248, 251, 253, 255, 255, 255, 253, 251, 248, 243, 238, 221, 203, 185, 166, 147, 128, 109, 90, 71, 53, 35, 18, 13, 8, 5, 3, 1, 1, 1, 3, 5, 8, 13, 18, 13, 8, 5, 3, 1, 1, 1, 3, 5, 8, 13, 18, 35, 53, 71, 90, 109};
const int pwmSin[] = {128, 132, 136, 140, 143, 147, 151, 155, 159, 162, 166, 170, 174, 178, 181, 185, 189, 192, 196, 200, 203, 207, 211, 214, 218, 221, 225, 228, 232, 235, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 253, 252, 252, 251, 250, 250, 249, 248, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 249, 250, 250, 251, 252, 252, 253, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 253, 252, 252, 251, 250, 250, 249, 248, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 235, 232, 228, 225, 221, 218, 214, 211, 207, 203, 200, 196, 192, 189, 185, 181, 178, 174, 170, 166, 162, 159, 155, 151, 147, 143, 140, 136, 132, 128, 124, 120, 116, 113, 109, 105, 101, 97, 94, 90, 86, 82, 78, 75, 71, 67, 64, 60, 56, 53, 49, 45, 42, 38, 35, 31, 28, 24, 21, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24, 28, 31, 35, 38, 42, 45, 49, 53, 56, 60, 64, 67, 71, 75, 78, 82, 86, 90, 94, 97, 101, 105, 109, 113, 116, 120, 124};
 
int currentStepA;
int currentStepB;
int currentStepC;
int sineArraySize;
int increment = 0;
boolean direct = 1; // direction true=forward, false=backward
 
//////////////////////////////////////////////////////////////////////////////
 
void setup() {
 
  setPwmFrequency(IN1); // Increase PWM frequency to 32 kHz  (make unaudible)
  setPwmFrequency(IN2);
  setPwmFrequency(IN3);
 
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  
  pinMode(EN1, OUTPUT);
  pinMode(EN2, OUTPUT);
  pinMode(EN3, OUTPUT);
 
 
  digitalWrite(EN1, HIGH);
  digitalWrite(EN2, HIGH);
  digitalWrite(EN3, HIGH);
  
 
  sineArraySize = sizeof(pwmSin)/sizeof(int); // Find lookup table size
  int phaseShift = sineArraySize / 3;         // Find phase shift and initial A, B C phase values
  currentStepA = 0;
  currentStepB = currentStepA + phaseShift;
  currentStepC = currentStepB + phaseShift;
 
  sineArraySize--; // Convert from array Size to last PWM array number
}
 
//////////////////////////////////////////////////////////////////////////////
 
void loop() {
 
  analogWrite(IN1, pwmSin[currentStepA]);
  analogWrite(IN2, pwmSin[currentStepB]);
  analogWrite(IN3, pwmSin[currentStepC]);  
  
  if (direct==true) increment = 1;
  else increment = -1;    
 
  currentStepA = currentStepA + increment;
  currentStepB = currentStepB + increment;
  currentStepC = currentStepC + increment;
 
  //Check for lookup table overflow and return to opposite end if necessary
  if(currentStepA > sineArraySize)  currentStepA = 0;
  if(currentStepA < 0)  currentStepA = sineArraySize;
 
  if(currentStepB > sineArraySize)  currentStepB = 0;
  if(currentStepB < 0)  currentStepB = sineArraySize;
 
  if(currentStepC > sineArraySize)  currentStepC = 0;
  if(currentStepC < 0) currentStepC = sineArraySize;
  
  /// Control speed by this delay
  delay(10);
 
}
 
 
void setPwmFrequency(int pin) {
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | 0x01;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | 0x01;
    }
  }
  else if(pin == 3 || pin == 11) {
    TCCR2B = TCCR2B & 0b11111000 | 0x01;
  }
}
Edited by chriscalandro
Link to comment
Share on other sites

13 minutes ago, electric_vehicle_lover said:

@esaj, in the end, the duty-dycle value should be a minimum. I did a code to make duty-dycle at minimum positive and after negative, in loop and expecting the motor to be blocked/stopped and it didn't worked.

current_error = angle - INITIAL_ANGLE; //error

If those are in degrees, anything at or above 1.0 degrees of error will always set the PWM to maximum allowed value, which could easily lead it to overshooting the 0-position, considering how powerful the motor is (at least when only balancing itself)? I didn't notice the current_error being divided or anything, it seems it's directly used in the final duty-cycle calculation:

duty_cycle = (current_error + integral_term + derivative_term);
duty_cycle *= KP;

 

Not saying I'm definitely right, this just seems suspicious to me ;)

 
   
 
Link to comment
Share on other sites

So if I understand this properly - you should not use the duty cycle as a way to drive the motor to the next sector, but should use it more as a way to control the motor angle within sectors.  as one sector duty cycle decreases the next sector duty cycle increases creating a smoother transition between windings.  Using the above example each increment or decrement should move the motor by 1 degree.

 

This should give higher definition the the motor.  I'm not sure about a delay controlling speed between steps though.  that seems wrong to me...

 

but whether or not this driving method is correct or not, using the current driver and PID we should be able to at least get a reasonable balance withing the motor definition we have driving each winding at whatever duty cycle value.  There will be deviation, but it should still work.

Edited by chriscalandro
  • Upvote 1
Link to comment
Share on other sites

I have spent a lot of time last night reading data sheets, BLDC examples, etc.  I did notice that as long as you are using an ST chip for the final product, all of their libraries are free to use.  As mentioned earlier, it's believed that most inverse pendulum device manufacturers that use ST micro controllers use their libraries.

 

This project can still be open source AND use the ST motor control library as long as we continue to use ST chips, so the question is

 

Why don't you just use that?

 

From what I can tell it has easy customization, does closed loop control with PID implementation, and control is straight forward. 

  • Upvote 1
Link to comment
Share on other sites

Ok, I tested the motor running sinewave control, openloop, as explaining here: http://www.berryjam.eu/2015/04/driving-bldc-gimbals-at-super-slow-speeds-with-arduino/

Here is the code: https://github.com/generic-electric-unicycle/firmware/commit/30921bdee2b4c2819c2d88feb3a3206defb2aeaa

Here is the motor running:

 

And now 2 videos to let us compare the sinewave control over the 6 steps control.

And now the motor running sinewave, one "loop/step" each 1 second:

 

And the motor with 6 steps control in openloop, 1 second each step:

Edited by electric_vehicle_lover
  • Upvote 2
Link to comment
Share on other sites

Seems I found the correct control method for the motor!! -- Sine Wave Space Vector.

I just have code to run the motor in open loop (without using any signal from the hall sensors or back emf) and at low speed.

Previously I were controlling the motor with 6 steps and fixed PWM. Now I tested in open loop the Sine Wave control and after the Sine Wave Space Vector - please compare the motor noise with this both ways to control, running at the same speed and duty-cycle:

Sine Wave control:

 

Sine Wave Space Vector:

Sine Wave Space Vector is almost silent!!

I will now start implementing the code I had before to run the motor forward and backward, accelerating/controlling duty-cycle using the potentiometer.

I am not sure that this control method will help on the balance/low speed/stop motor, as is not possible to use Sine Wave when the motor is stopped or near.

Edited by electric_vehicle_lover
  • Upvote 2
Link to comment
Share on other sites

11 hours ago, electric_vehicle_lover said:

Seems I found the correct control method for the motor!! -- Sine Wave Space Vector.

I just have code to run the motor in open loop (without using any signal from the hall sensors or back emf) and at low speed.

Previously I were controlling the motor with 6 steps and fixed PWM. Now I tested in open loop the Sine Wave control and after the Sine Wave Space Vector - please compare the motor noise with this both ways to control, running at the same speed and duty-cycle:

Sine Wave control:

 

Sine Wave Space Vector:

Sine Wave Space Vector is almost silent!!

I will now start implementing the code I had before to run the motor forward and backward, accelerating/controlling duty-cycle using the potentiometer.

I am not sure that this control method will help on the balance/low speed/stop motor, as is not possible to use Sine Wave when the motor is stopped or near.

@electric_vehicle_lover Good work ! However let me say that was exactly which I have tried to suggest to investigate in one of my last post speaking about sinewave vs trapezioidal .

Again .. compliments :)

  • Upvote 1
Link to comment
Share on other sites

20 hours ago, electric_vehicle_lover said:

 

I am not sure that this control method will help on the balance/low speed/stop motor, as is not possible to use Sine Wave when the motor is stopped or near.

About this dubt, I had never noticed before now, it is written here under the controller image before the sinewave image :D

http://www.iamips.com/pro_zero.php

"Optimization of power supply systems, independent research and development FOC vector control, motor precision adjustment, understanding better output power scheme."

Of course you board is different ..

  • Upvote 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...