一、模块了解
我们在使用模块时,要进行所用的传感器的有一定的了解,霍尔角度传感器是一种微型360度传感器,其基于霍尔效应原理工作。它与DFRobot重力传感器接口兼容,并使用5V DC电源。模拟输出也是0〜5V,因此可以直接与Arduino一起使用。
霍尔角度传感器通过将其角度信息转换为电信号来工作。当物体的旋转角度传递到旋转轴传感器时,它会输出与旋转角度成比例的电信号。
首先要特性了解:
其次是机械结构了解:
二、模块连接图(单模块)
将P3022-V1-CW360模块的OUT引脚连接到Uno的A2模拟口,GNG<–>GND,VCC<–>5V。(这有个注意点,我们应该用电压表测量一下基准电压的实际大小,我的实际测量就是4.980,有的可能误差很大。)
三、测试代码(单模块)
AD采样的代码(未将其转化成角度):
/***************************************************
* Hall angle sensor
* ****************************************************
* This example for AD
* @author YUYU
* @version V1.0
* @date 2019-10-19
* ****************************************************/
void setup()
{
Serial.begin(115200);
}
void loop()
{
float analogValue = analogRead(A2); //Voltage reading
float Voltage = analogValue/1024.0 * 4.980; //Angle calculation ( UNO is a 10-bit AD )
Serial.print("Voltage:");
Serial.println(Voltage);
}
测试结果:
由上测试结果可看:误差在0.01v。
转化为角度的第一版测试代码如下:
/***************************************************
* Hall angle sensor
* ****************************************************
* This example for AD
* @author YUYU
* @version V1.0
* @date 2019-10-20
* ****************************************************/
const int PIN_AD = A0; //pin connection
float sensorVolt; //unit: mV
float angle; //unit: centigrade
void setup()
{
sensorVolt =0;
pinMode(PIN_AD,INPUT);
Serial.begin(115200);
}
void loop()
{
sensorVolt = analogRead(PIN_AD); //转后的电压值
angle =(sensorVolt)/1024 * 360.0; //Angle calculation ( UNO is a 10-bit AD )
Serial.print("angle: "); //print the result
Serial.println(angle);
Serial.println("°");
}
执行的结果:
又找了比较多的资料,进行改版后的代码:
/***************************************************
* Hall angle sensor
* ****************************************************
* This example for AD
* @author YUYU
* @version V1.0
* @date 2019-10-21
* ****************************************************/
const int PIN_AD = A0; //pin connection
float sensorVolt; //unit: mV
float angle; //unit: centigrade
void setup()
{
sensorVolt =0;
pinMode(PIN_AD,INPUT);
Serial.begin(115200);
}
void loop()
{
sensorVolt = analogRead(PIN_AD); //转后的电压值
angle=sensorVolt/2.82; //这个代码的改写原理有点没搞懂,但是可以实现306度
Serial.print("angle: "); //print the result
Serial.println(angle);
Serial.println("°");
}
执行结果:
四、整体测试(电机+激光+角度传感器)
1.采样频率为默认情况下的测试
测试代码:
/***************************************************
* Hall angle sensor
* ****************************************************
* This example for AD
* @author YUYU
* @version V1.1
* @date 2019-10-22
* ****************************************************/
#define dir_pin 2
#define en_pin 5
#define stp_pin 6
//角度传感器的相关参数
const int PIN_AD = A0; //pin connection
float sensorVolt =0; //unit: mV
float angle; //unit: centigrade
//激光雷达的相关变量机常量
float range = 0;//目标距离
unsigned char uart[8]={0},counter = 0;//存放雷达测量的数据
unsigned char data[3]={0};
unsigned char sign=0;
const unsigned char HEADER=0x55;//数据包帧头
const unsigned char END=0xAA;//终止序列
//将接收的数据整合到一个结构体中,使其存储到一个连续的内存中,较为高效
struct Target_Bits
{
unsigned char Target_header:8; /* 0:7 */
unsigned char Target_key:8; /* 8:15 */
unsigned char Target_value:8; /* 16:23 */
unsigned char Target_data1:8; /* 24:31 */
unsigned char Target_data2:8; /* 32:39 */
unsigned char Target_data3:8; /* 40:47 */
unsigned char Target_CRC:8; /* 48:55 */
unsigned char Target_end:8; /* 56:63 */
};
//联合表示几个变量公用一个内存位置, 在不同的时间保存不同的数据类型和不同长度的变量
typedef union{
unsigned char Byte[8];
struct Target_Bits bit;
}TargetData;
void setup()
{
Serial.begin(115200);//设置arduino与电脑连接串口的波特率
Serial1.begin(115200);//设置雷达与arduino连接串口的波特率
//set timer4
TCCR4A = 0;
TCCR4B = 0;
TCNT4 = 0;
// Mode 10: phase correct PWM with ICR4 as Top (= F_CPU/2/25000)
// OC4A OC4B OC4C as Non-Inverted PWM output
ICR4 = (F_CPU/2000)/2;
TCCR4A =_BV(COM4A1) | _BV(COM4B1) | _BV(COM4C1) | _BV(WGM41);
TCCR4B = _BV(WGM43) | _BV(CS40);
// Set the PWM pin as output.
pinMode(2,OUTPUT);
pinMode(6, OUTPUT);
//模拟量输入
pinMode(PIN_AD,INPUT);
}
void loop()
{
//just set this for step motor
Pwm_out(6,1000);
digitalWrite(2,HIGH);
sensorVolt = analogRead(PIN_AD); //转后的电压值
angle=sensorVolt/2.82;
// Serial.print("angle: "); //print the result
// Serial.print(angle);
// Serial.println(" 度");
if(sign)
{
sign=0;
if(uart[1]==0x07)
{
TargetData TargetData;
for (uint8_t i = 0; i < 8; i++)
{
TargetData.Byte[i] = uart[i]; // Buf指向有效数据起始
// Serial.print(TargetData.Byte[i]);
// Serial.print("\n");
}
for(int j =0;j<3;++j)
{
data[j]=TargetData.Byte[j+3];
}
range=readCharToLL(data,3);
Serial.print(range);
Serial.print(",");
Serial.print(angle);
Serial.print("\n");
}
}
}
//激光数据采集
void serialEvent1() {
while (Serial1.available()) {
uart[counter]=(unsigned char)Serial1.read();
if(counter==0&&uart[0]!=HEADER) return; //第0号数据不是帧头
counter++;
if(counter==8) //接收到8个数据
{
counter=0; //重新赋值,准备下一帧数据的接收
sign=1;
}
}
}
/**
* 将unsigned char数组转换成long long数值
* @param str 数组
* @param len str数组长度
* @returns 0 on error
*/
int readCharToLL(unsigned char* str, int len)
{
if (str == NULL||len <= 0) //指针的判断
{
return 0;
}
int i = 0;
int value = 0;
for (i=0;i<len;i++)
{
value = value*16*16 + (str[i]/16)*16 + str[i]%16;
}
return value;
}
//motor driver
void Pwm_out(int pin ,int value)
{
switch(pin){
case 5:
OCR3A = value;
break;
case 6:
OCR4A = value;
break;
case 7:
OCR4B = value;
break;
case 8:
OCR4C = value;
break;
default:
//no other pin will work
break;
}
}
测试结果:
从上图看,角度值有缺失(这个问题还有待探究)