Perhaps I missed something, are you soldering the boards yourself?
Cheers,
Valentine
Probably. I’ll see if I can find board that are just the driver boards without the stm32. I’d much rather try an esp32 since it has a built in serial to USB and would reduce my ratsnest of wires.
I’m soldering enameled wire to the pins. I don’t have any jumpers and couldn’t find any on Amazon.
I’m also soldering the power and motor wires to the boards. That’s the bit I think the debris came from.
You know, weirdly enough this is somewhat normal for my projects.
Ok. So I have things turning and am trying to get the linear halls set up once again.
I have a 12n14p motor but during the sensor check, it thinks the motor has anywhere from 12-44 pole pairs.
The linear hall sensors look clean so I’m at a bit of a loss as to the cause.
The motor turns about 45 degrees CW and CCW.
I have about 1.6v off difference between high and low for each driver. Its about half my ADCs range.
15:17:11.837 -> MOT: Monitor enabled!
15:17:11.837 -> MOT: Init
15:17:12.352 -> MOT: Enable driver.
15:17:12.834 -> ESP32-CS: Timer 0 enable interrupt callback.
15:17:12.834 -> ESP32-CS: Timer 0 enable interrupts.
15:17:14.856 -> MOT: Align sensor.
15:17:17.045 -> MOT: sensor_direction==CCW
15:17:17.045 -> MOT: PP check: fail - estimated pp: 44.21
15:17:17.753 -> MOT: Zero elec. angle: 1.15
15:17:17.980 -> MOT: Align current sense.
15:17:19.076 -> CS: Switch A-C
15:17:19.076 -> CS: Inv A
15:17:20.172 -> CS: Inv B
15:17:20.172 -> CS: Inv C
15:17:20.172 -> MOT: Success: 4
15:17:20.172 -> MOT: Ready.
Once it passes this, the motor just starts jittering violently.
It works well in open loop mode though.
Code:
#include <SPI.h>
//#include <DRV832xS.h>
#include <SimpleFOC.h>
#include <SimpleFOCDrivers.h>
#include <encoders/linearhall/LinearHall.h>
//https://www.ti.com/lit/ds/symlink/drv8323.pdf
#define chipSelectPin 4
#define DRV8323SEnablePin 17
#define CSACalibrationPin 5
#define SPIComSpeed 1500 // kHz
// SPI Register Adresses
#define ADR_FAULT_STAT (0x00) // Fault Status Register 1
#define ADR_VGS_STAT (0x01) // Fault Status Register 2
#define ADR_DRV_CTRL (0x02) // Driver Control Register
#define ADR_GATE_DRV_HS (0x03) // Gate Drive HS Register
#define ADR_GATE_DRV_LS (0x04) // Gate Drive LS Register
#define ADR_OCP_CTRL (0x05) // OCP Control Register
#define ADR_CSA_CTRL (0x06) // CSA Control Register // DRV8323 only
// Set the pins for the hall sensors
#define LinHall0 35
#define LinHall1 32
// BLDC motor instance BLDCMotor(polepairs, (R), (KV), (L))
BLDCMotor motor = BLDCMotor(7);
// BLDC driver instance BLDCDriver6PWM(phA_h, phA_l, phB_h, phB_l, phC_h, phC_l, (en))
BLDCDriver6PWM driver = BLDCDriver6PWM(12, 14, 27, 26, 25, 33, 17); // 17
// lowside current sense instance LowsideCurrentSense(R, gain, phA, phB, (phC))
LowsideCurrentSense currentsense = LowsideCurrentSense(0.001, -40, 36, 39, 34);
// Set up the hall effect sensors
LinearHall sensor = LinearHall(LinHall0, LinHall1, 1);
// instantiate the commander
Commander command = Commander(Serial);
void doMotor(char* cmd) {
command.motor(&motor, cmd);
}
void setup() {
// Start the Serial communication
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);
// Initialize SPI
SPI.begin();
// Set the chip select pin as output
pinMode(chipSelectPin, OUTPUT);
digitalWrite(chipSelectPin, HIGH); // Deselect the device
//Enable the DRV8323S
pinMode(DRV8323SEnablePin, OUTPUT);
// Briefly disable the device to clear the registers
digitalWrite(DRV8323SEnablePin, LOW);
delay(250);
digitalWrite(DRV8323SEnablePin, HIGH);
// Set up the pind for the amplifier calibration
pinMode(CSACalibrationPin, OUTPUT);
// Set the pin to low so it doesn't try to calibrate yet
digitalWrite(CSACalibrationPin, LOW);
delay(500);
// set power supply voltage
driver.voltage_power_supply = 7.5;
// initialize driver
driver.init();
// link driver to motor
motor.linkDriver(&driver);
// link driver to current sense
currentsense.linkDriver(&driver);
// set motion control type to velocity openloop
motor.controller = MotionControlType::velocity;//_openloop;
// set torque control type to FOC current
motor.torque_controller = TorqueControlType::foc_current;
// set FOC modulation type to space vector modulation
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// use monitoring
motor.useMonitoring(Serial);
// Set the motor's limits
motor.voltage_limit = 0.45;
motor.current_limit = 15;
motor.voltage_sensor_align = .45;
// link the motor to the sensor
motor.linkSensor(&sensor);
// initialize motor
motor.init();
// initialize current sensing and link it to the motor
// https://docs.simplefoc.com/inline_current_sense#where-to-place-the-current_sense-configuration-in-your-foc-code
currentsense.init();
motor.linkCurrentSense(¤tsense);
// initFOC
motor.initFOC();
// add command to commander
command.add('M', doMotor, "target");
// Write any important buffers
uint16_t response = DRV8323S_SPI(chipSelectPin, SPIComSpeed, false, ADR_CSA_CTRL,0x00C3); //0b0000000011000011
// Calibrate the CSAs
digitalWrite(CSACalibrationPin, HIGH);
delay(200); // Needs at least a 100uS delay. The offset can also be set via the spi registers if you want to avoid this for some reason.
digitalWrite(CSACalibrationPin, LOW);
delay(500);
}
String printBinary(int num, int bits) {
String binaryString = "";
// Loop through each bit
for (int i = bits - 1; i >= 0; i--) {
// Check if the bit at position i is set
if (num & (1 << i)) {
binaryString += "1";
} else {
binaryString += "0";
}
}
return binaryString;
}
uint16_t DRV8323S_SPI(
uint8_t CSPin, // The pin we use to tell the spi registers we are writing to them
uint16_t commSpeedKHz, // The frequency we will use for spi in kHz (1500kHz is 1.5MHz)
bool readOnly, // True will only read while false writes to the register
uint8_t addr, // The address of the register to access
uint16_t data // Data to write to the register. If set to read only, any values here will be ignored and passed as zero instead
) {
/* Communicates with the DRV8323S over spi and returns any recieved values*/
// Print the value to be sent over SPI for debugging
//Serial.println(printBinary((readOnly << 15) | (addr << 11) | (data & 0x7FF),16));
// Select the SPI device
digitalWrite(CSPin, LOW);
// Begin SPI transaction with specified settings
SPI.beginTransaction(SPISettings(commSpeedKHz*1000, MSBFIRST, SPI_MODE1));
// Send and receive data from the spi registers
uint16_t response = SPI.transfer16((readOnly << 15) | (addr << 11) | (data & 0x7FF)); // VERY import for this to be transfer16 since transfer will only send and recieve 8 bits
// Deselect the device
digitalWrite(CSPin, HIGH);
// End the transaction
SPI.endTransaction();
return response;
}
uint16_t idx = 0;
void loop() {
//if(idx % 1000 == 0){
// Serial.println(printBinary(DRV8323S_SPI(chipSelectPin, SPIComSpeed, true, ADR_FAULT_STAT, 0x0000),16));
// Serial.println(printBinary(DRV8323S_SPI(chipSelectPin, SPIComSpeed, true, ADR_VGS_STAT, 0x0000),16));
// Serial.println("");
//}
// main FOC algorithm function
// the faster you run this function the better
// main FOC algorithm function, the higher the execution frequency, the better, don't put delays in the loop
motor.loopFOC();
// this function can be run at much lower frequency than loopFOC()
motor.move(2);
// significantly slowing the execution down
//motor.monitor();
// user communication
command.run();
}
Edit: I’m going to take a crack at writing my own code.
The most obvious problem I see is the LinearHall constructor has 1 for pole pairs when it should be 7 to match the BLDCMotor.
There’s also no call to sensor.init, though it may work without it. There are two versions of init. One that auto-calibrates the center values, which needs to be called after motor.init so it can move the motor, but before motor.initFOC since that needs the center values to be calibrated. The other one where you specify the center values can be called any time before motor.initFOC.
The code says that it should be set to 1 if you use a magnet on the shaft which is what I am doing.
This doesn’t appear to work for the linear hall library. Am I using the right one?
Oh I didn’t see that it was magnet on shaft. Yes, 1pp is correct then.
That is the correct library. Can you give any more detail on what you mean by “doesn’t appear to work”?
Have you tried printing sensor.getAngle() and seeing if it gives reasonable values as you move the motor by hand?
sensor.init(); gives me the error
exit status 1
Compilation error: no matching function for call to 'LinearHall::init()'
I’ll check sensor.getAngle() real quick and update you
I get values between 3.5 and 4.5 during a full revolution.
init needs arguments. First time do sensor.init(motor); to run the auto-calibration. Print out sensor.centerA and centerB (I should probably do that automatically in the init function itself…). Then you can change to sensor.init(a, b); with the values to skip the motor movement.
That’s not good. It should count up by 2pi each revolution. Try printing sensor.lastA and using Arduino serial plotter to see if it looks roughly sinusoidal as you rotate the motor.
sensor.init(&motor); compiled properly. My problems still remain however.
I’ve done that without the linear hall class and they look pretty good. My custom class I am working on gives the correct rotation values
The centers are off by a good bit.
My max value is 2800 and the min is around 1200.
They also differ quite a bit run to run
23:08:40.807 -> Sensor.centers: 2686 1961
23:06:06.800 -> Sensor.centers: 2327 2475
Whole output
23:08:28.447 -> ESP32-DRV: Configuring 6PWM in group: 0 on timer: 0
23:08:28.447 -> ESP32-DRV: Configuring 3 operators.
23:08:28.447 -> ESP32-DRV: Configuring 6PWM with hardware dead-time
23:08:28.479 -> ESP32-DRV: Configuring 3 comparators.
23:08:28.479 -> ESP32-DRV: Configuring 6 generators.
23:08:28.479 -> ESP32-DRV: Configuring Center-Aligned 6 pwm.
23:08:28.479 -> ESP32-DRV: Configuring dead-time.
23:08:28.479 -> ESP32-DRV: Enabling timer: 0
23:08:28.479 -> ESP32-DRV: MCPWM configured!
23:08:28.479 -> MOT: Monitor enabled!
23:08:28.479 -> MOT: Init
23:08:28.996 -> MOT: Enable driver.
23:08:29.478 -> ESP32-CS: Timer 0 enable interrupt callback.
23:08:29.510 -> ESP32-CS: Timer 0 enable interrupts.
23:08:35.482 -> MOT: Align sensor.
23:08:37.710 -> MOT: sensor_direction==CCW
23:08:37.710 -> MOT: PP check: fail - estimated pp: 12.07
23:08:38.420 -> MOT: Zero elec. angle: 4.03
23:08:38.613 -> MOT: Align current sense.
23:08:39.709 -> CS: Switch A-C
23:08:39.709 -> CS: Inv A
23:08:40.807 -> CS: Inv B
23:08:40.807 -> CS: Inv C
23:08:40.807 -> MOT: Success: 4
23:08:40.807 -> MOT: Ready.
23:08:40.807 -> Sensor.centers: 2686 1961
Wait. I just notices the sensor is reading the correct angles now.
My motor still grooves the second the FOC loop starts so I guess thats a PID issue.
Oh, the lack of sensor.init was definitely a problem. The constructor initializes the center values to 512 for ATmega328P’s 10-bit ADC, but it looks like yours is probably 12-bit.
I also see why the auto-calibration isn’t giving consistent results. It only rotates one electrical revolution, but that’s not enough to sample the full range of the sensors for a magnet on the shaft. Change line 87 of LinearHall.cpp to this:
float angle = _3PI_2 + _2PI * i * motor->pole_pairs / pp / 2000.0f;
That should scale the electrical angle to make one revolution of the sensor even if it doesn’t match the motor pole pairs.
Or you could just do sensor.init(2048, 2048); That will probably be close enough to work.
It is. I’m using an esp32 S3 since I let the smoke out of all my qvadran boards.
I have surprisingly not killed any more hardware yet.
Works beautifully.
Thanks for the help.