Hi runger,
yes, I want to use the sensor in PWM mode first because I can solder it better.
I have used your posted code and it seems, that the sensor get some information from the magnet. In the monitor I can see that, if I turn the motor faster, the left numbers are getting smaller. The slower I turn the motor, the higher are the numbers. But I can’t do much with it. Something is still wrong. I have also used a bigger diametrical magnet and the result is the same.
For PWM, you have to be sure the circuit is reliable and not subject to interference/noise. Once you have a clean signal, it should work, but since the sensor PWM freq is only 1kHz, this will limit your performance quite a lot.
For I2C, the communication can be simpler to set up reliably, withe the right pull-up resistors it usually works well. But also with I2C you won’t break any speed records… but if you’re controlling a gimbal type motor, and don’t need high performance, it can work quite well.
The left-hand numbers should be the absolute angle, in radians. So these numbers seem a little high unless you were running the motor a litte while? The right-hand numbers should be the velocity. When moving the motor by hand, it is normal to show 0 or near 0 most of the time.
Hi @runger ,
thank you for your replay
yesterday I tried to solder the 4 contacts for GND, 5V and the two for I2C. It is horror and not practical. I sat for an hour The contacts are about 1mm wide and 1mm apart there. can’t do it at all. i think i also created a short, but i can’t check it with the naked eye. nevertheless i tested the sensor and lo and behold. it seems to work for now:
#include <SimpleFOC.h>
// MagneticSensorI2C(uint8_t _chip_address, float _cpr, uint8_t _angle_register_msb)
// chip_address - I2C chip address
// bit_resolution - resolution of the sensor
// angle_register_msb - angle read register msb
// bits_used_msb - number of used bits in msb register
MagneticSensorI2C as5600 = MagneticSensorI2C(0x36, 12, 0x0E, 4);
// or quick config
// MagneticSensorI2C as5600 = MagneticSensorI2C(AS5600_I2C);
void setup() {
// monitoring port
Serial.begin(115200);
// init magnetic sensor hardware
as5600.init();
Serial.println("AS5600 ready");
_delay(1000);
}
void loop() {
// IMPORTANT - call as frequently as possible
// update the sensor values
as5600.update();
// display the angle and the angular velocity to the terminal
Serial.print(as5600.getAngle());
Serial.print("\t");
Serial.println(as5600.getVelocity());
}
why the right numbers jump like this i don’t know.
i have now ordered the white as5600 encoder and try my luck with the board. i have read here in the forum that the resistor R1 must be desoldered so that i can operate this encoder with 5V instead of 3.3V and the OUT must be grounded.
closed loop has not worked yet. the motor only hums. but with the other sensor and more space to solder it should be better.
#include <SimpleFOC.h>
// motor instance, number of pole pairs, not poles
BLDCMotor motor = BLDCMotor(7);
// driver instance, must use 6PWM FOR B-G431 driver
BLDCDriver6PWM driver = BLDCDriver6PWM(PHASE_UH, PHASE_UL, PHASE_VH, PHASE_VL, PHASE_WH, PHASE_WL);
// Magnetic sensor instance
MagneticSensorI2C sensor = MagneticSensorI2C(0x36, 12, 0x0E, 4);
// buttom config
const int buttonPin = PC10;
int lastState = 0; // last button state
long timestamp = millis(); // timestamp
int direction = 1; // 1 or -1
// gear
float i = 200;
void setup() {
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
// initialize magnetic sensor hardware
sensor.init();
Serial.println("Sensor ready");
// link the motor to the sensor
motor.linkSensor(&sensor);
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 9;
driver.init();
motor.linkDriver(&driver);
// set motion control loop to be used
motor.controller = MotionControlType::velocity;
// controller configuration based on the control type
// velocity PID controller parameters
// default P=0.5 I = 10 D =0
motor.PID_velocity.P = 0.5;
motor.PID_velocity.I = 10;
motor.PID_velocity.D = 1;
// jerk control using voltage voltage ramp
// default value is 300 volts per sec ~ 0.3V per millisecond
motor.PID_velocity.output_ramp = 300;
// maximal voltage to be set to the motor
motor.voltage_limit = 6;
// velocity low pass filtering
// default 5ms - try different values to see what is the best.
// the lower the less filtered
motor.LPF_velocity.Tf = 0.0005;
// since the phase resistance is provided we set the current limit not voltage
// default 0.2
motor.current_limit = 1; // Amps
// use monitoring with serial
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);
// motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE;
// downsampling
// motor.monitor_downsample = 100; // default 10
// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC();
// Serial.println("Motor ready.");
// Serial.println("Sensor ready.");
_delay(1000);
}
void loop() {
// main FOC algorithm function
motor.loopFOC();
// Motion control function
// motor.move(analogRead(POTENTIOMETER)/i*direction);
motor.move(2);
// buttom change direction
long deltaT = millis() - lastState;
if (deltaT>=500) {
int buttonState = digitalRead(buttonPin);
timestamp = millis();
if (buttonState!=lastState) {
lastState = buttonState;
if (buttonState==1)
direction = direction * -1;
}
}
sensor.update();
// display the angle and the angular velocity to the terminal
// Serial.println(sensor.getAngle());
// Serial.print("\t");
// Serial.println(sensor.getVelocity());
}
Hi together,
update:
I have managed the closed loop with the as5600 and the B-G431B-ESC1. The direction of rotation and the speed can also be set. Unfortunately, the board is still very warm and I think there is no temperature difference to open loop. What could help to get the temperature down?
Furthermore, the motor does not rotate 100% smoothly, there is a kind of chatter. Could this be due to the settings? Super is that the engine is absolutely quiet and you hear no noise.
This beginning portion of this post very nicely goes over what initFOC() does, and when/how to bypass parts of it.
Also a misaligned magnet can cause chatter and noise. There’s a recent post on the forum that goes over setting up a look-up-table to calibrate any offsets a sensor may experience.
Its worth a read even if it may not be your problem
the direction of my motor sensor combination is “Direction::CCW”
But I dont know the “offset” and I have read in the forum, that a have to use the tool
“find_zero_offset_and_direction”
Where can I find it? I use Arduino IDE
If you run initFOC() without these parameters, it will perform the alignment and print the electrical angle found… You can then store the value, and use it to set the zero angle so the alignment can be skipped.
Oh, and to do it all programmatically, you can read the alignment value from motor.zero_electric_angle.
I noted your comment that the board was getting hot - but for the motor you are using, with no load and in closed loop mode, there should be almost no current flowing… My PSU shows somewhere between 0.00 and 0.10 amps when running such motors unloaded. So really, the B-G431B-ESC1 with its custom FETs should not get hot at all… is it the FETs getting hot, or some other part of the board?
So I wonder what is going on?
Open-Loop mode is a lot less efficient than closed loop, so in open loop I would expect a certain amount of heat, but again, not much with this motor. Also, if the alignment for FOC mode runs, but cannot find the electrical angle reliably. Or if the magnet were to slip a little bit out of position after the alignment… things like this could adversely affect the FOC performance, and cause more heat.
these are in the upper picture the black parts of the board where the motor is soldered.
I have set the lowpass filter to 0,05 to reduce fully the motor vibration. When I set the LF to 0, the engine vibrates a lot. does this seem to be an indication that the as5600 sucks? Perhaps this is where the high load from the board comes from
Yeah, the 6 bigger components near the motor leads are the FETs which switch the power. These are normally what gets hot, but normally not unless you’re using significant power.
Yes, the AS5600 does suck
But the LPF is probably needed for any magnetic sensor - due to sampling effects and latencies the velocity has to be smoothed somewhat to make it useful. Tuning this parameter can be quite helpful sometimes. The value is somewhat linked to the main loop iteration speed and the motor.motion_downsample value. These factors determine how often the velocity gets computed, and therefore how much smoothing is needed.
do you know a good sensor board with pullups that is flat (less than 4mm) and costs less than 10euros that can do I2C and if the B-G431B-ESC1 board can do SPI (unfortunately I don’t know) also SPI?
You should avoid I2C sensors if possible. The slow speed of I2C will certainly limit your performance, it will become the limiting factor of the whole system.
I looked into this recently, and the B-G431B-ESC1 can’t do SPI, unfortunately.
The way I see it, the best options for precise sensors are a SSI interface (like SPI but with only 3 lines) or a ABZ interface. The MT6701 might be an option that can work for you, it’s fairly cheap and has loads of interfaces: I2C, SSI, ABZ, Analog and UVW, all in one sensor…
Otherwise there are other SSI sensors from AMS, like the AS5045, IIRC. The AS5048A also has a 3-wire mode, but typically costs more than $10.
I should also mention that while I’ve tried these sensors in other setups, I haven’t tried them with the B-G431B-ESC1 myself, so you’d be doing some experimentation here…
For ABZ mode, if the second picture can be trusted, you might have change something on the sensor PCB - remove a resistor or add one. Then you can connect the ABZ outputs to any available pins, and use the Encoder class of SimpleFOC as the sensor.
For SSI mode, the same pins are used as I2C, but presumably something has to be changed on the PCB to activate this.
For I2C mode, the intialization should work with: MagneticSensorI2C sensor = MagneticSensorI2C(0x6, 14, 0x03, 8);
But the MagneticSensorI2C class will try to do a 2-byte read, while the datasheet for the sensor suggests it wants 2 x 1-byte read, to consecutive registers. So I doubt it will work as is.
I’m actually working on a driver for the MT6701, let me see if I can get the I2C mode supported.
Can you perhaps send pictures of both sides of the sensor board you have? Do you have more than one of them? It seems on this board you have to switch modes by setting solder bridges…
hi runger,
ok, thanks!
exactly, it says that you have to short the IIC bridge so you can use the I2C or ABZ. I bought 2 of this sensors that I usually do because one could always break and I don’t want to wait a month for a new one.
I have now installed the following setting on my board. can you quickly look over there, whether from the settings goes out, whether there is something wrong, because the card is so warm? I would like to exclude that. By setting the correct offset, I could also take the LF further down and the engine runs not bad at all.
#include <SimpleFOC.h>
// motor instance, number of pole pairs, not poles
BLDCMotor motor = BLDCMotor(7);
// driver instance, must use 6PWM FOR B-G431 driver
BLDCDriver6PWM driver = BLDCDriver6PWM(PHASE_UH, PHASE_UL, PHASE_VH, PHASE_VL, PHASE_WH, PHASE_WL);
// Magnetic sensor instance
MagneticSensorI2C sensor = MagneticSensorI2C(0x36, 12, 0x0E, 4);
// buttom config
const int buttonPin = PC10;
int lastState = 0; // last button state
long timestamp = millis(); // timestamp
int direction = 1; // 1 or -1
// gear
float i = 175;
void setup() {
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
// initialize magnetic sensor hardware
sensor.init();
// link the motor to the sensor
motor.linkSensor(&sensor);
// power supply voltage [V]
driver.voltage_power_supply = 9;
driver.init();
motor.linkDriver(&driver);
motor.controller = MotionControlType::velocity;
// velocity PID controller parameters
// default P=0.5 I = 10 D =0
motor.PID_velocity.P = 0.7;
motor.PID_velocity.I = 10;
motor.PID_velocity.D = 0;
motor.PID_velocity.output_ramp = 1000;
motor.voltage_limit = 9;
motor.LPF_velocity.Tf = 0.05;
// since the phase resistance is provided we set the current limit not voltage
// default 0.2
motor.current_limit = 1; // Amps
// use monitoring with serial
// Serial.begin(115200);
// comment out if not needed
// motor.useMonitoring(Serial);
motor.init();
motor.initFOC(PI/100*18, Direction::CCW);
delay(100);
}
void loop() {
// main FOC algorithm function
motor.loopFOC();
// Motion control function
motor.move(analogRead(POTENTIOMETER)/i*direction);
// buttom change direction
long deltaT = millis() - lastState;
if (deltaT>=500) {
int buttonState = digitalRead(buttonPin);
timestamp = millis();
if (buttonState!=lastState) {
lastState = buttonState;
if (buttonState==1)
direction = direction * -1;
}
}
// sensor.update();
// display the angle and the angular velocity to the terminal
// Serial.println(sensor.getAngle());
// Serial.print("\t");
// Serial.println(sensor.getVelocity());
}
I got the jerking as good as gone by setting “motor.PID_velocity.P = 0.2;”
to “motor.PID_velocity.P = 0.7;”, at 0.8 it starts to oscillate briefly when turned on.
Here are the pictures of both sides:
What I would still find quite cool, is there a possibility to build acceleration ramps?
One thing I think see is that you have to set the motor.phase_resistance if you want to set a motor.current_limit. Without the phase resistance value, you can only set a motor.voltage_limit.
Good to hear it is working better!
You can limit the motor velocity and ramp value, in effect limiting acceleration, but to do acceleration ramps, you will have to write additional software. I think people have found that it works well to modify the target value (i.e. model the motion pattern in the move() loop) rather than messing with the PID controller.