Hi @David_Gonzalez
I am Katrin and collaborating with Adam_Donovan.
So I will share our code with you.
1.)
As we are using a multiplexer to address 3 motors at once, I modified the"MagneticSensorI2C.cpp" and “MagneticSensorI2C.h” . We are using the current FOC library (master v1.6.0 Releases 10) . Here I will just write what I added / the functions I modified, the complete code is here: https://drive.google.com/drive/folders/18HJprLy6dZAAi1Yfn-eJ00Omie4MwIr6?usp=sharing
----
My changes / additions to “MagneticSensorI2C.cpp”
----
#define MULTIPLEXER
void TCA9548A(uint8_t bus)
{
Wire.beginTransmission(0x70); // TCA9548A address is 0x70
Wire.write(1 << bus); // send byte to select bus
Wire.endTransmission();
}
MagneticSensorI2C::MagneticSensorI2C()
{};
void MagneticSensorI2C::init(int _id) {
id = _id;
... code like the normal init function ...
}
int MagneticSensorI2C::read(uint8_t angle_reg_msb) {
// read the angle register first MSB then LSB
byte readArray[2];
uint16_t readValue = 0;
#ifdef MULTIPLEXER
TCA9548A (id);
#endif
// notify the device that is aboout to be read
Wire.beginTransmission(chip_address);
Wire.write(angle_reg_msb);
Wire.endTransmission(false);
// read the data msb and lsb
Wire.requestFrom(chip_address, (uint8_t)2);
for (byte i=0; i < 2; i++) {
readArray[i] = Wire.read();
}
// depending on the sensor architecture there are different combinations of
// LSB and MSB register used bits
// AS5600 uses 0..7 LSB and 8..11 MSB
// AS5048 uses 0..5 LSB and 6..13 MSB
readValue = ( readArray[1] & lsb_mask );
readValue += ( ( readArray[0] & msb_mask ) << lsb_used );
return readValue;
}
----
My changes / additions to “MagneticSensorI2C.h”
----
class MagneticSensorI2C: public Sensor{
public:
MagneticSensorI2C();
void init(int _id) ;
private:
int id;
}
2.)
Trying to change the audible frequency, it did not seem that reasonable values like in the original code of “hardware_utils.cpp”, made any difference, neither on what we could hear, nor on what the oscilloscope was outputing. So I tried a value of 4000000 Hz instead of 40000 Hz
----
My changes / additions to “hardware_utils.cpp”
----
in
void _setPwmFrequency(long pwm_frequency,const int pinA, const int pinB, const int pinC, const int pinD) {
...
#elif defined(ESP_H) // if esp32 boards
if(pwm_frequency == NOT_SET) pwm_frequency = 4000000; // KKK, org: 40000 default frequency 20khz - centered pwm has twice lower frequency
else pwm_frequency = constrain(2*pwm_frequency, 0, 8000000); //KKK, org: 60000 constrain to 30kHz max - centered pwm has twice lower frequency
...
That alone did not have an influence, so I experimented with the prescales
in
void _configureTimerFrequency(long pwm_frequency, mcpwm_dev_t* mcpwm_num, mcpwm_unit_t mcpwm_unit){
...
mcpwm_num->clk_cfg.prescale = 0; //KKK , org 0
mcpwm_num->timer[0].period.prescale = 0; //KKK , org 4
mcpwm_num->timer[1].period.prescale = 0; //KKK , org 4
mcpwm_num->timer[2].period.prescale = 0; //KKK , org 4
...
and now we have as Adam discribed 39.1Khz on the oscilloscope, but can still hear noise…
3.)
The Arduino Test code for our 3 motors is now structured with a Wheel class, which has an instance of MagneticSensorI2C and an instance of BLDCMotor that are maching pairs in terms of sensor id and motor pins.
----
Main program: 201020_FOC1_6_esp32_position_control_3Motors_Multiplexer.ino
----
/**
ESP32 position motion control example with magnetic sensor
*/
#include "globals.h"
#define ESP_H
#define MULTIPLEXER
#include <SimpleFOC.h>
#include "config.h"
#include "Wheel.h"
Wheel wheelA;
Wheel wheelB;
Wheel wheelC;
int lastTime = 0;
int count = 0;
float rpmCount = 0;
void setup() {
// use monitoring with serial
Serial.begin(115200);
// ENABLE PIN FOR MOTORDRIVER POWER AND I2C PIN 0 and 2 (used for Bootup) //
pinMode(MOTOR_ENABLE_PIN, OUTPUT);
digitalWrite(MOTOR_ENABLE_PIN, HIGH);
//Wheel(int phAPin, int phBPin, int phCPin ,int polepairNb, int id)
wheelA = Wheel (MA0_PIN, MA1_PIN, MA2_PIN, 7, 2);//1
wheelB = Wheel (MB0_PIN, MB1_PIN, MB2_PIN, 7, 1);//2
wheelC = Wheel (MC0_PIN, MC1_PIN, MC2_PIN, 7, 0);//0
wheelA.init();
wheelB.init();
wheelC.init();
//-----------------------------------------
lastTime = micros();
}
void loop() {
count++;
rpmCount += wheelA.getVelocity();
int currentTime = micros();
if (currentTime - lastTime >= 1000000) //=1 s = 1000 ms = 1000000 us
{
// Serial.println ("vel: " + (String) degrees (sensor.getVelocity()/360.) *60 + " rpm "); // degrees/s / 360°
Serial.println ("vel: " + (String) ( degrees (rpmCount) / float(count) / 360. *60) + " rpm "); // degrees/s / 360°
Serial.println((String)count + " loop udates/s");
count = 0;
rpmCount = 0;
lastTime = currentTime;
}
wheelA.loopFOC();
wheelB.loopFOC();
wheelC.loopFOC();
wheelA.moveTo(target_angle);
wheelB.moveTo(target_angle);
wheelC.moveTo(target_angle);
}
----
Wheel.h
----
#ifndef _WHEEL_
#define _WHEEL_
#include "Arduino.h"
#include"SimpleFOC.h"
extern float target_angle;
// Wheel class, combination of BLDC Motor, and I2C Sensor //
class Wheel
{
public:
Wheel();
Wheel(int phAPin, int phBPin, int phCPin , int polepairNb, int _id);
void init();
void loopFOC();
void move();
void moveTo(float target_angle);
float getVelocity();
float getAngle();
private:
int id;
// SENSOR INSTANCE //
MagneticSensorI2C sensor;
// MOTOR INSTANCE //
BLDCMotor motor;
};
#endif
----
Wheel.cpp, here is also where the motor parameters are set
----
#include "Wheel.h"
Wheel::Wheel(int phAPin, int phBPin, int phCPin , int polepairNb, int _id)
{
//MagneticSensorI2C::MagneticSensorI2C(uint8_t _chip_address, int _bit_resolution, uint8_t _angle_register_msb, int _bits_used_msb)
// @param _chip_address I2C chip address
// @param _bit_resolution bit resolution of the sensor
// @param _angle_register_msb angle read register
// @param _bits_used_msb number of used bits in msb
sensor = MagneticSensorI2C(0x36, 12, 0x0E, 4);
// MOTOR INSTANCE //
// BLDCMotor( int phA, int phB, int phC, int pp, int cpr, int en)
// - phA, phB, phC - motor A,B,C phase pwm pins
// - pp - pole pair number
// - cpr - counts per rotation number (cpm=ppm*4)
// - enable pin - (optional input)
motor = BLDCMotor(phAPin, phBPin, phCPin, polepairNb);
id = _id;
}
Wheel::Wheel()
{}
void Wheel::init()
{
// initialise magnetic sensor hardware
sensor.init( id);
// link the motor to the sensor
motor.linkSensor(&sensor);
// MOTOR SETTINGS --------------------------------------------------------------------------
// power supply voltage
// default 12V
motor.voltage_power_supply = 8.4;
// choose FOC modulation (optional)
motor.foc_modulation = FOCModulationType::SinePWM;
// set motion control loop to be used
motor.controller = ControlType::angle ; //angle;
// contoller configuration
// default parameters in defaults.h
// velocity PI controller parameters
motor.PID_velocity.P = 0.01; // 0.01;
motor.PID_velocity.I = 5;//5;
// maximal voltage to be set to the motor
motor.voltage_limit = 4.1; //2.1// 4.1;
// velocity low pass filtering time constant
// the lower the less filtered
motor.LPF_velocity.Tf = 0.0001;
// angle P controller
motor.P_angle.P = 20; //20; //80; //16;
// maximal velocity of the position control
motor.velocity_limit = 60;//60 //100; //40;
// comment out if not needed
motor.useMonitoring(Serial);
// initialize motor
motor.init(); //frequency of pins to make it silent //KKK changed code in library
// align sensor and start FOC
motor.initFOC();
Serial.print("Motor "), Serial.print (id), Serial.println( " ready.");
}
void Wheel:: loopFOC ()
{
// main FOC algorithm function
// the faster you run this function the better
motor.loopFOC();
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
}
void Wheel:: move()
{
// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move();
// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!!
// motor.monitor();
}
void Wheel::moveTo(float target_angle)
{
// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move(target_angle);
// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!!
// motor.monitor();
}
float Wheel::getVelocity()
{
return motor.shaftVelocity();
}
float Wheel::getAngle()
{
return motor.shaftAngle();
}
----
config.h - Pin definitions
----
#ifndef config_h
#define config_h
//------------------------------------------------------------------------------
// PIN DEFINITIONS
//------------------------------------------------------------------------------
// MOTOR PINS //
// MOTOR B = M2
#define MA0_PIN 27
#define MA1_PIN 14
#define MA2_PIN 12
// MOTOR C = M1
#define MB0_PIN 5
#define MB1_PIN 18
#define MB2_PIN 19
// MOTOR A = M3
#define MC0_PIN 32
#define MC1_PIN 33
#define MC2_PIN 25
// ENABLE PIN FOR MOTORDRIVER POWER //
#define MOTOR_ENABLE_PIN 4
// I2C PINS FOR MUlTIPLEXER + ADDRESS OF MULTIPLEXER 0x70
#define SDA_PIN 21
#define SCL_PIN 22
#endif
----
globals.h - for future angle transmission from kinematic model
----
#ifndef Globals_h
#define Globals_h
//------------------------------------------------------------------------------
// INCLUDES
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// GLOBAL VARIABLES
//------------------------------------------------------------------------------
extern float target_angle = 90000000;
#endif