1 /*
2  * Copyright (c) 2021 Kevin Townsend
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <math.h>
8 #include <errno.h>
9 #include <zsl/zsl.h>
10 #include <zsl/orientation/orientation.h>
11 
zsl_att_to_vec(struct zsl_attitude * a,struct zsl_vec * v)12 int zsl_att_to_vec(struct zsl_attitude *a, struct zsl_vec *v)
13 {
14 	int rc = 0;
15 
16 	v->sz = 3;
17 	v->data = a->idx;
18 
19 	return rc;
20 }
21 
zsl_att_to_euler(struct zsl_attitude * a,struct zsl_euler * e)22 int zsl_att_to_euler(struct zsl_attitude *a, struct zsl_euler *e)
23 {
24 	int rc = 0;
25 
26 	e->x = a->roll * ZSL_DEG_TO_RAD;
27 	e->y = a->pitch * ZSL_DEG_TO_RAD;
28 	e->z = a->yaw * ZSL_DEG_TO_RAD;
29 
30 	return rc;
31 }
32 
zsl_att_from_euler(struct zsl_euler * e,struct zsl_attitude * a)33 int zsl_att_from_euler(struct zsl_euler *e, struct zsl_attitude *a)
34 {
35 	int rc = 0;
36 
37 	a->roll = e->x * ZSL_RAD_TO_DEG;
38 	a->pitch = e->y * ZSL_RAD_TO_DEG;
39 	a->yaw = e->z * ZSL_RAD_TO_DEG;
40 	a->status_bits =  0;
41 
42 	return rc;
43 }
44 
zsl_att_from_accelmag(struct zsl_vec * accel,struct zsl_vec * mag,struct zsl_attitude * a)45 int zsl_att_from_accelmag(struct zsl_vec *accel, struct zsl_vec *mag,
46 			  struct zsl_attitude *a)
47 {
48 	int rc = 0;
49 
50 #if CONFIG_ZSL_BOUNDS_CHECKS
51 	/* Make sure that the accelerometer and magnetometer vectors are size 3. */
52 	if (accel->sz != 3 || mag->sz != 3) {
53 		rc = -EINVAL;
54 		goto err;
55 	}
56 #endif
57 
58 	ZSL_VECTOR_DEF(mag_unit, 3);
59 	zsl_vec_copy(&mag_unit, mag);
60 	zsl_vec_to_unit(&mag_unit);
61 
62 	struct zsl_attitude att;
63 
64 	zsl_att_from_accel(accel, &att);
65 
66 	zsl_real_t nom = mag_unit.data[2] * ZSL_SIN(att.pitch * ZSL_DEG_TO_RAD) -
67 			 mag_unit.data[1] * ZSL_COS(att.pitch * ZSL_DEG_TO_RAD);
68 	zsl_real_t den = mag_unit.data[0] * ZSL_COS(att.roll * ZSL_DEG_TO_RAD) +
69 			 ZSL_SIN(att.roll * ZSL_DEG_TO_RAD) *
70 			 (mag_unit.data[1] * ZSL_SIN(att.pitch * ZSL_DEG_TO_RAD) +
71 			  mag_unit.data[2] * ZSL_COS(att.pitch * ZSL_DEG_TO_RAD));
72 
73 	a->roll = att.roll;
74 	a->pitch = att.pitch;
75 	a->yaw = ZSL_ATAN2(nom, den) * ZSL_RAD_TO_DEG;
76 
77 #if CONFIG_ZSL_BOUNDS_CHECKS
78 err:
79 #endif
80 	return rc;
81 }
82 
zsl_att_from_accel(struct zsl_vec * accel,struct zsl_attitude * a)83 int zsl_att_from_accel(struct zsl_vec *accel, struct zsl_attitude *a)
84 {
85 	int rc = 0;
86 
87 #if CONFIG_ZSL_BOUNDS_CHECKS
88 	/* Make sure that the accelerometer vector is size 3. */
89 	if (accel->sz != 3) {
90 		rc = -EINVAL;
91 		goto err;
92 	}
93 #endif
94 
95 	ZSL_VECTOR_DEF(accel_unit, 3);
96 	zsl_vec_copy(&accel_unit, accel);
97 	zsl_vec_to_unit(&accel_unit);
98 
99 	zsl_real_t ss = accel_unit.data[1] * accel_unit.data[1] +
100 			accel_unit.data[2] * accel_unit.data[2];
101 
102 	a->roll = ZSL_ATAN2(accel_unit.data[1], accel_unit.data[2])
103 		  * ZSL_RAD_TO_DEG;
104 	a->pitch = ZSL_ATAN2(-accel_unit.data[0], ZSL_SQRT(ss))
105 		   * ZSL_RAD_TO_DEG;
106 	a->yaw = 0.0;
107 
108 #if CONFIG_ZSL_BOUNDS_CHECKS
109 err:
110 #endif
111 	return rc;
112 }
113 
zsl_att_accel_angle(struct zsl_vec * a1,struct zsl_vec * a2,zsl_real_t * b)114 int zsl_att_accel_angle(struct zsl_vec *a1, struct zsl_vec *a2, zsl_real_t *b)
115 {
116 	int rc = 0;
117 
118 #if CONFIG_ZSL_BOUNDS_CHECKS
119 	/* Make sure that the accelerometer vectors are size 3. */
120 	if (a1->sz != 3 || a2->sz != 3) {
121 		rc = -EINVAL;
122 		goto err;
123 	}
124 #endif
125 
126 	zsl_real_t a1_norm, a2_norm, dot;
127 
128 	a1_norm = zsl_vec_norm(a1);
129 	a2_norm = zsl_vec_norm(a2);
130 	zsl_vec_dot(a1, a2, &dot);
131 
132 	*b = ZSL_ACOS(dot / (a1_norm * a2_norm));
133 
134 #if CONFIG_ZSL_BOUNDS_CHECKS
135 err:
136 #endif
137 	return rc;
138 }
139