BLDC Control Using Encoder and Encoder Zero Crossing

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys ,

I would like to sense commutation sequence using encoder(1024 resolution) for bldc motor and if current state - previous state >= a then motor can move for other sequence but if encoder value change 0-1023 then I cant find the difference.For example if motor position in 10 enc value and I controled the motor to move other sequence and new value 1000 now 1000-10 is problem. What is best solution for it ,I tried asin(sin(enc_val)) but still doesnt work well?

 

deltaT = (180/PI)*Keep_Enc_Val_Rad();
	if((fabs(deltaT - tut) >= thetaMechanicalRad-2))
	{
		tut = (180/PI)*Keep_Enc_Val_Rad();
		say=say+1;
		
		if(dir)  Set_DutyCycle(cw_table[say],pwm);
		if(!dir) Set_DutyCycle(ccw_table[say],pwm);
		
		if(say==5) say = -1;
		//delay_ms(10);
		do
		{
			test = (180/PI)*Keep_Enc_Val_Rad();
		}while( (fabs(test - tut) <= (thetaMechanicalRad-1)) );
		//
	}
	
	
	
	
	double Keep_Enc_Val_Rad(void)
{
	double deltaTheta=0;
	uint16_t enc=0;
	enc = qdec_get_position(&encConfig);
	deltaTheta = (double)enc*ANGLE_RES_RAD;
	deltaTheta = asin( sin(deltaTheta));
	
	return deltaTheta;
}

 

This topic has a solution.
Last Edited: Thu. Nov 14, 2019 - 06:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are using an encoder to read the position, what else do you need?   Why would you start throwing in trig functions?

Can you fully state on paper what you are trying to do?

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Fri. Oct 25, 2019 - 08:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My aim is finding next state.My processes are these.

 

First I energized the motor in specific states like these codes below. Then starting the codes that I sent before.And I decide if motor moved next state to measure the difference between current state and new state,but it doesn't work with these codes.I cant understand where is my mistake. arcsin(sin()) aim is to get position as angle with right way,For example if encoder show 10  arsin(sin(10*(360/1024)))= 3.515.If encoder show 1000   ,arsin(sin(100*(360/1024)))= -8.437 and result = -8.437-3.515; so why codes doesnt work.How other engineer drive motors.

for(int8_t j=0;j<6;j++)
	{
		Set_DutyCycle(ccw_table[j],1000);
		delay_ms(50);
	}
	for(int8_t j=5;j>=0;j--)
	{
		Set_DutyCycle(ccw_table[j],1000);
		delay_ms(50);
	}
	delay_ms(500);
qdec_reset_position(&encConfig); 
	tut_u = qdec_get_position(&encConfig);
	say = say+1;
	Set_DutyCycle(ccw_table[say],500);
	delay_ms(500);
	pwm = 500;

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Last Edited: Fri. Oct 25, 2019 - 08:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It makes no sense to convert encoder angle into degrees or radians for the commutation code. Everything is in encoder angle. In your previous thread i suggested you solve the commutation and put the solution into an array. You would have two arrays - forward and reverse. Think of how a physical commutator works. If you want to alter the commutation angle, you add or subtract encoder counts modulus 1024.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have an encoder to read, then you know the position...no need for any extremely slooooow trig function(s) to find the position!

 

I cant understand where is my mistake. arcsin(sin()) aim is to get position as angle with right way

The encoder position IS the angle...why do you need any other type of angle? You should not.   You will already know the next state is at positions 47, 233, 467, 588 or whatever the desired positions are.  This was mentioned by Kartman

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Fri. Oct 25, 2019 - 04:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes you guys right, I changed the codes like that in right way.

encoder_u = qdec_get_position(&encConfig);
	encoder_i = (int32_t)encoder_u;
	if(encoder_u==0 || encoder_u==1 || encoder_u==1023) Set_DutyCycle(ccw_table[5],pwm);
	
	if(!dir)
	{
		result_i = tut_i - encoder_i;
		if(result_i < 0)
		{
			result_i += 1023;
//Set_DutyCycle(ccw_table[5],pwm);
		} 
	
	}


	if(result_i >= 34 )
	{
		
		tut_u = qdec_get_position(&encConfig);
		tut_i = (int32_t)tut_u;
		say=say+1;
		if(!dir) Set_DutyCycle(ccw_table[say],pwm);
		//if(dir)  Set_DutyCycle(cw_table[say],pwm);
		if(say==5) say = -1;
	}

But now ,still doesnt work stable,the motor getting fast in time and suddenly moto buzz then getting slow.I think it is about encoder resolution because normally every commutation is 34.133 and in time this error getting high in a few revolution and this is why commutation time get in wrong time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can’t make much sense of your code. First up learn about binary modulus arithmetic. For 10 bits, just AND the unsigned result with 0x3ff.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
encoder_u = qdec_get_position(&encConfig);
encoder_i = (int32_t)encoder_u;
	
	
	
	if(!dir)
	{
		result_i = tut_i - encoder_i;
		
		//This part control if encoder pass the 0 to get right value
		// 0 - 900 = -900 + 1023 = 123
		if(result_i < 0)
		{
			result_i += 1023;
		// I need calibration in here
			
		} 
	
	}

    //This part control if it is ok to drive next commutation.
    //34 is for next commutation 12 degree.30*12=360 degree
    // 30 commutation = 1 revolution
	if(result_i >= 34 )
	{
		
		tut_u = qdec_get_position(&encConfig);
		tut_i = (int32_t)tut_u;
		say=say+1;
		if(!dir) Set_DutyCycle(ccw_table[say],pwm);
		//if(dir)  Set_DutyCycle(cw_table[say],pwm);
		if(say==5) say = -1;
		cnt++;

	}

Ok I got rid of the extra codes that I tried before. And I added comments.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
//This part control if encoder pass the 0 to get right value
		// 0 - 900 = -900 + 1023 = 123
		if(result_i < 0)
		{
			result_i += 1023;
		// I need calibration in here
			
		} 
		
	// don't use signed variables!
	
	//this will wrap around cleanly
	result_u &= 0x3ff;
	

Still, I have no idea of what you're doing. what does the ccw_table do? I would have the cw_table and ccw_table an array of 1024 entries. Each entry has the pwm values for each of your phases. No unsigned to signed shenanigans. No creeping error.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

uint8_t ccw_table[6] ={0x18, 0x09, 0x21, 0x24, 0x06, 0x12};
uint8_t cw_table[6]={0x18, 0x12, 0x06, 0x24, 0x21, 0x09};

 

These are that I should give energy appropriate pins.pwm is constant 1000 you can assume.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 and in time this error getting high in a few revolution and this is why commutation time get in wrong time

What are you referring to?  The encoder gives the position & there should be no accumulating error...each rotation is exactly the same as the previous.

 

Say an encoder gave 30 values per rotation & you wanted to switch every 7.3 steps (0 7.3, 14.6, 21.9, 29.2, 36.5 (6.5), 43.8 (13.8), 51.1 (21.1), 58.4 (28.4), 65.7 (5.7)....)

01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 01 02 03 04 05 06 07 08 09 10 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 39 30 01 02 03 04 05 06 07

                            S                                   S                              S                               S                                   S                          S                              S                              S                                   S

no error is accumulating ...the average step size is maintained at 7.3 (over many steps)  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

current = get_encoder();

 

 

if(dir) result = pre - current;

else if (!dir) result = current - pre;

if(i<0) result = result + 1023;

 

that is the solution.Thank you for helping.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Emrah Duatepe wrote:
if(i<0) result = result + 1023;

 

I mentioned earlier about finite precision binary. Try result &= 0x03ff;