I am working on a system that requires communication with a sensor that outputs data in BISS-C format. The communication between the microcontroller and the sensor is established through the SPI interface, and the sensor data is transmitted in 16-bit frames. I have previously run bit bang to get the data out but it is too slow and would like to use SPI but this bit shifting thing is driving me crazy, would appreciate if someone could help me
I got it working on Teency 4.0 but it does not work on STM32F4 with SimpleFoc Generic Sensor. Anyone has a clue? I suppose it has to do with some timings, maybe it calls to fast? When I debug sensor update method to read angle it jumps randomly and motor is shaking.
TEENCY 4.0
#define CLOCK_SPEED 1'000'000
const int miso_pin = 12;
const int clock_pin = 13;
void setup()
{
pinMode(clock_pin,OUTPUT);
pinMode(miso_pin,INPUT);
SPI.begin(); // Initialize SPI
Serial.begin(9600); // Initialize Serial communication at 9600 baud rate
delay(1000);
}
uint8_t encoderBuf[4] = {0,0,0,0};
uint32_t decodeEncoderFrame()
{
uint32_t data = static_cast<uint32_t>(encoderBuf[0] << 24) |
static_cast<uint32_t>(encoderBuf[1] << 16) |
static_cast<uint32_t>(encoderBuf[2] << 8) |
static_cast<uint32_t>(encoderBuf[3]); // here transfer8 was made
data = data >> 14;
return data;
}
void calculateAndPrintPosition(uint32_t& encoderData)
{
float angularAbsolutePosition = ((encoderData & 0x0FFF) * 360UL) / 4096.0;
SerialUSB.println("Encoder Positon = " + String(encoderData) + " Angle = " + String(angularAbsolutePosition, 4));
}
void loop()
{
// Start SPI transaction
SPI.beginTransaction(SPISettings(CLOCK_SPEED, MSBFIRST, SPI_MODE0));
// Send dummy bytes and read data
for (int i = 0; i < 4; i++)
{
encoderBuf[i] = SPI.transfer(0xAA);
}
SPI.endTransaction();
uint32_t encoderData = decodeEncoderFrame();
calculateAndPrintPosition(encoderData);
delay(100); // Delay for demonstration purposes
}
SIMPLE FOC
#define CLOCK_SPEED 1'000'000 // 1.0 MHz
SPISettings settingsSPI(CLOCK_SPEED, MSBFIRST, SPI_MODE0);
uint8_t encoderBuf[4] = {0,0,0,0};
uint32_t decodeEncoderFrame()
{
uint32_t data = static_cast<uint32_t>(encoderBuf[0] << 24) |
static_cast<uint32_t>(encoderBuf[1] << 16) |
static_cast<uint32_t>(encoderBuf[2] << 8) |
static_cast<uint32_t>(encoderBuf[3]); // here transfer8 was made
data = data >> 14;
return data;
}
float calculatePosition(uint32_t& encoderData)
{
return ((encoderData & 0x0FFF) * 360UL) / 4096.0;
}
float readMySensorCallback()
{
// Start SPI transaction
SPI.beginTransaction(settingsSPI);
// Send dummy bytes and read data (24)
for (int i = 0; i < 4; i++)
{
encoderBuf[i] = SPI.transfer(0xAA);
}
SPI.endTransaction();
uint32_t encoderData = decodeEncoderFrame();
return (calculatePosition(encoderData) * PI) / 180; //rads
}
void initMySensorCallback()
{
SPI.setSCLK(PC10);
SPI.setMISO(PC11);
SPI.setMOSI(PC12);
SPI.begin();
}
Seems to be the correct values now and the sensor check goes well, but when implementing the generic sensor the motor just shakes, motor runs fine during the sensor calibration.
Yes, the velocity mode depends on torque mode, and you need to tune the PID to match your motor. 20.0 is probably too high for the I term.
The voltage limit of 3/24 is not ideal: this is a low utilisation of the PWM range, all the PWM duty cycles will be very short. It would be better to use a 5V power supply if you only need 3V on the motor.
Which type of motor is it, what’s the winding resistance?
And how many pole pairs has the motor, did you configure it correctly? Its important to get the pole-pair number correct…
I’m new to motor driving but I it will probably be easier when all start to make sense, yes it’s still shake on same place. I appreciate your help!
That’s interesting, encoder is mounted on motor shaft but when I turn motor by hand it goes from 0 to 6.28 quite fast not a full motor turn. Can it be that encoder is calibrated somehow with gearing? Motor gearing is 30x for output shaft, but encoder is not mounted on output shaft…
I dont have access to code right now but it’s same as for torque example but with voltage limit of 3.
I will make a test to see how many times it reaches 2PI radians when made one full motor turn.
This is a strange sensor, but then yes, it sounds like it is somehow calibrated for maybe the output shaft position? Have you checked if the 0-2PI corresponds to one full turn of the output shaft?
→ if yes, then you could divide the value by the gear-down, i.e. 1/30…
But the datasheet you pasted says “Absolute position / revolution (motor side)” - which I would understand to mean before the gear-down…
The SimpleFOC code absolutely cannot work if the sensor does not return 0-2PI corresponding to the rotor position.
Perhaps another explanation is that the byte order is still wrong: maybe we’re using the low byte as the high byte? Then you would seem to get many 0-2PI outputs per revolution…
Is it better if you do: uint16_t rawval16 = (buff[2]<<8) | buff[1];
or does that make it even worse?
This makes it worse if switch so it seems fine, I notice when I turn maybe 5-10 degree of motor shaft it goes from 0 - 2PI, and values looks fine each time.
If I divide the value by the gear-down it jumps only from 0 - 0.21
I made a test with some counter that check each full turn of motor and when it reach 2PI
angle_rad: 0.80 - count: 10
So it tool 10 times to rotate 1 full motor turn and each range from 0-2PI