FORUM

Reading motor speed...
 
Notifications
Clear all

[Solved] Reading motor speed while in digital closed-loop torque control mode

16 Posts
2 Users
2 Likes
999 Views
Forum 1
(@lokmanho)
Active Member
Joined: 2 years ago
Posts: 7
Topic starter  

Hi,

I am trying to operate a configuration in which the SOLO is running in torque control mode, being commanded via UART by an Arduino which has the task of closing the speed loop. While I can quite reliably communicate with the SOLO using the Arduino library, I am having trouble with obtaining the motor speed signal. To construct the motor speed signal, I have to combine:

- the magnitude of the motor speed obtained by calling GetSpeed(), which in turn sends the command code 0x96

- the rotational direction of the motor obtained by calling GetDirectionRotation(), which in turns sends the command code 0xA9

While this works properly when the SOLO is running in speed control mode, I noticed that when in torque control mode, the rotational direction signal returns the sign of the quadrature current instead. I suspect that this is not intentional, since the quadrature current is already returned as a signed number. As it stands, I can't figure out a way to obtained the signed speed of the motor, which I need for closed-loop speed control.

Could you please confirm my observation and suggest a solution? Thank you!

By the way, seeing that a long in Arduino is a 4-byte integer and none of our motors are likely to spin at >1 billion rpm, wouldn't it make sense to return the motor speed also directly as a signed long (long is already the return type) incorporating direction information? As an added bonus, it would save me one message per control cycle 🙂

I have a SOLO UNO with the B08 firmware. The Arduino MEGA is executing the speed loop at a cycle time of 2ms.

Regards,

Lok Man


   
Quote
Forum 1
(@lokmanho)
Active Member
Joined: 2 years ago
Posts: 7
Topic starter  

I forgot to mention that I'm running a BLDC motor in hall sensor mode.


   
ReplyQuote
SOLO Team
(@milad)
Illustrious Member Admin
Joined: 3 years ago
Posts: 483
 

Hi @lokmanho,

Posted by: @lokmanho

I noticed that when in torque control mode, the rotational direction signal returns the sign of the quadrature current instead.

The direction that you read with GetDirectionRotation() function is not the real direction of the motor, it's the desired direction that you set, so you can just verify with that what direction you asked SOLO to follow, so I don't get the fact that if you mean this value changes dynamically? ( it shouldn't be like that)

Posted by: @lokmanho

As it stands, I can't figure out a way to obtained the signed speed of the motor, which I need for closed-loop speed control.

Yes, this can be challenging as now we return the speed as a Uint32 value, but in general, if you are in torque mode in steady-state, the sign of the "Iq" can define the real direction of rotation. ( only in steady state)

Posted by: @lokmanho

By the way, seeing that a long in Arduino is a 4-byte integer and none of our motors are likely to spin at >1 billion rpm, wouldn't it make sense to return the motor speed also directly as a signed long (long is already the return type) incorporating direction information? As an added bonus, it would save me one message per control cycle ?

You are 100% right, we will change the Speed feedback to signed Int32, so you can read the direction also from that, probably in V009 we will do that, Buuuuut for now, for your issue I would recommend doing the following to find the direction of rotation:

the most reliable way to find the real direction of the motor for now in Torque Mode ( before we make the speed feedback Int32 ) will be by looking at the measured Angle of the Motor ( you can read it with 0xB0 Command), if you read the Angle, you'll have 4 conditions as below:

Forum 5

 

This image is a generic Image, your Angle will be something between -2 to +2 (instead of 4000 shown in this image which is just the max value of that plot) but the trend is the same, so you need to find in which case you are, so if you are in CASE 1 & 2, it means your Motor is moving in C.C.W direction, if you are in Case 3 &4 it means your Motor is moving in C.W direction.

The GetAngle() function right now is not available in the Arduino library, but until it comes you can just make it yourself ( for example the method will be identical to any function with fixed-point data type like GetTorqueReference(), you just need to put the 0xB0 instead of the command part).

I understand this might make your code a little bit complicated, but until we make the speed feedback from the Int32 type, maybe it's the most reliable way.

of course, there are other ways like keep monitoring the Speed and catch the Zero touching or an interval that the speed reaches near zero, and if the sign of the Torque changes after that, you can be sure the direction is also changed, but may this becomes even more complicated than finding the direction from the angle which needs 1 differentiation each time you run the loop to find the Delta Theta.

I hope this could be helpful, I will remain available for further discussions.

Regards
Milad

 

If you found the answers helpful and you could solve your problems, please kindly verify here to help others in the future.


   
ReplyQuote
SOLO Team
(@milad)
Illustrious Member Admin
Joined: 3 years ago
Posts: 483
 

I forgot to say that, the most update Write/Read command table can be found in SOLO-UNO_User_Manual.pdf.

Regards

Milad

 

This post was modified 2 years ago by Solo

If you found the answers helpful and you could solve your problems, please kindly verify here to help others in the future.


   
ReplyQuote
Forum 1
(@lokmanho)
Active Member
Joined: 2 years ago
Posts: 7
Topic starter  

Thanks, I will try the suggested approach and report back.


   
SOLO Team reacted
ReplyQuote
SOLO Team
(@milad)
Illustrious Member Admin
Joined: 3 years ago
Posts: 483
 

Hi Lok, 

Last night due to a problem with our server, we lost your question on our forum, but fortunately, it was sent as an email and I'm going to put it here and then answer you after:

"

Hi,

I have implemented a Get3PhaseMotorAngle() function using the 0xB0 message as suggested. When rotating the motor shaft by hand in the counterclockwise (positive) direction, the function would return positions steps that are not monotonic, but rather change back and forth as shown in the attachment. This is in contrast with the rotor position signal displayed in monitor plot of the Motion Terminal, which increases monotonically until the upper limit is reached before wrapping to the minimum value, as one would expect. The behaviour of the 3 phase rotor angle read on the UART doesn't seem right to me.

Thanks in advance.

Cheers,
Lok Man

"

If you found the answers helpful and you could solve your problems, please kindly verify here to help others in the future.


   
ReplyQuote
SOLO Team
(@milad)
Illustrious Member Admin
Joined: 3 years ago
Posts: 483
 
Posted by: @milad

the function would return positions steps that are not monotonic, but rather change back and forth as shown in the attachment. This is in contrast with the rotor position signal displayed in monitor plot of the Motion Terminal, which increases monotonically until the upper limit is reached before wrapping to the minimum value, as one would expect.

Regarding this, as I saw in your image, it seemed to me you are sampling the signal very slowly, how much is your sampling interval?

It's important to sample that signal as fast as you can so you can see its real shape because that sawtooth-shaped signal has a relatively high frequency, and in Motion terminal for instance it's sampled at 500Hz, so I would imagine if you want to see the same shape as motion terminal you need to read that signal with the same frequency or even higher ( I think you can easily go up to 1kHz of sampling).

The reason that signal is not between 0 to 1, is the Hall sensor calibration value which is added to the calculated Angle, so the final angle will go out of this interval which is fine, if you put your Hall sensor calibration values to 0, you'll notice that it will stay between 0 to 1 ( but of course you lose your calibration and you need to recalibrate the Hall sensors again).

So pls provide me more information especially on how you are sampling this signal and also it will be good if you can share your code here, so we can help you better. I will remain available.

Regards
Milad

 

If you found the answers helpful and you could solve your problems, please kindly verify here to help others in the future.


   
ReplyQuote
Forum 1
(@lokmanho)
Active Member
Joined: 2 years ago
Posts: 7
Topic starter  

Dear Milad,

Thanks for recovering my message!

Regarding the sampling frequency, I was actually sampling with the Arduino at 500Hz, but printing via Serial to the host at the lower frequency to avoid impacting the sample time on a regular basis.

The phenomenon that I am displaying is more of a low speed and steady state one, so a higher sample rate would not have much impact. I am not concerned about the sharpness of the flanks of the sawtooth, but rather the steady state values. When rotated BY HAND in one direction, the plot shows the 3 phase motor angle jumping back and forth between steps in the middle of the [0,1] range, in behaviour unrelated to wrapping. As I rotate the shaft by hand, the motor always stops at the six cogging positions per electrical revolution, which is clearly visible as six monotonic steps in [0,1] in the position plot on the motion monitor. This is not the case for the 3 phase motor position obtained by the UART request. I have reattached the image to this message. Let me know if I should acquire measurements from another test.

Regarding the range of position, my opinion is that it makes more sense to maintain the hall-offset compensated output in the range [0,1], such that position wrapping and processing code can be reused without additionally adjusting for the hall sensor offset. It is a more consistent interpretation of an incremental position sensor with a P.U. output. However, in the meantime I will subtract the hall offset from the position read via UART.

Regards,
Lok Man

 read 3phase pos UART CCW motion

   
ReplyQuote
SOLO Team
(@milad)
Illustrious Member Admin
Joined: 3 years ago
Posts: 483
 
Posted by: @lokmanho

The phenomenon that I am displaying is more of a low speed and steady state one, so a higher sample rate would not have much impact. I am not concerned about the sharpness of the flanks of the sawtooth, but rather the steady state values. When rotated BY HAND in one direction, the plot shows the 3 phase motor angle jumping back and forth between steps in the middle of the [0,1] range, in behaviour unrelated to wrapping. As I rotate the shaft by hand, the motor always stops at the six cogging positions per electrical revolution, which is clearly visible as six monotonic steps in [0,1] in the position plot on the motion monitor. This is not the case for the 3 phase motor position obtained by the UART request. I have reattached the image to this message. Let me know if I should acquire measurements from another test.

Hi @lokmanho, Maybe I'm not getting your problem clearly, but what I did was this:

  1. I put the Motion terminal Monitoring to go on while showing the angle, 
  2. I turned the motor by hand, and let the angle remains steady ( at any random position)
  3. I read the angle by UART using "FFFF00B00000000000FE", and I see the angle is stable and matching with what I see on the Motion terminal monitoring part

Forum 10

so I don't get if you mean, while the motor is steady the angle goes up and down while you read it by UART? ( this is pretty strange and I didn't see it in my case too)

- another point, if you like, by end of next week ( Mid June 2021), we can provide you a "BETA" version of Firmware V009 with speed returned in Int32 format, so you can just use that instead of angle, however, that BETA firmware will not be compatible with our libraries and motion terminal until we release the final version ( so you need to change the Arduino Code a little bit for Speed reading), so let me know if this works for you?

Regards
Milad

 

If you found the answers helpful and you could solve your problems, please kindly verify here to help others in the future.


   
ReplyQuote
Forum 1
(@lokmanho)
Active Member
Joined: 2 years ago
Posts: 7
Topic starter  

Hi Milad,

Thanks for attempting to reproduce this issue. Let me try your procedure when I get home and report back to you.

The beta of V009 would be of interest to me, please keep me updated on that front. Thanks!

Cheers,
Lok Man

 


   
ReplyQuote
SOLO Team
(@milad)
Illustrious Member Admin
Joined: 3 years ago
Posts: 483
 

@lokmanho
yes, you can just try to read the Angles with Motion terminal Manually in the "Signals" section as I did and compare them with your Arduino Readings, if you click on the "Packet Received" it will automatically convert the DATA part into all the possible variable forms and you should look at the "double format" to see the real converted value of the DATA coming back as an Angle, they must match and it shouldn't vary with time if the motor is steady

I will remain available for further discussions.

Regards
Milad

 

If you found the answers helpful and you could solve your problems, please kindly verify here to help others in the future.


   
ReplyQuote
Forum 1
(@lokmanho)
Active Member
Joined: 2 years ago
Posts: 7
Topic starter  

It turned out to be a bug in the ConvertToFloat function in the Arduino library. The original code is:

dec = (data[0] / 16) * 268435456 + (data[0] % 16) * 16777216 +
(data[1] / 16) * 1048576 + (data[1] % 16) * 65536 +
(data[2] / 16) * 4096 + (data[2] % 16) * 256 +
(data[3] / 16) * 16 + (data[3] % 16) * 1;

in which the data[i] appears to be cast implicitly into signed chars, such that in some instances the value of dec is negative. Explicitly casting the to long prior to the operations fixes the problem:

dec = (long)data[0] * 16777216 + (long)data[1] * 65536 + (long)data[2] * 256 + (long)data[3];

Cheers,
Lok Man


   
SOLO Team reacted
ReplyQuote
SOLO Team
(@milad)
Illustrious Member Admin
Joined: 3 years ago
Posts: 483
 

Thanks @lokmanho for this great catch, we will investigate the issue and we will update the library for that, I'll remain available for the rest, keep me updated for your progress please.

Regards

Milad

 

If you found the answers helpful and you could solve your problems, please kindly verify here to help others in the future.


   
ReplyQuote
SOLO Team
(@milad)
Illustrious Member Admin
Joined: 3 years ago
Posts: 483
 
Posted by: @lokmanho

It turned out to be a bug in the ConvertToFloat function in the Arduino library. The original code is:

 

Hi @lokmanho, FYI, thanks to your report we fixed the bug in the library and the latest commit is downloadable below:

https://github.com/Solo-FL/SOLO-motor-controllers-ARDUINO-library

Regards

Milad

 

If you found the answers helpful and you could solve your problems, please kindly verify here to help others in the future.


   
ReplyQuote
Forum 1
(@lokmanho)
Active Member
Joined: 2 years ago
Posts: 7
Topic starter  

Glad I could help! Looking forward to the release of V009!

I will abuse this thread for reporting another minor Arduino library bug. Line 39-41 of SOLOMotorController.cpp, which is part of the ExeCMD() function, reads:

Serial.write(_cmd,10);
while(Serial.availableForWrite() == 0); // wait till end of writing
Serial.readBytes(_readPacket, 10); //read received data

The command Serial.availableForWrite() returns the number of bytes still free in the write buffer, and my test on an Arduino MEGA or UNO shows that the return value immediately after the write command is 54, increasing back up to the idle value of 63. The code in the library appears to have misinterpreted the function to return a Boolean indicating whether the transmit buffer is ready for writing again. The conclusion is that the code above does not actually wait until the transmit buffer has finished writing, but rather immediately proceeds to execute Serial.readBytes().

If the intention is to wait for the buffer to be transmitted, use Serial.flush() instead.

Cheers,
Lok Man


   
ReplyQuote
Page 1 / 2
Share: