Skip to content

Add two linear halls sensor module. #197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
Closed
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
*
* Torque control example using voltage control loop.
*
* Most of the low-end BLDC driver boards doesn't have current measurement therefore SimpleFOC offers
* you a way to control motor torque by setting the voltage to the motor instead of the current.
*
* This makes the BLDC motor effectively a DC motor, and you can use it in a same way.
*/
#include <SimpleFOC.h>

int16_t HALL_A_MIN = 98;
int16_t HALL_A_MAX = 577;

int16_t HALL_B_MIN = 80;
int16_t HALL_B_MAX = 591;

// BLDC motor & driver instance
//BLDCMotor motor = BLDCMotor(11);
//BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
BLDCMotor motor = BLDCMotor(4);
BLDCDriver3PWM driver = BLDCDriver3PWM(5, 6, 10, 8);

// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6, 8);

// Linear hall sensor instance
LinearHallSensor sensor = LinearHallSensor(A4, A5);

// voltage set point variable
float target_voltage = 2;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_voltage, cmd); }

void setup() {

/* use monitoring with serial */
Serial.begin(115200);
/* comment out if not needed */
motor.useMonitoring(Serial);

// initialize encoder sensor hardware
sensor.init(/* HALL_A_MIN, HALL_A_MAX, HALL_B_MIN, HALL_B_MAX*/);
// link the motor to the sensor
motor.linkSensor(&sensor);

// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.init();
// link driver
motor.linkDriver(&driver);

// aligning voltage
motor.voltage_sensor_align = 3;

// choose FOC modulation (optional)
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

// set motion control loop to be used
motor.controller = MotionControlType::torque;

// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC();

// add target command T
command.add('T', doTarget, "target voltage");

Serial.println(F("Motor ready."));
Serial.println(F("Set the target voltage using serial terminal:"));
_delay(1000);
}


void loop() {

// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
motor.loopFOC();

// 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_voltage);

// user communication
command.run();
}
1 change: 1 addition & 0 deletions src/SimpleFOC.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ void loop() {
#include "sensors/MagneticSensorAnalog.h"
#include "sensors/MagneticSensorPWM.h"
#include "sensors/HallSensor.h"
#include "sensors/LinearHallSensor.h"
#include "sensors/GenericSensor.h"
#include "drivers/BLDCDriver3PWM.h"
#include "drivers/BLDCDriver6PWM.h"
Expand Down
194 changes: 194 additions & 0 deletions src/sensors/LinearHallSensor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#include "LinearHallSensor.h"
#include "./communication/SimpleFOCDebug.h"

/** LinearHallSensor(uint8_t _pinAnalog, int _min, int _max)
* @param _pinAnalog the pin that is reading the pwm from magnetic sensor
* @param _min_raw_count the smallest expected reading. Whilst you might expect it to be 0 it is often ~15. Getting this wrong results in a small click once per revolution
* @param _max_raw_count the largest value read. whilst you might expect it to be 2^10 = 1023 it is often ~ 1020. Note: For ESP32 (with 12bit ADC the value will be nearer 4096)
*/
LinearHallSensor::LinearHallSensor(uint8_t _pinAnalog_a, uint8_t _pinAnalog_b)
{
pinAnalog_a = _pinAnalog_a;
pinAnalog_b = _pinAnalog_b;

if (pullup == Pullup::USE_INTERN)
{
pinMode(pinAnalog_a, INPUT_PULLUP);
pinMode(pinAnalog_b, INPUT_PULLUP);
}
else
{
pinMode(pinAnalog_a, INPUT);
pinMode(pinAnalog_b, INPUT);
}
}

/**
* @brief 线性传感器初始化
*
*/
void LinearHallSensor::init(int _min_raw_count_a, int _max_raw_count_a,
int _min_raw_count_b, int _max_raw_count_b)
{
raw_count_a = getRawCountA();
raw_count_b = getRawCountB();

if (_isset(_min_raw_count_a) && _isset(_max_raw_count_a) && _isset(_min_raw_count_b) && _isset(_max_raw_count_b))
{
/** LinearHall A */
min_raw_count_a = _min_raw_count_a;
max_raw_count_a = _max_raw_count_a;
/** LinearHall B */
min_raw_count_b = _min_raw_count_b;
max_raw_count_b = _max_raw_count_b;
}
else
{
/** 开始旋转电机一周校准线性霍尔的最大最小值 */
int minA, maxA, minB, maxB, centerA, centerB;

minA = raw_count_a;
maxA = minA;
centerA = (minA + maxA) / 2;
minB = raw_count_b;
maxB = minB;
centerB = (minB + maxB) / 2;

SIMPLEFOC_DEBUG("Sensor start init");

// move one electrical revolution forward
for (int i = 0; i <= 5000; i++)
{
// float angle = _3PI_2 + _2PI * i / 500.0f;
// BLDCMotor::setPhaseVoltage(FOCMotor::voltage_sensor_align, 0, angle);

//手动旋转电机一周来检测霍尔最大最小值
int tempA = getRawCountA();
if (tempA < minA)
minA = tempA;
if (tempA > maxA)
maxA = tempA;
centerA = (minA + maxA) / 2;

int tempB = getRawCountB();
if (tempB < minB)
minB = tempB;
if (tempB > maxB)
maxB = tempB;
centerB = (minB + maxB) / 2;

if (i % 500 == 0)
{
static int num = 10;
SIMPLEFOC_DEBUG("Count down: ", num);
SIMPLEFOC_DEBUG("A: ", centerA);
SIMPLEFOC_DEBUG("B: ", centerB);
SIMPLEFOC_DEBUG("min A: ", minA);
SIMPLEFOC_DEBUG("max A: ", maxA);
SIMPLEFOC_DEBUG("min B: ", minB);
SIMPLEFOC_DEBUG("max B: ", maxB);

num--;
}

_delay(2);
}

min_raw_count_a = minA;
max_raw_count_a = maxA;

min_raw_count_b = minB;
max_raw_count_b = maxB;

SIMPLEFOC_DEBUG("Sensor init ok:");
SIMPLEFOC_DEBUG("A: ", centerA);
SIMPLEFOC_DEBUG("B: ", centerB);
SIMPLEFOC_DEBUG("min A: ", minA);
SIMPLEFOC_DEBUG("max A: ", maxA);
SIMPLEFOC_DEBUG("min B: ", minB);
SIMPLEFOC_DEBUG("max B: ", maxB);
}

cpr = max_raw_count_a - min_raw_count_a;

this->Sensor::init(); // call base class init
}

/**
* @brief Shaft angle calculation
*
* @return angle is in radians [rad] float [0,2PI]
*/
float LinearHallSensor::getSensorAngle()
{
/* 1.获取双霍尔原始模拟值 */
raw_count_a = getRawCountA();
raw_count_b = getRawCountB();

/* 2.双霍尔模拟值滤波 */

/* 3.双霍尔滤波后值映射到[-1,1] */
this->hall_filtered_a = map_float(raw_count_a, min_raw_count_a, max_raw_count_a, -1, 1);
this->hall_filtered_b = map_float(raw_count_b, min_raw_count_b, max_raw_count_b, -1, 1);

/* 4.反正切函数计算轴角度[-180,180] */
float angle = atan2(hall_filtered_a, hall_filtered_b) * 180 / PI;

/* 5.轴角转为弧度制[0,2PI] */
return (angle + 180) * PI / 180.0f;
}

/**
* @brief Reading the raw counter of the linear hall sensor A
*
* @return int
*/
int LinearHallSensor::getRawCountA()
{
return analogRead(pinAnalog_a);
}

/**
* @brief Reading the raw counter of the linear hall sensor B
*
* @return int
*/
int LinearHallSensor::getRawCountB()
{
return analogRead(pinAnalog_b);
}

/**
* @brief 数据映射 float
*
* @param in_x 输入值
* @param in_min 输入值的最小幅值
* @param in_max 输入值的最大幅值
* @param out_min 输出值的最小幅值
* @param out_max 输出值的最大幅值
* @return float 映射后的输出值
*/
float LinearHallSensor::map_float(float in_x, float in_min, float in_max, float out_min, float out_max)
{
return (in_x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

/**
* @brief 获取线性霍尔A滤波后的值
*
* @return float [-1,1]
*/
float LinearHallSensor::getHallFiledA()
{
return this->hall_filtered_a;
}

/**
* @brief 获取线性霍尔B滤波后的值
*
* @return float [-1,1]
*/
float LinearHallSensor::getHallFiledB()
{
return this->hall_filtered_b;
}
69 changes: 69 additions & 0 deletions src/sensors/LinearHallSensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#ifndef LINEARHALLSENSOR_LIB_H
#define LINEARHALLSENSOR_LIB_H

#include "Arduino.h"
#include "../common/base_classes/Sensor.h"
#include "../common/foc_utils.h"
#include "../common/time_utils.h"

/**
* This sensor has LinearHallSensor.
* This approach is very simple.
*/
class LinearHallSensor : public Sensor
{
public:
/**
* LinearHallSensor class constructor
* @param _pinAnalog_a the pin to read the HALL A signal
* @param _pinAnalog_b the pin to read the HALL B signal
*/
LinearHallSensor(uint8_t _pinAnalog_a, uint8_t _pinAnalog_b);

/** sensor initialise pins */
void init(int _min_raw_count_a = NOT_SET, int _max_raw_count_a = NOT_SET,
int _min_raw_count_b = NOT_SET, int _max_raw_count_b = NOT_SET);

uint8_t pinAnalog_a; //!< Linear Hall pin A
uint8_t pinAnalog_b; //!< Linear Hall pin B

/** Encoder configuration */
Pullup pullup;

/** implementation of abstract functions of the Sensor class */
/** get current angle (rad) */
float getSensorAngle() override;
/** raw count (typically in range of 0-1023), useful for debugging resolution issues */
int raw_count_a;
int raw_count_b;

/** 获取霍尔滤波后的值[-1,1] */
float getHallFiledA();
float getHallFiledB();

/** 数据映射 */
float map_float(float in_x, float in_min, float in_max, float out_min, float out_max);

private:
/** LinearHall 实际输出模拟值范围 */
int min_raw_count_a;
int max_raw_count_a;
int min_raw_count_b;
int max_raw_count_b;

/** LinearHall 滤波后值映射到[-1,1] */
float hall_filtered_a;
float hall_filtered_b;

int cpr;
int read();

/**
* Function getting current angle register value
* it uses angle_register variable
*/
int getRawCountA();
int getRawCountB();
};

#endif
Binary file added 双线性霍尔角度计算.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.