位置检测有哪些传感器可以用?(带磁编码器AS5600代码)

news2024/9/27 9:30:46

常见的有三种

编码器、霍尔传感器、磁传感器。

编码器一般指AB相正交脉冲的增量器件,有的还会有一个Z相信号,用来指示零位;

霍尔传感器一般是指ABC三个成120度角度间隔排列的器件,这种传感器一般集成在电机内部,电机每转一圈会生成6N个信号,每个信号代表电机转到了特定的角度;

磁编码器本质上也是靠霍尔效应检测,但它是一种输出绝对位置的器件,这类传感器一般都有多种接口,如SPI、IIC、模拟值或PWM占空比。

编码器

编码器是一种用于运动控制的传感器,利用光电、电磁、电容或者电感等感应原理,来检测物体的机械或者位置变化,然后把信息转化为电信号输出,作为运动的反馈。

旋转编码器

光电编码器

通过光电转换,将输出轴的角位移、角速度等机械两转化为电脉冲,以数字量输出。

磁式编码器

电容式编码器

增量式编码器

资料

链接:https://pan.baidu.com/s/1Hp1fucofpC7nCn8-D8w_0A?pwd=pvpm
提取码:pvpm

代码

SimpleFOC Library设计了两种正交编码器的计数方法:

正交计数:对信号A和B的每次跳变都进行采样,这样在每个脉冲周期内将有四次信号跳变,采样四次,计数四次(即CPR Count Per Rotation),具体计算见以下源码。 普通计数:对信号A和B的上升沿进行计数,这样每个脉冲周期内将有两次信号跳变,采样两次,但只对某一个通道计数一次(即PPR Pulses Per Rotation),具体计算见以下源码。 正交模式下CPR = PPR*4 普通模式下CPR = PPR,显然正交模式下分辨率更高,但系统开支也更大,如果对分辨率要求不高可以使用普通模式。

MCU对A和B信号线连接的两个IO口使能外部中断,中断回调函数中实现了计数,回调函数源码如下所示,A和B两个通道的回调函数内容一样,只以A通道为例说明。

//定义对象,使能外部中断
Encoder encoder = Encoder(2, 3, 8192);      //定义正交编码器对象,连接到2和3号引脚,编码器PPR=8192
void doA(){encoder.handleA();}              //A通道中断回调函数
void doB(){encoder.handleB();}              //B通道中断回调函数
encoder.enableInterrupts(doA, doB);         //使能外部中断,设置回调函数

void Encoder::enableInterrupts(void (*doA)(), void(*doB)(), void(*doIndex)())
{
  // attach interrupt if functions provided
  switch(quadrature){        //quadrature:是否开启正交模式
    case Quadrature::ON:
      // A callback and B callback
      if(doA != nullptr) attachInterrupt(digitalPinToInterrupt(pinA), doA, CHANGE);
      if(doB != nullptr) attachInterrupt(digitalPinToInterrupt(pinB), doB, CHANGE);
      break;
    case Quadrature::OFF:
      // A callback and B callback
      if(doA != nullptr) attachInterrupt(digitalPinToInterrupt(pinA), doA, RISING);
      if(doB != nullptr) attachInterrupt(digitalPinToInterrupt(pinB), doB, RISING);
      break;
  }

  //如果有Z相信号线,使能Z相的中断
  if(hasIndex() && doIndex != nullptr) attachInterrupt(digitalPinToInterrupt(index_pin), doIndex, CHANGE);
}

//  Encoder interrupt callback functions
// A channel
void Encoder::handleA()
{
  bool A = digitalRead(pinA);                       //测量A引脚高低电平
  switch (quadrature)
  {                               
    case Quadrature::ON:                            //正交模式下:
    // CPR = 4xPPR
     if ( A != A_active )                           //如果A引脚状态不等于"当前记录的状态"
     {
       //如果A引脚"当前记录的状态"等于B引脚"当前记录的状态"计数+1
       //对应图六中左侧A信号的上升沿与下降沿状态
       //否则为逆时针旋转,计数-1
       pulse_counter += (A_active == B_active) ? 1 : -1;
       pulse_timestamp = _micros();
       A_active = A;                                 //更新A引脚当前状态
     }
     break;
   case Quadrature::OFF:                             //普通模式下
   // CPR = PPR
     if(A && !digitalRead(pinB))                     //如果A引脚是高电平且B引脚是低电平
     {
       pulse_counter++;                              //计数+1,对应图六中左上角A上升沿状态
       pulse_timestamp = _micros();
     }
     break;
   }
}

霍尔传感器

如上图所示,右侧的3个器件就是霍尔传感器,它们成120度夹角安装,也有60度安装的,但控制逻辑不一样。本节以一对极120度夹角电机模型说明。一对极指转子只有一对磁铁NS极,图四为多对极电机。

按特定的组合给电机的UVW三相供电,如U+,V-,W断开,此时电机转子将转到某一固定位置,假设为扇区Sector1,然后切换供电状态为W+,V-,U断开,电机将继续旋转60度到扇区二,按特定的顺序依次切换供电状态,电机将会一直转动下去,共有6种供电状态,对应着6个扇区,6种霍尔传感器的触发状态,如下图所示。

图六、霍尔的六种触发状态

霍尔传感器就是根据这六种状态确定转子的位置,加上这6种状态的循环次数就是当前电机转子的真实位置。

//HallSensor.h
//霍尔传感器状态与扇区对应关系
// seq 1 > 5 > 4 > 6 > 2 > 3 > 1     000 001 010 011 100 101 110 111
const int8_t ELECTRIC_SECTORS[8] = { -1,  0,  4,  5,  2,  1,  3 , -1 };

霍尔位置传感器的程序源码与ABZ正交编码器程序源码基本相同,引脚配置和外部中断设置基本相同,主要内容在updateState函数中,下边简单分析updateState函数。

void HallSensor::updateState() 
{
 long new_pulse_timestamp = _micros();
 //刷新三个霍尔传感器的状态
 int8_t new_hall_state = C_active + (B_active << 1) + (A_active << 2);
 //去除噪声
  // glitch avoidance #1 - sometimes we get an interrupt but pins haven't changed
 if (new_hall_state == hall_state) {
 return;
  }
 hall_state = new_hall_state;
 //匹配当前所在扇区
 int8_t new_electric_sector = ELECTRIC_SECTORS[hall_state];
 static Direction old_direction;
 //
 if (new_electric_sector - electric_sector > 3) {    //如从扇区0转到了扇区5,则循环次数-1
    //underflow
 direction = Direction::CCW;
 electric_rotations += direction;
  } else if (new_electric_sector - electric_sector < (-3)) {//如从扇区5转到了扇区0,则循环次数+1
    //overflow
 direction = Direction::CW;
 electric_rotations += direction;
  } else {
 direction = (new_electric_sector > electric_sector)? Direction::CW : Direction::CCW;
  }
 electric_sector = new_electric_sector;

  // glitch avoidance #2 changes in direction can cause velocity spikes.  Possible improvements needed in this area
 if (direction == old_direction) {
    // not oscilating or just changed direction
 pulse_diff = new_pulse_timestamp - pulse_timestamp;
  } else {
 pulse_diff = 0;
  }
 
 pulse_timestamp = new_pulse_timestamp;
 total_interrupts++;
 old_direction = direction;
 if (onSectorChange != nullptr) onSectorChange(electric_sector);
}

磁编码器

磁编码器有基于霍尔效应原理的,也有基于磁阻效应的。SimpleFOC项目使用的有以下几种,这里以AS5600说明。

/** Typical configuration for the 12bit AMS AS5600 magnetic sensor over I2C interface */
MagneticSensorI2CConfig_s AS5600_I2C = {
  .chip_address = 0x36,
  .bit_resolution = 12,
  .angle_register = 0x0C,
  .data_start_bit = 11
};

/** Typical configuration for the 12bit AMS AS5048 magnetic sensor over I2C interface */
MagneticSensorI2CConfig_s AS5048_I2C = {
  .chip_address = 0x40,  // highly configurable.  if A1 and A2 are held low, this is probable value
  .bit_resolution = 14,
  .angle_register = 0xFE,
  .data_start_bit = 15
};

/** Typical configuration for the 14bit AMS AS5147 magnetic sensor over SPI interface */
MagneticSensorSPIConfig_s AS5147_SPI = {
  .spi_mode = SPI_MODE1,
  .clock_speed = 1000000,
  .bit_resolution = 14,
  .angle_register = 0x3FFF,
  .data_start_bit = 13, 
  .command_rw_bit = 14,
  .command_parity_bit = 15
};
// AS5048 and AS5047 are the same as AS5147
MagneticSensorSPIConfig_s AS5048_SPI = AS5147_SPI;
MagneticSensorSPIConfig_s AS5047_SPI = AS5147_SPI;

/** Typical configuration for the 14bit MonolithicPower MA730 magnetic sensor over SPI interface */
MagneticSensorSPIConfig_s MA730_SPI = {
  .spi_mode = SPI_MODE0,
  .clock_speed = 1000000,
  .bit_resolution = 14,
  .angle_register = 0x0000,
  .data_start_bit = 15, 
  .command_rw_bit = 0,  // not required
  .command_parity_bit = 0 // parity not implemented
};

原理

AS5600

是基于霍尔的旋转磁位置传感器,有12位高分辨率,使用平面传感器来将垂直于芯片表面的磁场分量转换为电压。它有3种输出方式,模拟值,PWM和IIC。

模拟值模式

//examples\utils\sensor_test\magnetic_sensors\magnetic_sensor_analog_example\find_raw_min_max\find_raw_min_max.ino
#include <SimpleFOC.h>
/**
 * 编码器处于Analog模式,指定AD引脚,它的电压与位置成线性正比
 */
//AD使用A1引脚,AD最小值为14,最大值为1020,10位AD采样
MagneticSensorAnalog sensor = MagneticSensorAnalog(A1, 14, 1020);

void setup()
{
  // monitoring port
 Serial.begin(115200);
  //传感器初始化,读取一次AD值,并记录当前时间
 sensor.init();
 Serial.println("Sensor ready");
 _delay(1000);
}

void loop() {
  // display the angle and the angular velocity to the terminal
 Serial.print(sensor.getAngle());
 Serial.print("\t");
 Serial.println(sensor.getVelocity());
}
//src\sensors\MagneticSensorAnalog.cpp
#include "MagneticSensorAnalog.h"
MagneticSensorAnalog::MagneticSensorAnalog(uint8_t _pinAnalog, int _min_raw_count, int _max_raw_count)
{
 pinAnalog = _pinAnalog;                   //AD引脚
 cpr = _max_raw_count - _min_raw_count;    //cpr计算
 min_raw_count = _min_raw_count;
 max_raw_count = _max_raw_count;

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

}


void MagneticSensorAnalog::init()
{
  // velocity calculation init
 angle_prev = 0;
 velocity_calc_timestamp = _micros(); 

  // full rotations tracking number
 full_rotation_offset = 0;
 raw_count_prev = getRawCount();       //读取一次当前AD值
}

//  Shaft angle calculation
//  angle is in radians [rad]
float MagneticSensorAnalog::getAngle(){
  //读取一次当前AD值
 raw_count = getRawCount(); 
//计算AD值变化量,如果变化量大于0.8cpr,则认为已经进入下一圈了,或者是后退到上一圈了
 int delta = raw_count - raw_count_prev;
  // if overflow happened track it as full rotation
 if(abs(delta) > (0.8*cpr) ) full_rotation_offset += delta > 0 ? -_2PI : _2PI; 
 //计算绝对角度,弧度
 float angle = full_rotation_offset + ( (float) (raw_count) / (float)cpr) * _2PI;

  //计算速度
 long now = _micros();
 float Ts = ( now - velocity_calc_timestamp)*1e-6;
  // quick fix for strange cases (micros overflow)
 if(Ts <= 0 || Ts > 0.5) Ts = 1e-3; 
 velocity = (angle - angle_prev)/Ts;

  // save variables for future pass
 raw_count_prev = raw_count;
 angle_prev = angle;
 velocity_calc_timestamp = now;

 return angle;
}

// function reading the raw counter of the magnetic sensor
int MagneticSensorAnalog::getRawCount(){
 return analogRead(pinAnalog);//AD阻塞采样
}

磁编码器的模拟值输出方式计算位置原理十分简单,只是一个AD值到角度的线性转换,需要注意的是AD的最大最小值最好自己测量一下,避免误差。另外一个需要注意的地方是getAngle()函数需要以较高的频率调用(频率跟电机转动速度相关),否则可能会导致角度计算错误,最好是使用定时器定时调用,或者在多任务系统种单独一个任务以固定周期调用该函数。

上述源码AD采样使用的是阻塞方式采样,STM32中我们可以使用中断或DMA中断方式采样,在中断函数中调用getAngle()函数,并开启下一次采样。

PWM模式

PWM模式和模拟值输出模式很相似,只是将模拟值输出的电压变成了PWM形式,PWM的高电平时间与角度成正比。

examples\utils\sensor_test\magnetic_sensors\magnetic_sensor_pwm_example\magnetic_sensor_pwm\magnetic_sensor_pwm.ino
#include <SimpleFOC.h>
/**
 * MagneticSensorPWM(uint8_t MagneticSensorPWM, int _min, int _max)
 * - pinPWM         - PWM输入引脚
 * - min_raw_count  - 最短高电平时间us
 * - max_raw_count  - 最长高电平时间us
*/
MagneticSensorPWM sensor = MagneticSensorPWM(2, 4, 904);
//定义中断回调函数
void doPWM(){sensor.handlePWM();}

void setup() {
  // monitoring port
 Serial.begin(115200);

  // initialise magnetic sensor hardware
 sensor.init();
  //使能外部中断(监测引脚上升沿下降沿)检测PWM引脚高电平时间
  //如果注释掉这一句,则以默认的阻塞方式检测PWM引脚高电平时间
 sensor.enableInterrupt(doPWM);

 Serial.println("Sensor ready");
 _delay(1000);
}

void loop() {
  // display the angle and the angular velocity to the terminal
 Serial.print(sensor.getAngle());
 Serial.print("\t");
 Serial.println(sensor.getVelocity());
}

IIC模式

AS5600可以使用IIC通信方式得到角度数据,需要注意的是,AS5600的地址是固定的,也就是说IIC总线上只能有一个AS5600。如果想要使用多个AS5600就需要多个IIC总线。

//examples\utils\sensor_test\magnetic_sensors\magnetic_sensor_i2c_example\magnetic_sensor_i2c_example.ino
#include <SimpleFOC.h>
// Example of AS5600 configuration 
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);

void setup() {
  // monitoring port
 Serial.begin(115200);

  //i2C使用快速模式400K
 Wire.setClock(400000);
  // initialise magnetic sensor hardware
 sensor.init();

 Serial.println("Sensor ready");
 _delay(1000);
}

void loop() {
  // display the angle and the angular velocity to the terminal
 Serial.print(sensor.getAngle());
 Serial.print("\t");
 Serial.println(sensor.getVelocity());
}

参考

无刷电机控制器分析(1.1)SimpleFOC位置检测传感器例程源码分析 - 知乎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/139983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Amazon]人工智能入门学习笔记---AI-机器学习-深度学习

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea; (*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &a…

基于模型预测控制的波浪能转换器(WEC)研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Flink简介

Flink 系列教程传送门 第一章 Flink 简介 第二章 Flink 环境部署 第三章 Flink DataStream API 第四章 Flink 窗口和水位线 第五章 Flink Table API&SQL 第六章 新闻热搜实时分析系统 前言 流计算产品实时性有两个非常重要的实时性设计因素&#xff0c;一个是待计算…

基于 Docker 的 Neo4j 部署及数据备份与恢复

目录一、部署二、验证三、备份3.1 离线备份3.2 在线备份3.3 社区版备份一、部署 1、pull 镜像 docker pull neo4j:4.4.16-community2、创建目录 mkdir -p /home/data/neo4j/{data,logs,conf,import,db-backup}3、运行容器 docker run -itd \--name neo4j \--restart always…

openwrt-看门狗watchdog

一、硬件watchdog和软件watchdog Linux内核不仅为各种不同类型的watchdog硬件电路提供了驱动&#xff0c;还提供了一个基于定时器的纯软件watchdog驱动&#xff0c;软件watchdog基于内核的定时器实现&#xff0c;当内核或中断出现异常时&#xff0c;软件watchdog是无法复位系统…

二叉树17:路径总和

主要是我自己刷题的一些记录过程。如果有错可以指出哦&#xff0c;大家一起进步。 转载代码随想录 原文链接&#xff1a; 代码随想录 leetcode链接&#xff1a;112. 路径总和 112. 路径总和 题目&#xff1a; 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判…

判断图中有没有证件图片

整体解决思路: 前提:拍摄场景光线稳定,证件没有放在图像边缘;且图片使用的证件阅读器拍摄的红外图片,采用了开灯和关灯各拍摄一张图片,图像相减,进行了背景去除; 1)使用二值化和膨胀腐蚀以及sobel算子等进行图像的预处理; 2)进行凸包计算,通过角度,进行证件区域…

缓存穿透,缓存雪崩,缓存击穿的超详解

文章目录1、缓存穿透问题的解决思路2、缓存雪崩问题及解决思路3、缓存击穿问题及解决思路1、缓存穿透问题的解决思路 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这些请求都会打到数据库&#xff0c;失去了缓存的意…

pytorch数据dataset的三种读取方式

文章目录1.自带的datasets2.ImageFolder3.自己创建的dataset&#xff08;用的多&#xff09;1.自带的datasets pytorch自带的数据集 具体数据集如下&#xff1a; 用法&#xff1a; 可以用的功能 2.ImageFolder 文件形式如下时用此&#xff1a;&#xff08;一个文件下只…

MyBatis框架 入门案例

二刷复习简介MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff08;Plain Old Jav…

磨金石教育科技摄影技能干货分享|艺术摄影的本源是创作,核心是表达

艺术类的作品一直都有一个风格&#xff0c;那就是抽象。特别是摄影领域&#xff0c;一幅作品如果缺乏创意&#xff0c;只是展现现实的景物&#xff0c;那么很容易就变成了纪实摄影或者风光摄影。因此&#xff0c;要想让作品突出艺术性&#xff0c;就要再原有的画面上&#xff0…

Exynos_4412——中断处理(中断学习结尾篇)

目录 一、ARM的异常处理机制 1.1异常概念 1.2异常处理机制 1.3ARM异常源 1.4异常模式 1.5ARM异常响应 1.6异常向量表 1.7异常返回 1.8IRQ异常举例 二、工程模板代码结构 三、中断处理框架搭建 四、中断处理程序 五、用key3再试一试 前景提要&#xff1a; Exynos_…

利用Model Inspector的建模规则检查

利用Model Inspector的规则检查 Model Inspector是一种基于模型的软件静态验证自动化解决方案。通过对模型进行规则检查,开发人员的工作成本将减少,开发效率将会大大提高。 Model Inspector支持各种行业标准建模规范,对违反规范进行检查。 用户可通过dashboard获知模型质量指标…

滴滴前端一面常考手写面试题合集

使用Promise封装AJAX请求 // promise 封装实现&#xff1a; function getJSON(url) {// 创建一个 promise 对象let promise new Promise(function(resolve, reject) {let xhr new XMLHttpRequest();// 新建一个 http 请求xhr.open("GET", url, true);// 设置状态的…

磨金石教育摄影技能干货分享|优秀摄影作品欣赏——艺术的表达

艺术摄影是难以欣赏的&#xff0c;这是大部分人的共识。艺术作品的创作也自然具有较高的难度&#xff0c;很多时候画面的表达与思想不符。要么内容不足以反应思想&#xff0c;要么思想太浅&#xff0c;而内容太杂。想要真正理解作者要表达什么&#xff0c;就要从内容去逐个分解…

ZigBee案例笔记 -- 外部中断

文章目录1.中断概述2.中断屏蔽3.中断处理4.按键中断控制LED1.中断概述 CC2530有18个中断源&#xff0c;每个中断源都有它自己的位于一系列 SFR 寄存器中的中断请求标志。相应标志位请求的每个中断可以分别使能或禁用&#xff0c;中断分别组合为不同的、可以选择的优先级别&…

分布式ID之雪花算法

分布式ID常见生成策略 分布式ID生成策略常见的有如下几种: 数据库自增ID。UUID生成。Redis的原子自增方式。数据库水平拆分&#xff0c;设置初始值和相同的自增步长。批量申请自增ID。雪花算法。百度UidGenerator算法(基于雪花算法实现自定义时间戳)。美团Leaf算法(依赖于数据…

【ZooKeeper】第一章 快速入门

【ZooKeeper】第一章 快速入门 文章目录【ZooKeeper】第一章 快速入门一、概念二、安装1.环境准备2.安装3.配置二、命令操作1.数据模型2.服务端常用命令3.客户端常用命令一、概念 ZooKeeper 是 Apache Hadoop 项目下的一个子项目&#xff0c;是一个树形目录服务ZooKeeper 翻译…

SpringBoot使用SchedulingConfigurer实现多个定时任务多机器部署问题

目录一、使用SchedulingConfigurer实现多个定时任务二、定时任务多机器部署解决方案三、基于redis实现的代码示例3.1、基于redis实现的概述3.2、基于redis实现的代码3.2.1、代码目录结构3.2.2、引入依赖包3.2.3、配置文件新增redis连接配置3.2.4、自定义redis锁注解类3.2.5、自…

Linux 块设备驱动

1.块设备是针对存储设备的&#xff0c;比如 SD 卡、 EMMC、 NAND Flash、 Nor Flash、 SPI Flash、机械硬盘、固态硬盘等。因此块设备驱动其实就是这些存储设备驱动&#xff0c;块设备驱动相比字符设备驱动的主要区别如下&#xff1a; ①、块设备只能以块为单位进行读写访问&am…