import sympy as sp
import numpy as np
# TODO: remove code duplication between openpilot.common.orientation
def quat2rot ( quats ) :
quats = np . array ( quats )
input_shape = quats . shape
quats = np . atleast_2d ( quats )
Rs = np . zeros ( ( quats . shape [ 0 ] , 3 , 3 ) )
q0 = quats [ : , 0 ]
q1 = quats [ : , 1 ]
q2 = quats [ : , 2 ]
q3 = quats [ : , 3 ]
Rs [ : , 0 , 0 ] = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3
Rs [ : , 0 , 1 ] = 2 * ( q1 * q2 - q0 * q3 )
Rs [ : , 0 , 2 ] = 2 * ( q0 * q2 + q1 * q3 )
Rs [ : , 1 , 0 ] = 2 * ( q1 * q2 + q0 * q3 )
Rs [ : , 1 , 1 ] = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3
Rs [ : , 1 , 2 ] = 2 * ( q2 * q3 - q0 * q1 )
Rs [ : , 2 , 0 ] = 2 * ( q1 * q3 - q0 * q2 )
Rs [ : , 2 , 1 ] = 2 * ( q0 * q1 + q2 * q3 )
Rs [ : , 2 , 2 ] = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3
if len ( input_shape ) < 2 :
return Rs [ 0 ]
else :
return Rs
def euler2quat ( eulers ) :
eulers = np . array ( eulers )
if len ( eulers . shape ) > 1 :
output_shape = ( - 1 , 4 )
else :
output_shape = ( 4 , )
eulers = np . atleast_2d ( eulers )
gamma , theta , psi = eulers [ : , 0 ] , eulers [ : , 1 ] , eulers [ : , 2 ]
q0 = np . cos ( gamma / 2 ) * np . cos ( theta / 2 ) * np . cos ( psi / 2 ) + \
np . sin ( gamma / 2 ) * np . sin ( theta / 2 ) * np . sin ( psi / 2 )
q1 = np . sin ( gamma / 2 ) * np . cos ( theta / 2 ) * np . cos ( psi / 2 ) - \
np . cos ( gamma / 2 ) * np . sin ( theta / 2 ) * np . sin ( psi / 2 )
q2 = np . cos ( gamma / 2 ) * np . sin ( theta / 2 ) * np . cos ( psi / 2 ) + \
np . sin ( gamma / 2 ) * np . cos ( theta / 2 ) * np . sin ( psi / 2 )
q3 = np . cos ( gamma / 2 ) * np . cos ( theta / 2 ) * np . sin ( psi / 2 ) - \
np . sin ( gamma / 2 ) * np . sin ( theta / 2 ) * np . cos ( psi / 2 )
quats = np . array ( [ q0 , q1 , q2 , q3 ] ) . T
for i in range ( len ( quats ) ) :
if quats [ i , 0 ] < 0 : # pylint: disable=unsubscriptable-object
quats [ i ] = - quats [ i ] # pylint: disable=unsupported-assignment-operation,unsubscriptable-object
return quats . reshape ( output_shape )
def euler2rot ( eulers ) :
return quat2rot ( euler2quat ( eulers ) )
rotations_from_quats = quat2rot
def cross ( x ) :
ret = sp . Matrix ( np . zeros ( ( 3 , 3 ) ) )
ret [ 0 , 1 ] , ret [ 0 , 2 ] = - x [ 2 ] , x [ 1 ]
ret [ 1 , 0 ] , ret [ 1 , 2 ] = x [ 2 ] , - x [ 0 ]
ret [ 2 , 0 ] , ret [ 2 , 1 ] = - x [ 1 ] , x [ 0 ]
return ret
def rot_to_euler ( R ) :
gamma = sp . atan2 ( R [ 2 , 1 ] , R [ 2 , 2 ] )
theta = sp . asin ( - R [ 2 , 0 ] )
psi = sp . atan2 ( R [ 1 , 0 ] , R [ 0 , 0 ] )
return sp . Matrix ( [ gamma , theta , psi ] )
def rot_matrix ( roll , pitch , yaw ) :
cr , sr = np . cos ( roll ) , np . sin ( roll )
cp , sp = np . cos ( pitch ) , np . sin ( pitch )
cy , sy = np . cos ( yaw ) , np . sin ( yaw )
rr = np . array ( [ [ 1 , 0 , 0 ] , [ 0 , cr , - sr ] , [ 0 , sr , cr ] ] )
rp = np . array ( [ [ cp , 0 , sp ] , [ 0 , 1 , 0 ] , [ - sp , 0 , cp ] ] )
ry = np . array ( [ [ cy , - sy , 0 ] , [ sy , cy , 0 ] , [ 0 , 0 , 1 ] ] )
return ry . dot ( rp . dot ( rr ) )
def euler_rotate ( roll , pitch , yaw ) :
# make symbolic rotation matrix from eulers
matrix_roll = sp . Matrix ( [ [ 1 , 0 , 0 ] ,
[ 0 , sp . cos ( roll ) , - sp . sin ( roll ) ] ,
[ 0 , sp . sin ( roll ) , sp . cos ( roll ) ] ] )
matrix_pitch = sp . Matrix ( [ [ sp . cos ( pitch ) , 0 , sp . sin ( pitch ) ] ,
[ 0 , 1 , 0 ] ,
[ - sp . sin ( pitch ) , 0 , sp . cos ( pitch ) ] ] )
matrix_yaw = sp . Matrix ( [ [ sp . cos ( yaw ) , - sp . sin ( yaw ) , 0 ] ,
[ sp . sin ( yaw ) , sp . cos ( yaw ) , 0 ] ,
[ 0 , 0 , 1 ] ] )
return matrix_yaw * matrix_pitch * matrix_roll
def quat_rotate ( q0 , q1 , q2 , q3 ) :
# make symbolic rotation matrix from quat
return sp . Matrix ( [ [ q0 * * 2 + q1 * * 2 - q2 * * 2 - q3 * * 2 , 2 * ( q1 * q2 + q0 * q3 ) , 2 * ( q1 * q3 - q0 * q2 ) ] ,
[ 2 * ( q1 * q2 - q0 * q3 ) , q0 * * 2 - q1 * * 2 + q2 * * 2 - q3 * * 2 , 2 * ( q2 * q3 + q0 * q1 ) ] ,
[ 2 * ( q1 * q3 + q0 * q2 ) , 2 * ( q2 * q3 - q0 * q1 ) , q0 * * 2 - q1 * * 2 - q2 * * 2 + q3 * * 2 ] ] ) . T
def quat_matrix_l ( p ) :
return sp . Matrix ( [ [ p [ 0 ] , - p [ 1 ] , - p [ 2 ] , - p [ 3 ] ] ,
[ p [ 1 ] , p [ 0 ] , - p [ 3 ] , p [ 2 ] ] ,
[ p [ 2 ] , p [ 3 ] , p [ 0 ] , - p [ 1 ] ] ,
[ p [ 3 ] , - p [ 2 ] , p [ 1 ] , p [ 0 ] ] ] )
def quat_matrix_r ( p ) :
return sp . Matrix ( [ [ p [ 0 ] , - p [ 1 ] , - p [ 2 ] , - p [ 3 ] ] ,
[ p [ 1 ] , p [ 0 ] , p [ 3 ] , - p [ 2 ] ] ,
[ p [ 2 ] , - p [ 3 ] , p [ 0 ] , p [ 1 ] ] ,
[ p [ 3 ] , p [ 2 ] , - p [ 1 ] , p [ 0 ] ] ] )
def sympy_into_c ( sympy_functions , global_vars = None ) :
from sympy . utilities import codegen
routines = [ ]
for name , expr , args in sympy_functions :
r = codegen . make_routine ( name , expr , language = " C99 " , global_vars = global_vars )
# argument ordering input to sympy is broken with function with output arguments
nargs = [ ]
# reorder the input arguments
for aa in args :
if aa is None :
nargs . append ( codegen . InputArgument ( sp . Symbol ( ' unused ' ) , dimensions = [ 1 , 1 ] ) )
continue
found = False
for a in r . arguments :
if str ( aa . name ) == str ( a . name ) :
nargs . append ( a )
found = True
break
if not found :
# [1,1] is a hack for Matrices
nargs . append ( codegen . InputArgument ( aa , dimensions = [ 1 , 1 ] ) )
# add the output arguments
for a in r . arguments :
if type ( a ) == codegen . OutputArgument :
nargs . append ( a )
# assert len(r.arguments) == len(args)+1
r . arguments = nargs
# add routine to list
routines . append ( r )
[ ( _ , c_code ) , ( _ , c_header ) ] = codegen . get_code_generator ( ' C ' , ' ekf ' , ' C99 ' ) . write ( routines , " ekf " )
c_header = ' \n ' . join ( x for x in c_header . split ( " \n " ) if len ( x ) > 0 and x [ 0 ] != ' # ' )
c_code = ' \n ' . join ( x for x in c_code . split ( " \n " ) if len ( x ) > 0 and x [ 0 ] != ' # ' )
return c_header , c_code