嵌入式算法之空间向量夹角公式及其应用

开发 前端 算法
有些设备正常工作时需按合适的方位安装,比如GPS天线必须朝向天空才能保证信号最佳,温湿度传感器监测口必须朝向被测目标才能及时响应。软件需求是在安装角度异常时提醒用户改变位置。

[[350122]]

有些设备正常工作时需按合适的方位安装,比如GPS天线必须朝向天空才能保证信号最佳,温湿度传感器监测口必须朝向被测目标才能及时响应。软件需求是在安装角度异常时提醒用户改变位置。那设备如何感知当前方位呢?需要一颗加速度传感器硬件支持,辅以算法实现。

1、重力加速度

根据物理常识,地面上任何物体静止时都受到1g的重力加速度,且方向是竖直向下。

 

因为倾斜角的不同,1g的加速度按向量分解到xyz三轴:

  • acc_x=1g.sinθ.cosϕ
  • acc_y=-1g.sinθ.sinϕ
  • acc_z=1g.cosϕ

符号.代表相乘,读取加速度传感器的xyz三轴数据的细节,不是本文考虑的范畴。

因为传感器的位数精度和量程不同,同样的1g,读寄存器的数值不同,为统一后文描述,假设数值255对应1g的加速度。物体水平静止时加速度值理想情况是(0,0,255),反向水平放置是(0,0,-255)。这个数值等比例的缩小或放大,不影响角度的判断。

2、空间向量夹角

假设期望的正确安装方式下三轴是(x0,y0,z0),实际三轴数据是(x1,y1,z1)。那如何得出当前偏差的角度呢?已知两空间向量的坐标为a=(x1,y1,z1),b=(x2,y2,z2),则两向量的夹角余弦cosθ公式为:

 

在实际应用中,翻转角度为181度时,按179度处理。本文只考虑0-180度的应用,180度以上的需要额外再计算翻转。

 

根据空间向量夹角余弦,再反余弦得出在0-180度的角度,即可判断设备安装角度是否正确。

3、代码实现

  1. #include "math.h" 
  2. #include "stdio.h" 
  3.  
  4. #define PI  3.1415926 
  5.  
  6. typedef struct 
  7.     unsigned short x; 
  8.     unsigned short y; 
  9.     unsigned short z; 
  10. }sensor_data_struct; 
  11.  
  12. static sensor_data_struct ref={0,0,255}; 
  13. static sensor_data_struct test={0,180,180}; 
  14.  
  15. //计算当前向量与参考向量的夹角 
  16. float get_angle(sensor_data_struct data) 
  17.     float cosine; 
  18.     float temp,angle; 
  19.     cosine=(data.x*ref.x+data.y*ref.y+data.z*ref.z)/ \ 
  20.             ((sqrt(data.x*data.x+data.y*data.y+data.z*data.z))*\ 
  21.              (sqrt(ref.x*ref.x+ref.y*ref.y+ref.z*ref.z))); 
  22.  
  23.      temp=acos(cosine); 
  24.      angle=(temp*180)/PI; 
  25.      return angle; 
  26.  
  27. int main(int argc, char *argv[]) 
  28.     float angle; 
  29.     printf("reference vector (%d,%d,%d)\r\n",ref.x,ref.y,ref.z); 
  30.     printf("test vector (%d,%d,%d)\r\n",test.x,test.y,test.z); 
  31.     angle=get_angle(test); 
  32.     printf("angle = %f'\r\n",angle); 
  33.     return 0; 
  • reference vector (0,0,255)
  • test vector (0,180,180)
  • angle = 45.000004'

4、优化改进

求解角度使用的三角函数,部分单片机可能不支持;对角度的精度,使用整形即可。基于这个条件,可以建立cosθ的数组表,以1度--2度--3度---180度步进,按如下代码生成数组表:

  1. void creat_table(void) 
  2.     float i; 
  3.     for(i=0;i<180;i++)//i的步进值决定精度 
  4.     { 
  5.         if((unsigned char )i%9==0) 
  6.         { 
  7.             printf("\r\n"); 
  8.         } 
  9.         printf("%f,",cos(i*PI/180));//角度转弧度再传入 
  10.     } 

根据代码生成数组表后,查找余弦表,数组的下标即为角度。

  1. static const float cos_table[180]={ 
  2.     1.000000,0.999848,0.999391,0.998630,0.997564,0.996195,0.994522,0.992546,0.990268, 
  3.     0.987688,0.984808,0.981627,0.978148,0.974370,0.970296,0.965926,0.961262,0.956305, 
  4.     0.951057,0.945519,0.939693,0.933580,0.927184,0.920505,0.913545,0.906308,0.898794, 
  5.     0.891007,0.882948,0.874620,0.866025,0.857167,0.848048,0.838671,0.829038,0.819152, 
  6.     0.809017,0.798636,0.788011,0.777146,0.766044,0.754710,0.743145,0.731354,0.719340, 
  7.     0.707107,0.694658,0.681998,0.669131,0.656059,0.642788,0.629320,0.615661,0.601815, 
  8.     0.587785,0.573576,0.559193,0.544639,0.529919,0.515038,0.500000,0.484810,0.469472, 
  9.     0.453991,0.438371,0.422618,0.406737,0.390731,0.374607,0.358368,0.342020,0.325568, 
  10.     0.309017,0.292372,0.275637,0.258819,0.241922,0.224951,0.207912,0.190809,0.173648, 
  11.     0.156434,0.139173,0.121869,0.104528,0.087156,0.069756,0.052336,0.034900,0.017452, 
  12.     0.000000,-0.017452,-0.034899,-0.052336,-0.069756,-0.087156,-0.104528,-0.121869,-0.139173, 
  13.     -0.156434,-0.173648,-0.190809,-0.207912,-0.224951,-0.241922,-0.258819,-0.275637,-0.292372, 
  14.     -0.309017,-0.325568,-0.342020,-0.358368,-0.374607,-0.390731,-0.406737,-0.422618,-0.438371, 
  15.     -0.453990,-0.469472,-0.484810,-0.500000,-0.515038,-0.529919,-0.544639,-0.559193,-0.573576, 
  16.     -0.587785,-0.601815,-0.615661,-0.629320,-0.642788,-0.656059,-0.669131,-0.681998,-0.694658, 
  17.     -0.707107,-0.719340,-0.731354,-0.743145,-0.754710,-0.766044,-0.777146,-0.788011,-0.798635, 
  18.     -0.809017,-0.819152,-0.829038,-0.838671,-0.848048,-0.857167,-0.866025,-0.874620,-0.882948, 
  19.     -0.891007,-0.898794,-0.906308,-0.913545,-0.920505,-0.927184,-0.933580,-0.939693,-0.945519, 
  20.     -0.951057,-0.956305,-0.961262,-0.965926,-0.970296,-0.974370,-0.978148,-0.981627,-0.984808, 
  21.     -0.987688,-0.990268,-0.992546,-0.994522,-0.996195,-0.997564,-0.998630,-0.999391,-0.999848, 
  22. }; 
  23.  
  24. unsigned short get_angle(sensor_data_struct data) 
  25.     float cosine; 
  26.     unsigned short i; 
  27.  
  28.     cosine=(data.x*ref.x+data.y*ref.y+data.z*ref.z)/ \ 
  29.             ((sqrt(data.x*data.x+data.y*data.y+data.z*data.z))*\ 
  30.              (sqrt(ref.x*ref.x+ref.y*ref.y+ref.z*ref.z))); 
  31.  
  32.     for(i=0;i<180;i++) 
  33.     { 
  34.         if(cos_table[i]<cosine)//查表 
  35.         { 
  36.             return i; 
  37.         } 
  38.     } 
  39.     return 180;//error 
  40.  
  41. int main(int argc, char *argv[]) 
  42.     unsigned short angle;//改成整形 
  43.     printf("reference vector (%d,%d,%d)\r\n",ref.x,ref.y,ref.z); 
  44.     printf("test vector (%d,%d,%d)\r\n",test.x,test.y,test.z); 
  45.  
  46.     angle=get_angle(test); 
  47.  
  48.     printf("angle = %d'\r\n",angle); 
  49.     return 0; 
  • reference vector (0,0,255)
  • test vector (0,180,180)
  • angle = 46'

查表得出46度,因为查表以及浮点的精度,所以角度误差+-1度,但这个不影响业务逻辑。

5、小节

1、空间向量夹角公式可在基于xyz三轴的传感器中应用。

2、针对范例中的应用,两个向量的参数必须是在静止情况下采样,根据向量模进行过滤,否则角度计算错误。

3、未考虑大于180度的翻转。

本文转载自微信公众号「嵌入式系统」,可以通过以下二维码关注。转载本文请联系嵌入式系统公众号。

 

责任编辑:武晓燕 来源: 嵌入式系统
相关推荐

2021-11-05 22:47:44

冒泡排序选择插入

2020-11-04 10:20:56

嵌入式算法CRC

2022-03-10 08:59:59

傅里叶变换算法系统

2023-03-26 12:41:46

2018-05-02 16:34:56

EAF嵌入式框架

2009-04-11 15:22:24

Linux 2.6内核应用

2009-12-17 18:38:56

Fedora 7嵌入式

2009-04-20 21:20:32

Linux文件系统存储机制

2021-11-29 07:43:08

大数据存储算法

2012-07-30 14:13:11

Linux 2.6内核嵌入式

2011-01-14 13:13:23

嵌入式Linux开发

2022-11-24 11:15:49

IoTLinux设备树机制

2022-03-25 20:00:40

人工智能机器人

2009-04-11 15:12:24

2017-10-09 10:40:43

AMD

2009-12-16 15:41:40

嵌入式Linux入门

2009-12-17 10:33:05

嵌入式Linux

2011-04-18 11:34:34

嵌入式软件测试

2009-12-09 10:12:28

嵌入式Linux

2009-07-17 16:06:59

ARM嵌入式开发
点赞
收藏

51CTO技术栈公众号