├── firmware ├── hex │ └── .gitkeep ├── hedrot-firmware │ ├── I2Ccom.h │ ├── hedrot_comm_protocol.h │ ├── I2Ccom.cpp │ ├── Mag5883.h │ ├── ITG3200.h │ ├── Mag5883.cpp │ └── ADXL345.h ├── CHANGELOG.txt └── README.txt ├── enclosure └── Enclosure.skp ├── scripts ├── logo │ ├── hedrot.ico │ ├── hedrot.png │ ├── hedrot.icns │ └── hedrot.rsrc ├── README-DISTRIBUTION.txt ├── Mac │ ├── build.sh │ └── makeDistribution.sh ├── Win │ ├── build.bat │ └── makeDistribution.bat └── README-BUILD.txt ├── doc └── hedrot user manual.docx ├── command-line-demo ├── visual studio │ ├── hedrotReceiverDemo.vcxproj.user │ ├── hedrotReceiverDemo.sln │ ├── hedrotReceiverDemo.vcxproj.filters │ └── hedrotReceiverDemo.vcxproj ├── xcode │ └── hedrotReceiverDemo.xcodeproj │ │ ├── xcuserdata │ │ └── baskind.xcuserdatad │ │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── headtracker_rcv_cmd.xcscheme │ │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── baskind.xcuserdatad │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── WorkspaceSettings.xcsettings │ │ └── project.pbxproj └── source │ └── hedrotReceiverDemo.c ├── hedrotReceiver ├── xcode │ ├── hedrot_receiver.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcuserdata │ │ │ │ └── baskind.xcuserdatad │ │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ │ └── WorkspaceSettings.xcsettings │ │ ├── xcuserdata │ │ │ └── baskind.xcuserdatad │ │ │ │ └── xcschemes │ │ │ │ ├── xcschememanagement.plist │ │ │ │ └── max-external.xcscheme │ │ └── project.pbxproj │ ├── Info.plist │ └── hedrot_receiver.xcconfig ├── visual studio │ ├── hedrot_receiver.props │ ├── max_extern_common.props │ └── hedrot_receiver.sln ├── hedrotReceiver.maxproj ├── hedrotReceiver.json ├── patches │ └── rs_set.maxpat └── source │ └── hedrot_receiver.h ├── matlab ├── quaternion_library │ ├── quaternConj.m │ ├── rotMat2euler.m │ ├── quaternProd.m │ ├── axisAngle2quatern.m │ ├── quatern2rotMat.m │ ├── quatern2euler.m │ ├── euler2rotMat.m │ ├── axisAngle2rotMat.m │ ├── rotMat2quatern.m │ └── TestScript.m ├── calibration │ ├── readTextOfflineCalrawData.m │ ├── test_script.m │ └── ellipsoid_fit.m ├── showCookedData.m ├── showHeadtrackerDataSpectrum.m ├── readTextDataFromHeadtracker.m └── computeAnglesMadgwick.m ├── libhedrot ├── libhedrot_utils.h ├── libhedrot_calibration.h ├── libhedrot_serialcomm.h ├── libhedrot_RTmagCalibration.h └── libhedrot_utils.c ├── CHANGELOG.txt └── README.md /firmware/hex/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /enclosure/Enclosure.skp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaskind/hedrot/HEAD/enclosure/Enclosure.skp -------------------------------------------------------------------------------- /scripts/logo/hedrot.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaskind/hedrot/HEAD/scripts/logo/hedrot.ico -------------------------------------------------------------------------------- /scripts/logo/hedrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaskind/hedrot/HEAD/scripts/logo/hedrot.png -------------------------------------------------------------------------------- /scripts/logo/hedrot.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaskind/hedrot/HEAD/scripts/logo/hedrot.icns -------------------------------------------------------------------------------- /scripts/logo/hedrot.rsrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaskind/hedrot/HEAD/scripts/logo/hedrot.rsrc -------------------------------------------------------------------------------- /doc/hedrot user manual.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaskind/hedrot/HEAD/doc/hedrot user manual.docx -------------------------------------------------------------------------------- /scripts/README-DISTRIBUTION.txt: -------------------------------------------------------------------------------- 1 | hedrot - open-source head-tracker 2 | 3 | 4 | Hedrot Version: XXXX 5 | Firmware Version: YYYY 6 | 7 | 8 | Please read « hedrot user manual.pdf » for more information -------------------------------------------------------------------------------- /command-line-demo/visual studio/hedrotReceiverDemo.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /command-line-demo/xcode/hedrotReceiverDemo.xcodeproj/xcuserdata/baskind.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /hedrotReceiver/xcode/hedrot_receiver.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /command-line-demo/xcode/hedrotReceiverDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /hedrotReceiver/xcode/hedrot_receiver.xcodeproj/project.xcworkspace/xcuserdata/baskind.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaskind/hedrot/HEAD/hedrotReceiver/xcode/hedrot_receiver.xcodeproj/project.xcworkspace/xcuserdata/baskind.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /command-line-demo/xcode/hedrotReceiverDemo.xcodeproj/project.xcworkspace/xcuserdata/baskind.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abaskind/hedrot/HEAD/command-line-demo/xcode/hedrotReceiverDemo.xcodeproj/project.xcworkspace/xcuserdata/baskind.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /matlab/quaternion_library/quaternConj.m: -------------------------------------------------------------------------------- 1 | function qConj = quaternConj(q) 2 | %QUATERN2ROTMAT Converts a quaternion to its conjugate 3 | % 4 | % qConj = quaternConj(q) 5 | % 6 | % Converts a quaternion to its conjugate. 7 | % 8 | % For more information see: 9 | % http://www.x-io.co.uk/node/8#quaternions 10 | % 11 | % Date Author Notes 12 | % 27/09/2011 SOH Madgwick Initial release 13 | 14 | qConj = [q(:,1) -q(:,2) -q(:,3) -q(:,4)]; 15 | end 16 | -------------------------------------------------------------------------------- /hedrotReceiver/xcode/hedrot_receiver.xcodeproj/project.xcworkspace/xcuserdata/baskind.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /command-line-demo/xcode/hedrotReceiverDemo.xcodeproj/project.xcworkspace/xcuserdata/baskind.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /matlab/calibration/readTextOfflineCalrawData.m: -------------------------------------------------------------------------------- 1 | % readTextMagCalData.m 2 | % 3 | % read raw magnetometer calibration data recorded in a text file by hedrot 4 | % 5 | % Copyright 2017 Alexis Baskind 6 | 7 | function offlineCalrawData = readTextOfflineCalrawData(filename) 8 | 9 | fileID = fopen(filename,'r'); 10 | 11 | [VAL, COUNT, ERRMSG] = fscanf (fileID, "%i, %i %i %i;\n"); 12 | 13 | M=reshape(VAL,4,COUNT/4)'; 14 | 15 | offlineCalrawData = M(:,2:4); 16 | 17 | fclose(fileID); 18 | 19 | endfunction -------------------------------------------------------------------------------- /hedrotReceiver/visual studio/hedrot_receiver.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | C:\Users\Baskind\Desktop\Developpement\MaxSDK-6.1.4\c74support 6 | 7 | 8 | 9 | 10 | 11 | $(C74SUPPORT) 12 | true 13 | 14 | 15 | -------------------------------------------------------------------------------- /matlab/showCookedData.m: -------------------------------------------------------------------------------- 1 | % showCookedData.m 2 | % 3 | % Copyright 2016 Alexis Baskind 4 | 5 | function showCookedData(headtrackerData) 6 | figure; 7 | 8 | subplot(4,1,1); 9 | plot(headtrackerData.data.gyroCalData); 10 | title("Gyroscope calibrated data"); 11 | 12 | subplot(4,1,2); 13 | plot(headtrackerData.data.magCalData); 14 | title("Magnetometer calibrated data"); 15 | 16 | subplot(4,1,3); 17 | plot(headtrackerData.data.accCalData); 18 | title("Accelerometer calibrated data"); 19 | 20 | subplot(4,1,4); 21 | plot(headtrackerData.data.yawPitchRoll); 22 | title("Estimated Angles");legend("yaw","pitch","roll"); 23 | 24 | endfunction 25 | -------------------------------------------------------------------------------- /hedrotReceiver/hedrotReceiver.maxproj: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "hedrotReceiver", 3 | "version" : 1, 4 | "creationdate" : -734034129, 5 | "modificationdate" : -710628712, 6 | "viewrect" : [ 2.0, 54.0, 300.0, 500.0 ], 7 | "autoorganize" : 0, 8 | "hideprojectwindow" : 0, 9 | "showdependencies" : 1, 10 | "autolocalize" : 0, 11 | "contents" : { 12 | "patchers" : { 13 | "hedrotReceiver.maxpat" : { 14 | "kind" : "patcher", 15 | "local" : 1, 16 | "toplevel" : 1 17 | } 18 | 19 | } 20 | , 21 | "externals" : { 22 | 23 | } 24 | 25 | } 26 | , 27 | "layout" : { 28 | 29 | } 30 | , 31 | "searchpath" : { 32 | 33 | } 34 | , 35 | "detailsvisible" : 0 36 | } 37 | -------------------------------------------------------------------------------- /hedrotReceiver/xcode/hedrot_receiver.xcodeproj/xcuserdata/baskind.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | max-external.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 2FBBEAD608F335360078DB84 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /command-line-demo/xcode/hedrotReceiverDemo.xcodeproj/xcuserdata/baskind.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | headtracker_rcv_cmd.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 166D0E471DB3E54D007B85B9 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /matlab/quaternion_library/rotMat2euler.m: -------------------------------------------------------------------------------- 1 | function euler = rotMat2euler(R) 2 | %ROTMAT2EULER Converts a rotation matrix orientation to ZYX Euler angles 3 | % 4 | % euler = rotMat2euler(R) 5 | % 6 | % Converts a rotation matrix orientation to ZYX Euler angles where phi is 7 | % a rotation around X, theta around Y and psi around Z. 8 | % 9 | % For more information see: 10 | % http://www.x-io.co.uk/node/8#quaternions 11 | % 12 | % Date Author Notes 13 | % 27/09/2011 SOH Madgwick Initial release 14 | 15 | phi = atan2(R(3,2,:), R(3,3,:) ); 16 | theta = -atan(R(3,1,:) ./ sqrt(1-R(3,1,:).^2) ); 17 | psi = atan2(R(2,1,:), R(1,1,:) ); 18 | 19 | euler = [phi(1,:)' theta(1,:)' psi(1,:)']; 20 | end 21 | 22 | -------------------------------------------------------------------------------- /matlab/quaternion_library/quaternProd.m: -------------------------------------------------------------------------------- 1 | function ab = quaternProd(a, b) 2 | %QUATERNPROD Calculates the quaternion product 3 | % 4 | % ab = quaternProd(a, b) 5 | % 6 | % Calculates the quaternion product of quaternion a and b. 7 | % 8 | % For more information see: 9 | % http://www.x-io.co.uk/node/8#quaternions 10 | % 11 | % Date Author Notes 12 | % 27/09/2011 SOH Madgwick Initial release 13 | 14 | ab(:,1) = a(:,1).*b(:,1)-a(:,2).*b(:,2)-a(:,3).*b(:,3)-a(:,4).*b(:,4); 15 | ab(:,2) = a(:,1).*b(:,2)+a(:,2).*b(:,1)+a(:,3).*b(:,4)-a(:,4).*b(:,3); 16 | ab(:,3) = a(:,1).*b(:,3)-a(:,2).*b(:,4)+a(:,3).*b(:,1)+a(:,4).*b(:,2); 17 | ab(:,4) = a(:,1).*b(:,4)+a(:,2).*b(:,3)-a(:,3).*b(:,2)+a(:,4).*b(:,1); 18 | end 19 | 20 | -------------------------------------------------------------------------------- /matlab/quaternion_library/axisAngle2quatern.m: -------------------------------------------------------------------------------- 1 | function q = axisAngle2quatern(axis, angle) 2 | %AXISANGLE2QUATERN Converts an axis-angle orientation to a quaternion 3 | % 4 | % q = axisAngle2quatern(axis, angle) 5 | % 6 | % Converts and axis-angle orientation to a quaternion where a 3D rotation 7 | % is described by an angular rotation around axis defined by a vector. 8 | % 9 | % For more information see: 10 | % http://www.x-io.co.uk/node/8#quaternions 11 | % 12 | % Date Author Notes 13 | % 27/09/2011 SOH Madgwick Initial release 14 | 15 | q0 = cos(angle./2); 16 | q1 = -axis(:,1)*sin(angle./2); 17 | q2 = -axis(:,2)*sin(angle./2); 18 | q3 = -axis(:,3)*sin(angle./2); 19 | q = [q0 q1 q2 q3]; 20 | end 21 | 22 | -------------------------------------------------------------------------------- /firmware/hedrot-firmware/I2Ccom.h: -------------------------------------------------------------------------------- 1 | // I2Ccom: I2C communication with the I2c_t3 library 2 | 3 | 4 | #ifndef _I2CCOM_H_ 5 | #define _I2CCOM_H_ 6 | 7 | #include "i2c_t3.h" 8 | 9 | void writeBit(uint8_t address, uint8_t subAddress, uint8_t bitnumber, uint8_t data); 10 | void writeBits(uint8_t address, uint8_t subAddress, uint8_t bitStart, uint8_t length, uint8_t data); 11 | void writeByte(uint8_t address, uint8_t subAddress, uint8_t data); 12 | bool readBit(uint8_t address, uint8_t subAddress, uint8_t bitnumber); 13 | uint8_t readBits(uint8_t address, uint8_t subAddress, uint8_t bitStart, uint8_t length); 14 | uint8_t readByte(uint8_t address, uint8_t subAddress); 15 | int8_t readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest); 16 | 17 | 18 | #endif /* _I2CCOM_H_ */ 19 | -------------------------------------------------------------------------------- /hedrotReceiver/visual studio/max_extern_common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <_ProjectFileVersion>11.0.60610.1 7 | ..\ 8 | build\$(Configuration)_$(PlatformName)\ 9 | 10 | 11 | 12 | MaxAPI.lib;MaxAudio.lib;jitlib.lib;%(AdditionalDependencies) 13 | 14 | 15 | VER_TARGETNAME="$(TargetName)";%(PreprocessorDefinitions) 16 | 17 | 18 | -------------------------------------------------------------------------------- /matlab/quaternion_library/quatern2rotMat.m: -------------------------------------------------------------------------------- 1 | function R = quatern2rotMat(q) 2 | %QUATERN2ROTMAT Converts a quaternion orientation to a rotation matrix 3 | % 4 | % R = quatern2rotMat(q) 5 | % 6 | % Converts a quaternion orientation to a rotation matrix. 7 | % 8 | % For more information see: 9 | % http://www.x-io.co.uk/node/8#quaternions 10 | % 11 | % Date Author Notes 12 | % 27/09/2011 SOH Madgwick Initial release 13 | 14 | R(1,1,:) = 2.*q(:,1).^2-1+2.*q(:,2).^2; 15 | R(1,2,:) = 2.*(q(:,2).*q(:,3)+q(:,1).*q(:,4)); 16 | R(1,3,:) = 2.*(q(:,2).*q(:,4)-q(:,1).*q(:,3)); 17 | R(2,1,:) = 2.*(q(:,2).*q(:,3)-q(:,1).*q(:,4)); 18 | R(2,2,:) = 2.*q(:,1).^2-1+2.*q(:,3).^2; 19 | R(2,3,:) = 2.*(q(:,3).*q(:,4)+q(:,1).*q(:,2)); 20 | R(3,1,:) = 2.*(q(:,2).*q(:,4)+q(:,1).*q(:,3)); 21 | R(3,2,:) = 2.*(q(:,3).*q(:,4)-q(:,1).*q(:,2)); 22 | R(3,3,:) = 2.*q(:,1).^2-1+2.*q(:,4).^2; 23 | end 24 | 25 | -------------------------------------------------------------------------------- /matlab/showHeadtrackerDataSpectrum.m: -------------------------------------------------------------------------------- 1 | % showHeadtrackerDataSpectrum.m 2 | % 3 | % Copyright 2016 Alexis Baskind 4 | 5 | function showHeadtrackerDataSpectrum (headtrackerData, stream, Nsamples, windowtype) 6 | if(nargin<3) 7 | Nsamples = headtrackerData.numberOfSamples; 8 | endif 9 | 10 | if(nargin<4) 11 | windowtype = "hanning"; 12 | endif 13 | 14 | if(strcmp(windowtype,"rect")) 15 | window = ones(Nsamples,3); 16 | else 17 | eval(strcat("window = ",windowtype,"(Nsamples)*ones(1,3);")); 18 | endif 19 | 20 | %Nfft=pow2(nextpow2(headtrackerData.numberOfSamples)); 21 | Nfft = 65536; 22 | %Nfft=headtrackerData.numberOfSamples; 23 | f=(0:Nfft-1)/Nfft*headtrackerData.header.samplerate; 24 | eval(strcat("X=fft(headtrackerData.data.",stream,"(1:Nsamples,:).*window,Nfft,1);")); 25 | 26 | figure;plot(f(1:Nfft/2+1),20*log10(abs(X(1:Nfft/2+1,:))));grid 27 | xlabel("frequency (Hz)");ylabel("amplitude (dB)"); 28 | endfunction 29 | -------------------------------------------------------------------------------- /matlab/quaternion_library/quatern2euler.m: -------------------------------------------------------------------------------- 1 | function euler = quatern2euler(q) 2 | %QUATERN2EULER Converts a quaternion orientation to ZYX Euler angles 3 | % 4 | % q = quatern2euler(q) 5 | % 6 | % Converts a quaternion orientation to ZYX Euler angles where phi is a 7 | % rotation around X, theta around Y and psi around Z. 8 | % 9 | % For more information see: 10 | % http://www.x-io.co.uk/node/8#quaternions 11 | % 12 | % Date Author Notes 13 | % 27/09/2011 SOH Madgwick Initial release 14 | 15 | R(1,1,:) = 2.*q(:,1).^2-1+2.*q(:,2).^2; 16 | R(2,1,:) = 2.*(q(:,2).*q(:,3)-q(:,1).*q(:,4)); 17 | R(3,1,:) = 2.*(q(:,2).*q(:,4)+q(:,1).*q(:,3)); 18 | R(3,2,:) = 2.*(q(:,3).*q(:,4)-q(:,1).*q(:,2)); 19 | R(3,3,:) = 2.*q(:,1).^2-1+2.*q(:,4).^2; 20 | 21 | phi = atan2(R(3,2,:), R(3,3,:) ); 22 | theta = -atan(R(3,1,:) ./ sqrt(1-R(3,1,:).^2) ); 23 | psi = atan2(R(2,1,:), R(1,1,:) ); 24 | 25 | euler = [phi(1,:)' theta(1,:)' psi(1,:)']; 26 | end 27 | 28 | -------------------------------------------------------------------------------- /hedrotReceiver/xcode/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${PRODUCT_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleLongVersionString 16 | ${PRODUCT_NAME} ${PRODUCT_VERSION} 17 | CFBundlePackageType 18 | iLaX 19 | CFBundleShortVersionString 20 | ${PRODUCT_VERSION} 21 | CFBundleSignature 22 | max2 23 | CFBundleVersion 24 | ${PRODUCT_VERSION} 25 | CSResourcesFileMapped 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /firmware/CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | hedrot firmware, changelog: 2 | 3 | Version 7 (24/10/16) 4 | . changed key strings from function TransmitInfo() according to the internal variable names (easier to handle on the receiver side) 5 | 6 | Version 8 (04/08/17) 7 | . self test when the board is connected or reset: 8 | - if everything goes well, the onboard led should blink twice slowly (then it’s ready for use) 9 | - if the teensy board can connect to the daughter sensor board but cannot read its data, the onboard led blinks fast endlessly 10 | - if the teensy board cannot connect to the daughter board, nothing happens 11 | => in both latter cases, there is probably a hardware problem: either the daugther board is damaged, or there is bad contact in the connections between both boards, or the main teensy board is damaged. 12 | 13 | Version 9 (21/01/18) 14 | . First hotfix version of the firmware that works with the QMC5883 Magnetometer 15 | 16 | Version 10 (29/01/18) 17 | . clean version of the firmware that works with the QMC5883 Magnetometer -------------------------------------------------------------------------------- /matlab/quaternion_library/euler2rotMat.m: -------------------------------------------------------------------------------- 1 | function R = euler2rotMat(phi, theta, psi) 2 | %EULER2ROTMAT Converts a ZYX Euler angle orientation to a rotation matrix 3 | % 4 | % q = euler2rotMat(axis, angle) 5 | % 6 | % Converts ZYX Euler angle orientation to a rotation matrix where phi is 7 | % a rotation around X, theta around Y and psi around Z. 8 | % 9 | % For more information see: 10 | % http://www.x-io.co.uk/node/8#quaternions 11 | % 12 | % Date Author Notes 13 | % 27/09/2011 SOH Madgwick Initial release 14 | 15 | R(1,1,:) = cos(psi).*cos(theta); 16 | R(1,2,:) = -sin(psi).*cos(phi) + cos(psi).*sin(theta).*sin(phi); 17 | R(1,3,:) = sin(psi).*sin(phi) + cos(psi).*sin(theta).*cos(phi); 18 | 19 | R(2,1,:) = sin(psi).*cos(theta); 20 | R(2,2,:) = cos(psi).*cos(phi) + sin(psi).*sin(theta).*sin(phi); 21 | R(2,3,:) = -cos(psi).*sin(phi) + sin(psi).*sin(theta).*cos(phi); 22 | 23 | R(3,1,:) = -sin(theta); 24 | R(3,2,:) = cos(theta).*sin(phi); 25 | R(3,3,:) = cos(theta).*cos(phi); 26 | end 27 | 28 | -------------------------------------------------------------------------------- /matlab/quaternion_library/axisAngle2rotMat.m: -------------------------------------------------------------------------------- 1 | function R = axisAngle2rotMat(axis, angle) 2 | %AXISANGLE2ROTMAT Converts an axis-angle orientation to a rotation matrix 3 | % 4 | % q = axisAngle2rotMat(axis, angle) 5 | % 6 | % Converts and axis-angle orientation to a rotation matrix where a 3D 7 | % rotation is described by an angular rotation around axis defined by a 8 | % vector. 9 | % 10 | % For more information see: 11 | % http://www.x-io.co.uk/node/8#quaternions 12 | % 13 | % Date Author Notes 14 | % 27/09/2011 SOH Madgwick Initial release 15 | 16 | kx = axis(:,1); 17 | ky = axis(:,2); 18 | kz = axis(:,3); 19 | cT = cos(angle); 20 | sT = sin(angle); 21 | vT = 1 - cos(angle); 22 | 23 | R(1,1,:) = kx.*kx.*vT + cT; 24 | R(1,2,:) = kx.*ky.*vT - kz.*sT; 25 | R(1,3,:) = kx.*kz.*vT + ky.*sT; 26 | 27 | R(2,1,:) = kx.*ky.*vT + kz.*sT; 28 | R(2,2,:) = ky.*ky.*vT + cT; 29 | R(2,3,:) = ky.*kz.*vT - kx.*sT; 30 | 31 | R(3,1,:) = kx.*kz.*vT - ky.*sT; 32 | R(3,2,:) = ky.*kz.*vT + kx.*sT; 33 | R(3,3,:) = kz.*kz.*vT + cT; 34 | end 35 | 36 | -------------------------------------------------------------------------------- /firmware/README.txt: -------------------------------------------------------------------------------- 1 | hedrot-firmware 2 | 3 | teensy firmware for the hedrot head tracker. 4 | 5 | software requirements: 6 | . Arduino IDE 1.6.11 7 | . Teensyduino 1.30 (teensy support for the Arduino IDE). During the installation of teensyduino, at least the library i2c_t3 (i2c communication library optimized for teensy, standard with Teensyduino) has to be installed 8 | 9 | hedrot-firmware can be compiled with the Arduino compiler: 10 | => open the file hedrot-firmware.ino 11 | => in the Tools Menu, select as « Board » « Teensy 3.2/3.1 » 12 | => compile 13 | the hex file of the firmware binary has then to be found manually (look at the Arduino console) 14 | 15 | alternatively, the firmware can be compiled from the command line: 16 | 17 | /Applications/Arduino.app/Contents/MacOS/Arduino -v --board teensy:avr:teensy31:usb=serial --pref build.path=$FIRMWARE_FOLDER/build --verify $FIRMWARE_FOLDER/hedrot-firmware/hedrot-firmware.ino 18 | 19 | ... where $FIRMWARE_FOLDER is an environment variable corresponding to the current folder. The main advantage of the command line method is that the hex file hedrot-firmware.ino.hex can be now easily accessed from the "build" subfolder -------------------------------------------------------------------------------- /hedrotReceiver/visual studio/hedrot_receiver.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hedrot_receiver", "hedrot_receiver.vcxproj", "{D7D2B050-0FAC-4326-89AD-C82254541416}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {D7D2B050-0FAC-4326-89AD-C82254541416}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {D7D2B050-0FAC-4326-89AD-C82254541416}.Debug|Win32.Build.0 = Debug|Win32 16 | {D7D2B050-0FAC-4326-89AD-C82254541416}.Debug|x64.ActiveCfg = Debug|x64 17 | {D7D2B050-0FAC-4326-89AD-C82254541416}.Debug|x64.Build.0 = Debug|x64 18 | {D7D2B050-0FAC-4326-89AD-C82254541416}.Release|Win32.ActiveCfg = Release|Win32 19 | {D7D2B050-0FAC-4326-89AD-C82254541416}.Release|Win32.Build.0 = Release|Win32 20 | {D7D2B050-0FAC-4326-89AD-C82254541416}.Release|x64.ActiveCfg = Release|x64 21 | {D7D2B050-0FAC-4326-89AD-C82254541416}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /command-line-demo/visual studio/hedrotReceiverDemo.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hedrotReceiverDemo", "hedrotReceiverDemo.vcxproj", "{F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}.Debug|Win32.Build.0 = Debug|Win32 16 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}.Debug|x64.ActiveCfg = Debug|x64 17 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}.Debug|x64.Build.0 = Debug|x64 18 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}.Release|Win32.ActiveCfg = Release|Win32 19 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}.Release|Win32.Build.0 = Release|Win32 20 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}.Release|x64.ActiveCfg = Release|x64 21 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /matlab/quaternion_library/rotMat2quatern.m: -------------------------------------------------------------------------------- 1 | function q = rotMat2quatern(R) 2 | %ROTMAT2QUATERN Converts a rotation matrix orientation to a quaternion 3 | % 4 | % q = axisAngle2quatern(axis, angle) 5 | % 6 | % Converts a rotation matrix orientation to a quaternion. 7 | % 8 | % For more information see: 9 | % http://www.x-io.co.uk/node/8#quaternions 10 | % 11 | % Date Author Notes 12 | % 27/09/2011 SOH Madgwick Initial release 13 | 14 | [row col numR] = size(R); 15 | q = zeros(numR, 4); 16 | K = zeros(4,4); 17 | for i = 1:numR 18 | K(1,1) = (1/3) * (R(1,1,i) - R(2,2,i) - R(3,3,i)); 19 | K(1,2) = (1/3) * (R(2,1,i) + R(1,2,i)); 20 | K(1,3) = (1/3) * (R(3,1,i) + R(1,3,i)); 21 | K(1,4) = (1/3) * (R(2,3,i) - R(3,2,i)); 22 | K(2,1) = (1/3) * (R(2,1,i) + R(1,2,i)); 23 | K(2,2) = (1/3) * (R(2,2,i) - R(1,1,i) - R(3,3,i)); 24 | K(2,3) = (1/3) * (R(3,2,i) + R(2,3,i)); 25 | K(2,4) = (1/3) * (R(3,1,i) - R(1,3,i)); 26 | K(3,1) = (1/3) * (R(3,1,i) + R(1,3,i)); 27 | K(3,2) = (1/3) * (R(3,2,i) + R(2,3,i)); 28 | K(3,3) = (1/3) * (R(3,3,i) - R(1,1,i) - R(2,2,i)); 29 | K(3,4) = (1/3) * (R(1,2,i) - R(2,1,i)); 30 | K(4,1) = (1/3) * (R(2,3,i) - R(3,2,i)); 31 | K(4,2) = (1/3) * (R(3,1,i) - R(1,3,i)); 32 | K(4,3) = (1/3) * (R(1,2,i) - R(2,1,i)); 33 | K(4,4) = (1/3) * (R(1,1,i) + R(2,2,i) + R(3,3,i)); 34 | [V,D] = eig(K); 35 | %p = find(max(D)); 36 | %q = V(:,p)'; 37 | q(i,:) = V(:,4)'; 38 | q(i,:) = [q(i,4) q(i,1) q(i,2) q(i,3)]; 39 | end 40 | end -------------------------------------------------------------------------------- /scripts/Mac/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "this builds the following binaries:" 3 | echo " . the firmware (in firmware/build/hedrot-firmware.ino.hex" 4 | echo " . the command-line demo (in command-line-demo/xcode/hedrotReceiverDemo)" 5 | echo " . the max external hedrotReceiver.mxo" 6 | echo 7 | echo "The Standlone hedrotReceiver has to be rebuilt afterwards in Max!!!!" 8 | 9 | thisDirectory=`pwd` 10 | rootDirectory=$thisDirectory/../.. 11 | 12 | ArduinoAppPath=/Applications/Arduino.app/Contents/MacOS/Arduino 13 | 14 | ######### build firmware (both versions) ############################# 15 | rm -rf $rootDirectory/firmware/build/* 16 | 17 | $ArduinoAppPath --verify --board teensy:avr:teensy31:usb=serial,speed=96,opt=o1std,keys=en-us --pref build.path=$rootDirectory/firmware/build $rootDirectory/firmware/hedrot-firmware/hedrot-firmware.ino 18 | cp $rootDirectory/firmware/build/hedrot-firmware.ino.hex $rootDirectory/firmware/hex/hedrot-firmware-teensy31-32.ino.hex 19 | 20 | $ArduinoAppPath --verify --board teensy:avr:teensyLC:usb=serial,speed=48,opt=osstd,keys=en-us --pref build.path=$rootDirectory/firmware/build $rootDirectory/firmware/hedrot-firmware/hedrot-firmware.ino 21 | cp $rootDirectory/firmware/build/hedrot-firmware.ino.hex $rootDirectory/firmware/hex/hedrot-firmware-teensyLC.ino.hex 22 | 23 | ######### build the command-line demo ############################# 24 | xcodebuild -configuration Release -project $rootDirectory/command-line-demo/xcode/hedrotReceiverDemo.xcodeproj 25 | 26 | ######### build the Max external ############################# 27 | xcodebuild -configuration Deployment -project $rootDirectory/hedrotReceiver/xcode/hedrot_receiver.xcodeproj 28 | -------------------------------------------------------------------------------- /matlab/readTextDataFromHeadtracker.m: -------------------------------------------------------------------------------- 1 | % readTextDataFromHeadtracker.m 2 | % 3 | % read raw and cooked data recorded in a text file by hedrot 4 | % 5 | % Copyright 2016 Alexis Baskind 6 | 7 | function headtrackerData = readTextDataFromHeadtracker(filename) 8 | 9 | fileID = fopen(filename,'r'); 10 | 11 | % 1° read the header 12 | readHeaderFlag = 1; 13 | while(readHeaderFlag && ((txt = fgetl (fileID)) != -1)) 14 | if(strcmp(txt,"")) 15 | % did we reach the end of the header? 16 | readHeaderFlag = 0; 17 | elseif(strcmp(txt,"
")) 18 | % is it the beginning of the header? If yes, just ignore the line 19 | else 20 | a = strsplit (txt, {', ', ';'}); 21 | key = a{1}; 22 | value = a{2}; 23 | %split the key between spaces 24 | numberOfItems = length(strsplit(value)); 25 | 26 | %case 1: single value 27 | if(numberOfItems == 1) 28 | eval(sprintf("headtrackerData.header.%s = %s;",key,value)); 29 | else 30 | %case 2: several values: save as array 31 | eval(sprintf("headtrackerData.header.%s = [%s];",key,value)); 32 | endif 33 | endif 34 | endwhile 35 | 36 | 37 | %2° read the data 38 | [VAL, COUNT, ERRMSG] = fscanf (fileID, "%i, %i %i %i %i %i %i %i %i %i %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f;\n"); 39 | M=reshape(VAL,29,COUNT/29)'; 40 | 41 | headtrackerData.data.magRawData = M(:,2:4); 42 | headtrackerData.data.accRawData = M(:,5:7); 43 | headtrackerData.data.gyroRawData = M(:,8:10); 44 | headtrackerData.data.magCalData = M(:,11:13); 45 | headtrackerData.data.accCalData = M(:,14:16); 46 | headtrackerData.data.accCalDataLP = M(:,17:19); 47 | headtrackerData.data.gyroCalData = M(:,20:22); 48 | headtrackerData.data.quaternion = M(:,23:26); 49 | headtrackerData.data.yawPitchRoll = M(:,27:29); 50 | 51 | 52 | headtrackerData.numberOfSamples = size(M,1); 53 | 54 | fclose(fileID); 55 | 56 | endfunction -------------------------------------------------------------------------------- /libhedrot/libhedrot_utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // libhedrot_utils.h 3 | // hedrot_receiver 4 | // 5 | // Created by Alexis Baskind on 17/04/17. 6 | // 7 | // 8 | 9 | #ifndef __hedrot_receiver__libhedrot_utils__ 10 | #define __hedrot_receiver__libhedrot_utils__ 11 | 12 | #include 13 | #include 14 | 15 | // double floating point modulo 16 | double mod(double a, double N); 17 | 18 | // round (not defined in VS2012) 19 | #if defined(_WIN32) || defined(_WIN64) 20 | double round(double value); 21 | #endif /* #if defined(_WIN32) || defined(_WIN64) */ 22 | 23 | // math utils 24 | 25 | // min and max not standard in Mac 26 | #ifndef min 27 | #define min(a,b) (((a)<(b))?(a):(b)) 28 | #endif 29 | 30 | #ifndef max 31 | #define max(a,b) (((a)>(b))?(a):(b)) 32 | #endif 33 | 34 | #define M_PI_float (float) 3.14159265358979323846264338327950288 35 | #define DEGREE_TO_RAD M_PI_float / 180.0f 36 | #define RAD_TO_DEGREE 180.0f / M_PI_float 37 | 38 | #ifndef sign 39 | #define sign(a) (((a)>=0.0)*2-1) 40 | #endif 41 | 42 | // prototypes 43 | #if defined(_WIN32) || defined(_WIN64) 44 | # define strtok_r strtok_s // strtok_r does not exist on windows, use strtok_s instead 45 | #endif /* #if defined(_WIN32) || defined(_WIN64) */ 46 | 47 | //===================================================================================================== 48 | // utils 49 | //===================================================================================================== 50 | double mod(double a, double N); 51 | float invSqrt(float x); 52 | void quaternion2YawPitchRoll(float q1, float q2, float q3, float q4, float *yaw, float *pitch, float *roll); 53 | void quaternion2RollPitchYaw(float q1, float q2, float q3, float q4, float *yaw, float *pitch, float *roll); 54 | void quaternionComposition(float q01, float q02, float q03, float q04, float q11, float q12, float q13, float q14, float *q21, float *q22, float *q23, float *q24); 55 | int stringToFloats(char* valueBuffer, float* data, int nvalues); 56 | int stringToChars(char* valueBuffer, char* data, int nvalues); 57 | 58 | void getMean3(double *samples, long numberOfSamples, float* mean); 59 | float getMean1f(float *samples, long numberOfSamples); 60 | float getStdDev1f(float *samples, long numberOfSamples, float mean); 61 | 62 | 63 | #endif /* defined(__hedrot_receiver__libhedrot_utils__) */ 64 | -------------------------------------------------------------------------------- /scripts/Win/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo this builds the following binaries (in 64 bits only): 3 | echo . the firmware (in firmware\build\hedrot-firmware.ino.hex 4 | echo . the command-line demo (in command-line-demo/xcode/hedrotReceiverDemo) 5 | echo . the max external hedrotReceiver.mxe64 6 | echo -- 7 | echo The Standlone hedrotReceiver has to be rebuilt afterwards in Max!!!! 8 | echo the 64 bit version of the Standlone hedrotReceiver has to be built in the folder hedrotReceiver\standalone-Win\x64 9 | echo -- 10 | 11 | set thisDirectory=%cd% 12 | set "rootDirectory=%thisDirectory%\..\.." 13 | 14 | REM ######### PATH SETTINGS ############################# 15 | set "ArduinoAppPath=C:\Program Files (x86)\Arduino\arduino_debug.exe" 16 | set "MSBuildPath=C:\Windows\Microsoft.NET\Framework\v4.0.30319" 17 | set "VCTargetsPath=C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110" 18 | 19 | 20 | REM ######### build firmware (both versions) ############################# 21 | rm -rf "%rootDirectory%\firmware\build\*" 22 | 23 | "%ArduinoAppPath%" --verify --board teensy:avr:teensy31:usb=serial,speed=96,opt=o1std,keys=en-us --pref "build.path=%rootDirectory%\firmware\build" "%rootDirectory%\firmware\hedrot-firmware\hedrot-firmware.ino" 24 | copy "%rootDirectory%\firmware\build\hedrot-firmware.ino.hex" "%rootDirectory%\firmware\hex\hedrot-firmware-teensy31-32.ino.hex" 25 | 26 | "%ArduinoAppPath%" --verify --board teensy:avr:teensyLC:usb=serial,speed=48,opt=osstd,keys=en-us --pref "build.path=%rootDirectory%\firmware\build" "%rootDirectory%\firmware\hedrot-firmware\hedrot-firmware.ino" 27 | copy "%rootDirectory%\firmware\build\hedrot-firmware.ino.hex" "%rootDirectory%\firmware\hex\hedrot-firmware-teensyLC.ino.hex" 28 | 29 | 30 | REM ######### build the command-line demo ############################# 31 | "%MSBuildPath%\MSBuild.exe" /t:Build "%rootDirectory%\command-line-demo\visual studio\hedrotReceiverDemo.vcxproj" /p:CommonProgramFiles="C:\Program Files (x86)\Common Files" /p:PlatformToolset=v110 /p:Configuration=Release /p:Platform=x64 /p:"VCTargetsPath=%VCTargetsPath%" 32 | 33 | REM ######### build the Max external ############################# 34 | "%MSBuildPath%\MSBuild.exe" /t:Build "%rootDirectory%\hedrotReceiver\visual studio\hedrot_receiver.vcxproj" /p:CommonProgramFiles="C:\Program Files (x86)\Common Files" /p:PlatformToolset=v110 /p:Configuration=Release /p:Platform=x64 /p:"VCTargetsPath=%VCTargetsPath%" 35 | -------------------------------------------------------------------------------- /command-line-demo/visual studio/hedrotReceiverDemo.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | -------------------------------------------------------------------------------- /matlab/calibration/test_script.m: -------------------------------------------------------------------------------- 1 | maxError = .05; # maximum radius deviation 2 | 3 | 4 | rawMagCalData = readTextOfflineCalrawData("/Users/baskind/Desktop/headtrackerRawMagCalibrationData.txt"); 5 | 6 | # estimation 1 (free ellipsoid) 7 | [ center1, radii1, evecs1, v1 ] = ellipsoid_fit( rawMagCalData, 0 ) 8 | 9 | # calculate and show calibrated data 10 | MagCalData1 = (rawMagCalData - ones(size(rawMagCalData,1),1)*center1')./(ones(size(rawMagCalData,1),1)*radii1')*evecs1; 11 | figure;plot3(MagCalData1(:,1),MagCalData1(:,2),MagCalData1(:,3),'o'); 12 | xlim([-1.5 1.5]);ylim([-1.5 1.5]);zlim([-1.5 1.5]); 13 | title("points after calibration, WITH rotation"); 14 | 15 | # calculate and show radius error 16 | radius_error1 = sqrt(MagCalData1(:,1).^2+MagCalData1(:,2).^2+MagCalData1(:,3).^2); 17 | figure;plot(radius_error1); 18 | title("error after calibration, WITH rotation");ylim([.8 1.2]);grid 19 | filteredIndexes = find(abs(radius_error1-1)<=maxError); 20 | min(radius_error1(filteredIndexes)), max(radius_error1(filteredIndexes)) 21 | 22 | 23 | # estimation 2 (non rotated ellipsoid) 24 | [ center2, radii2, evecs2, v2 ] = ellipsoid_fit( rawMagCalData, 1 ) 25 | 26 | # calculate and show calibrated data 27 | MagCalData2 = (rawMagCalData - ones(size(rawMagCalData,1),1)*center2')./(ones(size(rawMagCalData,1),1)*radii2'); 28 | figure;plot3(MagCalData2(:,1),MagCalData2(:,2),MagCalData2(:,3),'o'); 29 | xlim([-1.5 1.5]);ylim([-1.5 1.5]);zlim([-1.5 1.5]); 30 | title("points after calibration, NO rotation"); 31 | 32 | # calculate and show radius error 33 | radius_error2 = sqrt(MagCalData2(:,1).^2+MagCalData2(:,2).^2+MagCalData2(:,3).^2); 34 | figure;plot(radius_error2); 35 | title("error after calibration, NO rotation");ylim([.8 1.2]);grid 36 | filteredIndexes = find(abs(radius_error2-1)<=maxError); 37 | min(radius_error2(filteredIndexes)), max(radius_error2(filteredIndexes)) 38 | 39 | # estimation 3 (non rotated ellipsoid, second pass after removing the farther points) 40 | rawMagCalDataFiltered = rawMagCalData(filteredIndexes,:); 41 | [ center3, radii3, evecs3, v3 ] = ellipsoid_fit( rawMagCalDataFiltered, 1 ) 42 | 43 | # calculate and show calibrated data 44 | MagCalData3 = (rawMagCalDataFiltered - ones(size(rawMagCalDataFiltered,1),1)*center3')./(ones(size(rawMagCalDataFiltered,1),1)*radii3'); 45 | figure;plot3(MagCalData3(:,1),MagCalData3(:,2),MagCalData3(:,3),'o'); 46 | xlim([-1.5 1.5]);ylim([-1.5 1.5]);zlim([-1.5 1.5]); 47 | title("points after calibration, NO rotation, second pass"); 48 | 49 | # calculate and show radius error 50 | radius_error3 = sqrt(MagCalData3(:,1).^2+MagCalData3(:,2).^2+MagCalData3(:,3).^2); 51 | figure;plot(radius_error3); 52 | title("error after calibration, NO rotation, second pass");ylim([.8 1.2]);grid 53 | min(radius_error3), max(radius_error3) 54 | -------------------------------------------------------------------------------- /matlab/quaternion_library/TestScript.m: -------------------------------------------------------------------------------- 1 | % TestScript.m 2 | % 3 | % This script tests the quaternion library functions to ensure that each 4 | % function output is consistent. 5 | % 6 | % Date Author Notes 7 | % 27/09/2011 SOH Madgwick Initial release 8 | 9 | %% Start of script 10 | 11 | close all; % close all figures 12 | clear; % clear all variables 13 | clc; % clear the command terminal 14 | 15 | %% Axis-angle to rotation matrix 16 | 17 | axis = [1 2 3]; 18 | axis = axis / norm(axis); 19 | angle = pi/2; 20 | 21 | R = axisAngle2rotMat(axis, angle); 22 | num = ' % 1.5f'; 23 | a = sprintf('\rAxis-angle to rotation matrix:'); 24 | b = sprintf(strcat('\r', num, '\t', num, '\t', num), R(1,:)); 25 | c = sprintf(strcat('\r', num, '\t', num, '\t', num), R(2,:)); 26 | d = sprintf(strcat('\r', num, '\t', num, '\t', num), R(3,:)); 27 | disp(strcat(a,b,c,d)); 28 | 29 | %% Axis-angle to quaternion 30 | 31 | q = axisAngle2quatern(axis, angle); 32 | num = ' % 1.5f'; 33 | a = sprintf('\rAxis-angle to quaternion:'); 34 | b = sprintf(strcat('\r', num, '\t', num, '\t', num, '\t', num), q); 35 | disp(strcat(a,b)); 36 | 37 | %% Quaternion to rotation matrix 38 | 39 | R = quatern2rotMat(q); 40 | num = ' % 1.5f'; 41 | a = sprintf('\rQuaternion to rotation matrix:'); 42 | b = sprintf(strcat('\r', num, '\t', num, '\t', num), R(1,:)); 43 | c = sprintf(strcat('\r', num, '\t', num, '\t', num), R(2,:)); 44 | d = sprintf(strcat('\r', num, '\t', num, '\t', num), R(3,:)); 45 | disp(strcat(a,b,c,d)); 46 | 47 | %% Rotation matrix to quaternion 48 | 49 | q = rotMat2quatern(R); 50 | num = ' % 1.5f'; 51 | a = sprintf('\rRotation matrix to quaternion:'); 52 | b = sprintf(strcat('\r', num, '\t', num, '\t', num, '\t', num), q); 53 | disp(strcat(a,b)); 54 | 55 | %% Rotation matrix to ZYX Euler angles 56 | 57 | euler = rotMat2euler(R); 58 | num = ' % 1.5f'; 59 | a = sprintf('\rRotation matrix to ZYX Euler angles:'); 60 | b = sprintf(strcat('\r', num, '\t', num, '\t', num), euler); 61 | disp(strcat(a,b)); 62 | 63 | %% Quaternion to ZYX Euler angles 64 | 65 | euler = quatern2euler(q); 66 | num = ' % 1.5f'; 67 | a = sprintf('\rQuaternion to ZYX Euler angles:'); 68 | b = sprintf(strcat('\r', num, '\t', num, '\t', num), euler); 69 | disp(strcat(a,b)); 70 | 71 | %% ZYX Euler angles to rotation matrix 72 | 73 | R = euler2rotMat(euler(1), euler(2), euler(3)); 74 | num = ' % 1.5f'; 75 | a = sprintf('\rZYX Euler angles to rotation matrix:'); 76 | b = sprintf(strcat('\r', num, '\t', num, '\t', num), R(1,:)); 77 | c = sprintf(strcat('\r', num, '\t', num, '\t', num), R(2,:)); 78 | d = sprintf(strcat('\r', num, '\t', num, '\t', num), R(3,:)); 79 | disp(strcat(a,b,c,d)); 80 | 81 | %% End of script -------------------------------------------------------------------------------- /libhedrot/libhedrot_calibration.h: -------------------------------------------------------------------------------- 1 | // 2 | // libhedrot_calibration.h 3 | // hedrot_receiver 4 | // 5 | // Created by Alexis Baskind on 17/04/17. 6 | // 7 | // Part of code is derived from Matthieu Aussal, CMAP - Ecole Polytechnique / CNRS 8 | // 9 | 10 | 11 | 12 | #ifndef __hedrot_receiver__libhedrot_calibration__ 13 | #define __hedrot_receiver__libhedrot_calibration__ 14 | 15 | // constants 16 | #define MAX_NUMBER_OF_SAMPLES_FOR_CALIBRATION 100000 17 | #define MAX_CONDITION_NUMBER_OFFLINE 100000 18 | #define NORM_ERROR_TOLERANCE .05 // during calibration, all samples which norm is outside (1 +/- NORM_ERROR_TOLERANCE) after first pass of calibration are filtered out for the second pass 19 | 20 | #define MAX_ALLOWED_OFFSET 10000 21 | #define MAX_ALLOWED_SCALING 10000 22 | 23 | //===================================================================================================== 24 | // structure definition: temporary calibration data for magnetometer and accelerometer 25 | //===================================================================================================== 26 | 27 | typedef struct _calibrationData { 28 | long numberOfSamples; 29 | double rawSamples[MAX_NUMBER_OF_SAMPLES_FOR_CALIBRATION][3]; // raw samples 30 | double calSamples[MAX_NUMBER_OF_SAMPLES_FOR_CALIBRATION][3]; // calibrated samples 31 | float dataNorm[MAX_NUMBER_OF_SAMPLES_FOR_CALIBRATION]; // vector norm after calibration 32 | float conditionNumber; 33 | float normAverage; // average norm to the center 34 | float normStdDev; // standard deviation of the norm to the center 35 | float maxNormError; // maximum norm error (absolute value of norm minus averageNorm) 36 | } calibrationData; 37 | 38 | 39 | int accMagCalibration(calibrationData* calData, float* estimatedOffset, float* estimatedScaling); 40 | 41 | int myCalibration1(calibrationData* calData, float* estimatedOffset, float* estimatedScaling); 42 | 43 | int nonRotatedEllipsoidFit(calibrationData* calData, float* estimatedOffset, float* estimatedScaling, double *quadricCoefficients, double maxConditionNumber); 44 | int rotatedEllipsoidFit(calibrationData* calData, double *quadricCoefficients, double maxConditionNumber); 45 | 46 | int filterCalData(calibrationData *inCalData, calibrationData *outCalData, float center[3]); 47 | 48 | void cookCalibrationData(calibrationData* calData, float* estimatedOffset, float* estimatedScaling); 49 | void computeCalNormStatistics(calibrationData* calData, float* estimatedOffset, float* estimatedScaling, float* normAverage, float* normStdDev); 50 | 51 | 52 | #endif /* defined(__hedrot_receiver__libhedrot_calibration__) */ 53 | -------------------------------------------------------------------------------- /scripts/README-BUILD.txt: -------------------------------------------------------------------------------- 1 | how to build the binaries and create the distribution 2 | 3 | 4 | 1/ Mac OS X 5 | . edit « scripts/Mac/build.sh » and change the path to Arduino.app (variable ArduinoAppPath) if necessary 6 | . edit « Max/xcode/hedrot_receiver.xcconfig » and change the path to the « c74support » folder in the Max SDK (variable C74SUPPORT) 7 | . run « scripts/Mac/build.sh » from the command-line 8 | . open hedrotReceiver.maxproj in Max and build the standalone in the same directory 9 | . run « makeDistribution.sh » from the command-line 10 | 11 | 2/ Windows 12 | . edit « scripts/Win/build.bat » and change the following paths if necessary: 13 | - path to arduino.exe (variable ArduinoAppPath) 14 | - path to Microsoft.NET framework (variable MSBuildPath) 15 | - path to Visual Studio target V110 (variable VCTargetsPath) 16 | . edit "Max\visual studio\hedrot_receiver.props" and change the path to the « c74support » folder in the Max SDK (variable C74SUPPORT) 17 | . run « scripts/Win/build.bat » 18 | . open hedrotReceiver.maxproj in Max and build the standalone in the same directory 19 | . edit « scripts/Win/makeDistribution.bat »and change the following paths if necessary: 20 | - path to rcedit (small tool to change the app icon, available at https://github.com/electron/rcedit) 21 | . run « scripts/Win/makeDistribution.bat » 22 | 23 | In order to build hedrot binaries on Windows, a distribution of BLAS+LAPACK+LAPACKE is required. To build this distribution: 24 | 25 | . install MinGW for 64 bits. It can be found at: http://mingw-w64.org 26 | 27 | . install cmake version 2.8.12 (https://cmake.org/files/). CAUTION: lapack does not build with cmake v3+, build it with 2.8.12 28 | 29 | . download lapack sources from github (https://github.com/Reference-LAPACK). CAUTION: the latest release of the sources (3.7.0) does not build in 64 bits. The bug has been corrected afterwards (29 dec 2016). Download the repository version from 29 dec 2016, only this one will build. Here is the link: 30 | https://github.com/Reference-LAPACK/lapack-release/archive/42944f6fdee4de98fd1dd650c4f81047937635c2.zip 31 | 32 | . follow the instructions in http://icl.cs.utk.edu/lapack-for-windows/lapack/#build 33 | 34 | 35 | . in the visual studio project: 36 | 1/ add the directory containing the lapacke headers in Project Properties => Configuration Properties => C/C++ => General => Additional Include Directories 37 | 2/ add the directory containing the BLAS+lapack+lapacke .lib files in Project Properties => Configuration Properties => Linker => General => Additional Library Directories 38 | 39 | 40 | . the following DLLs built in the lapack sources are required for running the program: libblas.dll, liblapack.dll, liblapacke.dll. 41 | 42 | 43 | . copy all those dlls, as well as libgfortran-3.dll and libgcc_s_seh-1.dll, libquadmath-0.dll and libwinpthread-1.dll from the MinGW64 distribution close to the binary, i.e.: 44 | - for the command-line demo: command-line-demo\visual studio\exe\Release_x64 45 | - for the max external: in directory Max\ 46 | 47 | -------------------------------------------------------------------------------- /hedrotReceiver/xcode/hedrot_receiver.xcconfig: -------------------------------------------------------------------------------- 1 | // Xcode target configuration settings for the Max 6 SDK 2 | // Used as the basis for Xcode projects to build Max externals. 3 | // 4 | // Changes to the settings in this file will be applied to all SDK examples 5 | // To change settings for only one of the examples, override the settings using 6 | // Xcode's target inspector. 7 | // 8 | // by Timothy Place 9 | // Copyright © 2012, Cycling '74 10 | 11 | 12 | // Name & Version 13 | PRODUCT_NAME = $(PROJECT_NAME) 14 | PRODUCT_VERSION = 6.1.4 15 | ARCHS = i386 x86_64 16 | 17 | 18 | // Paths 19 | C74SUPPORT = /Volumes/Data/Developpement/SDKs/MaxSDK-6.1.4/c74support 20 | HEADER_SEARCH_PATHS = "$(C74SUPPORT)/max-includes" "$(C74SUPPORT)/msp-includes" "$(C74SUPPORT)/jit-includes" 21 | FRAMEWORK_SEARCH_PATHS = "$(C74SUPPORT)/max-includes" "$(C74SUPPORT)/msp-includes" "$(C74SUPPORT)/jit-includes" 22 | DSTROOT = $(SRCROOT) 23 | // (This next path is relative to DSTROOT) 24 | INSTALL_PATH = /.. 25 | 26 | 27 | // Special Files 28 | GCC_PREFIX_HEADER = $(C74SUPPORT)/max-includes/macho-prefix.pch 29 | INFOPLIST_FILE = Info.plist 30 | 31 | 32 | // Architecture and Deployment 33 | ARCHS = i386 x86_64 34 | 35 | // The following section sets the Mac SDK version to be used. 36 | // For most projects this has little to no impact because there are no direct dependencies on OS function calls. 37 | // In those projects with OS function calls, it should be okay to use the most recent SDK version because the 38 | // MACOSX_DEPLOYMENT_TARGET will disable functionality that is unavailable in the older target OS. 39 | // For this reason, the SDKROOT variable is commented out, telling Xcode to use the default (which is the most recent SDK). 40 | // 41 | // If you do need to define the SDKROOT, different versions of Xcode have varying syntax and varying versions of the SDK present. 42 | 43 | // Xcode 3.x 44 | // SDKROOT = $(DEVELOPER_DIR)/SDKs/MacOSX10.5.sdk 45 | 46 | // Xcode 4.0 - Xcode 4.2 47 | // SDKROOT = $(DEVELOPER_DIR)/SDKs/MacOSX10.6.sdk 48 | 49 | // Xcode 4.3+ 50 | // SDKROOT = macosx10.6 51 | 52 | MACOSX_DEPLOYMENT_TARGET = 10.6 53 | 54 | 55 | // Compiler Version -- leave them all commented out to get the default version provided by Xcode 56 | // GCC_VERSION = 4.2.1 57 | // GCC_VERSION = com.apple.compilers.llvmgcc42 58 | // GCC_VERSION = com.apple.compilers.llvm.clang.1_0 59 | 60 | 61 | // Preprocessor Defines 62 | GCC_PREPROCESSOR_DEFINITIONS = "DENORM_WANT_FIX = 1" "NO_TRANSLATION_SUPPORT = 1" 63 | 64 | 65 | // Static Configuration (don't change these) 66 | WRAPPER_EXTENSION = mxo; 67 | WARNING_CFLAGS = -Wmost -Wno-four-char-constants -Wno-unknown-pragmas 68 | DEPLOYMENT_LOCATION = YES 69 | GENERATE_PKGINFO_FILE = YES 70 | 71 | 72 | // Flags to enforce some build-time checks for the symbols used while not actually performing a hard link 73 | C74_SYM_LINKER_FLAGS = @$(C74SUPPORT)/max-includes/c74_linker_flags.txt 74 | 75 | 76 | // hide all symbols by default 77 | // mark a function to be exported with the C74_EXPORT macro -- most likely this will only apply to the main() function 78 | OTHER_CFLAGS = -fvisibility=hidden 79 | -------------------------------------------------------------------------------- /libhedrot/libhedrot_serialcomm.h: -------------------------------------------------------------------------------- 1 | // 2 | // libhedrot_serialcomm.h 3 | // 4 | // Part of code is derived from "comport", (c) 1998-2005 Winfried Ritsch, Institute for Electronic Music - Graz 5 | // 6 | // Copyright 2016 Alexis Baskind 7 | 8 | #ifndef __libheadtracker_serialcomm__ 9 | #define __libheadtracker_serialcomm__ 10 | 11 | #include 12 | 13 | // for serial communication 14 | #if defined(_WIN32) || defined(_WIN64) 15 | #include 16 | #include 17 | #else 18 | #include 19 | #include 20 | #include /* for ioctl DTR */ 21 | #include /* for TERMIO ioctl calls */ 22 | #include 23 | #include 24 | #include 25 | #define INVALID_HANDLE_VALUE -1 26 | #endif /* #if defined(_WIN32) || defined(_WIN64) */ 27 | 28 | // other includes 29 | #include "hedrot_comm_protocol.h" 30 | 31 | // internal constants 32 | #define MAX_NUMBER_OF_PORTS 99 33 | #define READ_BUFFER_SIZE 10000 34 | 35 | //===================================================================================================== 36 | // structure definition: headtrackerSerialcomm (all infos for serial communication with the headtracker) 37 | //===================================================================================================== 38 | 39 | typedef struct _headtrackerSerialcomm { 40 | char** availablePorts; 41 | int numberOfAvailablePorts; 42 | 43 | unsigned long numberOfReadBytes; 44 | unsigned char readBuffer[READ_BUFFER_SIZE]; 45 | 46 | // information about the opened port 47 | char *serial_device_name; 48 | int portNumber; // port number in the list "availablePorts" 49 | #if defined(_WIN32) || defined(_WIN64) 50 | HANDLE comhandle; /* holds the comport handle */ 51 | DCB dcb; /* holds the comm pars */ 52 | DCB dcb_old; /* holds the comm pars */ 53 | COMMTIMEOUTS old_timeouts; 54 | #else /* #if defined(_WIN32) || defined(_WIN64) */ 55 | struct termios com_termio; /* save the com config */ 56 | int comhandle; /* holds the headtracker_rcv handle */ 57 | fd_set com_rfds; 58 | #endif /* #if defined(_WIN32) || defined(_WIN64) */ 59 | 60 | int baud; /* holds the current baud rate */ 61 | 62 | char verbose; 63 | } headtrackerSerialcomm; 64 | 65 | //===================================================================================================== 66 | // function declarations 67 | //===================================================================================================== 68 | 69 | void serial_comm_init(headtrackerSerialcomm *x); 70 | void list_comm_ports(headtrackerSerialcomm *x); 71 | void init_read_serial(headtrackerSerialcomm *x); 72 | int is_data_available(headtrackerSerialcomm *x); 73 | int write_serial(headtrackerSerialcomm *x, unsigned char *serial_byte, unsigned long numberOfBytesToWrite); 74 | #if defined(_WIN32) || defined(_WIN64) 75 | HANDLE open_serial(headtrackerSerialcomm *x, char* portName); 76 | HANDLE close_serial(headtrackerSerialcomm *x); 77 | #else /* #if defined(_WIN32) || defined(_WIN64) */ 78 | int open_serial(headtrackerSerialcomm *x, char* portName); 79 | int close_serial(headtrackerSerialcomm *x); 80 | #endif 81 | 82 | 83 | #endif /* defined(__libheadtracker_serialcomm__) */ 84 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | hedrot distribution, changelog: 2 | 3 | Version 1.3.0 (XX/XX/18) 4 | . 3D-printable enclosure ! (provided are the source Sketchup files as well as the STL files needed for printing) 5 | . now compatible with alternative version of the gy-85 board using qst QMC5883L magnetometer instead of Honeywell HMC5883L 6 | . magnetometer calibration: less constraints on so-called « absurd » estimation: now able to deal with bigger magnetic field biases that may occur with some headphones 7 | . added specific gyroscope-only estimation method (if the magnetometer does not provide reliable results) 8 | . minor: Magnetometer settings: « gain » renamed as « range » 9 | 10 | Version 1.2.2 (04/09/17) 11 | . bug solved: accelerometer hard offset could not be negative in the Max app 12 | 13 | Version 1.2.1 (04/08/17) 14 | . version 8 of the firmware. Version 8 offers exactly the same functionalities as version 7, but adds a self test when the board is connected or reset: 15 | - if everything goes well, the onboard led should blink twice slowly (then it’s ready for use) 16 | - if the teensy board can connect to the daughter sensor board but cannot read its data, the onboard led blinks fast endlessly 17 | - if the teensy board cannot connect to the daughter board, nothing happens 18 | => in both latter cases, there is probably a hardware problem: either the daugther board is damaged, or there is bad contact in the connections between both boards, or the main teensy board is damaged. 19 | 20 | Version 1.2.0 (02/08/17) 21 | . calibration routines ported in the library, completely rewritten and enhanced 22 | . experimental real-time magnetometer calibration routines 23 | . default headtracker parameters (MaxGain, acc LP filter, magnetometer rate) slightly modified for better results 24 | . added icon 25 | . added firmware for teensy LC 26 | 27 | Version 1.1.1 (07/04/17) 28 | . minor doc update 29 | . better detection if magnetometer/accelerometer is calibrated or not 30 | . bug correction on 64 bits: invSqrt sometimes provided negative results (flips the sign of the quaternion but has no effect on the estimated angles 31 | 32 | Version 1.1.0 (28/02/17) 33 | . GUI: window smaller 34 | . GUI: 3D visual display of the head tracker 35 | . ability to change the orientation of the X-Y-Z axes, the yaw-pitch-roll rotation order and to invert the rotation 36 | . doc update, examples with Reaper/Ambix, mybino and Max/Spat 37 | . OSC output: scaling options, for instance to control plugins in Reaper 38 | . the MaxBeta parameter can now be set to 0 in order to disconnect the magnetometer 39 | . Much smaller App « hedrotReceiver » 40 | 41 | Version 1.0.3 (10/02/17) 42 | . Windows version 43 | . bug solved: hedrotReceiver: only yaw transmitted by default, although « yaw/pitch/roll » is selected on startup 44 | 45 | Version 1.0.2 (20/11/16) 46 | . added sources of Max patch in the distribution 47 | . quaternion output (added an extra outlet in the Max patch) 48 | 49 | Version 1.0.1 (15/11/16) 50 | . development bugfix: possible crash with max external when compiled in Development configuration 51 | . development bugfix: problem with search paths when including hedrotReceiver.maxpat in a bigger max standalone app 52 | . added version number to attributes of hedrotReceiver.app 53 | . hedrotReceiver.app: fixed problem with receiver attributes not being updated in the GUI 54 | . hedrotReceiver.app: various GUI optimizations 55 | 56 | Version 1.0.0 (6/11/16) - initial release -------------------------------------------------------------------------------- /hedrotReceiver/xcode/hedrot_receiver.xcodeproj/xcuserdata/baskind.xcuserdatad/xcschemes/max-external.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 48 | 49 | 50 | 56 | 57 | 58 | 59 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /command-line-demo/xcode/hedrotReceiverDemo.xcodeproj/xcuserdata/baskind.xcuserdatad/xcschemes/headtracker_rcv_cmd.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /firmware/hedrot-firmware/hedrot_comm_protocol.h: -------------------------------------------------------------------------------- 1 | // hedrot_comm_protocol.h: all constants related to communication protocol betwenn headtracker and receiver 2 | // 3 | // Copyright 2016 Alexis Baskind 4 | 5 | 6 | 7 | // "R2H_" constants correspond to messages sent from receiver to headtracker 8 | // "H2R_" constants correspond to messages sent from headtracker to receiver 9 | 10 | 11 | #ifndef _HEADTRACKER_COMM_PROTOCOL_H_ 12 | #define _HEADTRACKER_COMM_PROTOCOL_H_ 13 | 14 | #define HEDROT_FIRMWARE_VERSION 10 15 | 16 | //serial communication settings 17 | #define BAUDRATE 230400 18 | 19 | #define NUMBER_OF_BYTES_IN_RAWDATA_FRAME 21 20 | 21 | 22 | // reserved bytes (corresponding to ASCII codes, and cannot be used for codes): 23 | // . 44 (ASCII code corresponding to ',') 24 | // . 45 (ASCII code corresponding to '-') 25 | // . 46 (ASCII code corresponding to '.') 26 | // . from 48 to 57 (ASCII codes corresponding to digits 0-9) 27 | 28 | // standard ASCII codes for transmission of decimal values 29 | #define ASCII_0 48 30 | #define ASCII_9 57 31 | #define CARRIAGE_RETURN 13 32 | #define SPACE 32 33 | #define COMMA 44 34 | #define MINUS 45 35 | #define DOT 46 36 | 37 | 38 | // data sent from receiver to headtracker 39 | #define R2H_STOP_TRANSMISSION_CHAR 0 40 | 41 | #define R2H_SEND_INFO_CHAR 1 42 | 43 | #define R2H_START_TRANSMIT_ACCEL_OFFSET_DATA_CHAR 2 44 | #define R2H_STOP_TRANSMIT_ACCEL_OFFSET_DATA_CHAR 3 45 | 46 | #define R2H_START_TRANSMIT_ACCEL_SCALING_DATA_CHAR 4 47 | #define R2H_STOP_TRANSMIT_ACCEL_SCALING_DATA_CHAR 5 48 | 49 | #define R2H_START_TRANSMIT_MAG_OFFSET_DATA_CHAR 6 50 | #define R2H_STOP_TRANSMIT_MAG_OFFSET_DATA_CHAR 7 51 | 52 | #define R2H_START_TRANSMIT_MAG_SCALING_DATA_CHAR 8 53 | #define R2H_STOP_TRANSMIT_MAG_SCALING_DATA_CHAR 9 54 | 55 | #define R2H_TRANSMIT_SAMPLERATE 11 56 | 57 | #define R2H_TRANSMIT_GYRO_RATE 21 58 | #define R2H_TRANSMIT_GYRO_CLOCK_SOURCE 22 59 | #define R2H_TRANSMIT_GYRO_LPF_BANDWIDTH 23 60 | 61 | #define R2H_TRANSMIT_ACCEL_RANGE 31 62 | #define R2H_START_TRANSMIT_ACCEL_HARD_OFFSET 32 63 | #define R2H_STOP_TRANSMIT_ACCEL_HARD_OFFSET 33 64 | #define R2H_TRANSMIT_ACCEL_FULL_RESOLUTION_BIT 34 65 | #define R2H_TRANSMIT_ACCEL_DATARATE 35 66 | 67 | #define R2H_TRANSMIT_MAG_MEASUREMENT_BIAS 51 68 | #define R2H_TRANSMIT_MAG_SAMPLE_AVERAGING 52 69 | #define R2H_TRANSMIT_MAG_DATA_RATE 53 70 | #define R2H_TRANSMIT_MAG_GAIN 54 71 | #define R2H_TRANSMIT_MAG_MEASUREMENT_MODE 55 72 | 73 | #define R2H_AREYOUTHERE_CHAR 126 74 | #define R2H_PING_CHAR 127 75 | 76 | // data sent from headtracker to receiver 77 | // must be between 0 and 127 so that the MSB is always 0 78 | // (MSB = 1 is reserved for transmitting headtracking data) 79 | #define H2R_END_OF_RAWDATA_FRAME 0 80 | #define H2R_BOARD_OVERLOAD 1 // the teensy is too slow (the samplerate is too high) 81 | 82 | 83 | #define H2R_START_TRANSMIT_INFO_CHAR 11 84 | #define H2R_STOP_TRANSMIT_INFO_CHAR 12 85 | 86 | #define H2R_DATA_RECEIVE_ERROR_CHAR 21 87 | 88 | #define H2R_IAMTHERE_CHAR 126 89 | #define H2R_PING_CHAR 127 90 | 91 | 92 | 93 | #endif /* _HEADTRACKER_COMM_PROTOCOL_H_ */ 94 | -------------------------------------------------------------------------------- /firmware/hedrot-firmware/I2Ccom.cpp: -------------------------------------------------------------------------------- 1 | // I2Ccom: I2C communication with the I2c_t3 library 2 | 3 | #include "I2Ccom.h" 4 | 5 | // pas ultra efficace car on fait appel à deux autres fonctions 6 | void writeBit(uint8_t address, uint8_t subAddress, uint8_t bitnumber, uint8_t data) { 7 | uint8_t b = readByte(address, subAddress); 8 | b = (data != 0) ? (b | (1 << bitnumber)) : (b & ~(1 << bitnumber)); 9 | writeByte(address, subAddress, b); 10 | } 11 | 12 | void writeBits(uint8_t address, uint8_t subAddress, uint8_t bitStart, uint8_t length, uint8_t data) { 13 | // 010 value to write 14 | // 76543210 bit numbers 15 | // xxx args: bitStart=4, length=3 16 | // 00011100 mask byte 17 | // 10101111 original value (sample) 18 | // 10100011 original & ~mask 19 | // 10101011 masked | value 20 | uint8_t b = readByte(address, subAddress); 21 | uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); 22 | data <<= (bitStart - length + 1); // shift data into correct position 23 | data &= mask; // zero all non-important bits in data 24 | b &= ~(mask); // zero all important bits in existing byte 25 | b |= data; // combine data with existing byte 26 | writeByte(address, subAddress, b); 27 | } 28 | 29 | void writeByte(uint8_t address, uint8_t subAddress, uint8_t data) { 30 | Wire.beginTransmission(address); // Initialize the Tx buffer 31 | Wire.write(subAddress); // Put slave register address in Tx buffer 32 | Wire.write(data); // Put data in Tx buffer 33 | Wire.endTransmission(); // Send the Tx buffer 34 | } 35 | 36 | bool readBit(uint8_t address, uint8_t subAddress, uint8_t bitnumber) { 37 | uint8_t data; // `data` will store the register data (whole byte) 38 | Wire.beginTransmission(address); // Initialize the Tx buffer 39 | Wire.write(subAddress); // Put slave register address in Tx buffer 40 | Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive 41 | // Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive 42 | // Wire.requestFrom(address, 1); // Read one byte from slave register address 43 | Wire.requestFrom(address, (size_t) 1); // Read one byte from slave register address 44 | data = Wire.read(); // Fill Rx buffer with result 45 | return data & (1 << bitnumber); // Return data read from slave register 46 | } 47 | 48 | uint8_t readBits(uint8_t address, uint8_t subAddress, uint8_t bitStart, uint8_t length) { 49 | // 01101001 read byte 50 | // 76543210 bit numbers 51 | // xxx args: bitStart=4, length=3 52 | // 010 masked 53 | // -> 010 shifted 54 | uint8_t b; 55 | b = readByte(address, subAddress); 56 | uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); 57 | b &= mask; 58 | b >>= (bitStart - length + 1); 59 | 60 | return b; 61 | } 62 | 63 | uint8_t readByte(uint8_t address, uint8_t subAddress) { 64 | uint8_t data; // `data` will store the register data 65 | Wire.beginTransmission(address); // Initialize the Tx buffer 66 | Wire.write(subAddress); // Put slave register address in Tx buffer 67 | Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive 68 | // Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive 69 | // Wire.requestFrom(address, 1); // Read one byte from slave register address 70 | Wire.requestFrom(address, (size_t) 1); // Read one byte from slave register address 71 | data = Wire.read(); // Fill Rx buffer with result 72 | return data; // Return data read from slave register 73 | } 74 | 75 | int8_t readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest) { 76 | Wire.beginTransmission(address); // Initialize the Tx buffer 77 | Wire.write(subAddress); // Put slave register address in Tx buffer 78 | Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive 79 | // Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive 80 | uint8_t i = 0; 81 | // Wire.requestFrom(address, count); // Read bytes from slave register address 82 | Wire.requestFrom(address, (size_t) count); // Read bytes from slave register address 83 | while (Wire.available()) { 84 | dest[i++] = Wire.read(); } // Put read results in the Rx buffer 85 | return i; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /matlab/computeAnglesMadgwick.m: -------------------------------------------------------------------------------- 1 | % computeAnglesMadgwick.m 2 | % 3 | % octave/matlab version of angle estimation in libhedrot 4 | % 5 | % Part of code is derived from Sebastian Madgwick's open-source gradient descent angle estimation algorithm 6 | % 7 | % Copyright 2016 Alexis Baskind 8 | 9 | function newHeadtrackerData = computeAnglesMadgwick(headtrackerData) 10 | newHeadtrackerData = headtrackerData; 11 | 12 | SamplePeriod = 1/newHeadtrackerData.header.samplerate; 13 | alphaMin = newHeadtrackerData.header.accLPalphaMin; 14 | alphaGain = newHeadtrackerData.header.accLPalphaGain; 15 | BetaMax = newHeadtrackerData.header.MadgwickBetaMax; 16 | BetaGain = newHeadtrackerData.header.MadgwickBetaGain; 17 | 18 | accLPstate = newHeadtrackerData.data.accCalData(1, :); 19 | 20 | %the first value is left as it was calculated by the headtracker receiver (initialization) 21 | for t = 2:length(newHeadtrackerData.data.gyroCalData(:,1)) 22 | [newHeadtrackerData.data.quaternion(t, :), newHeadtrackerData.data.step(t, :), accLPstate] = Update(newHeadtrackerData.data.quaternion(t-1, :), SamplePeriod, alphaMin, alphaGain, BetaMax, BetaGain, accLPstate, newHeadtrackerData.data.gyroCalData(t,:), newHeadtrackerData.data.accCalData(t,:), newHeadtrackerData.data.magCalData(t,:)); 23 | end 24 | 25 | eulerAngles = quatern2euler(quaternConj(newHeadtrackerData.data.quaternion)) * (180/pi); %roll pitch yaw 26 | newHeadtrackerData.data.yawPitchRoll = [eulerAngles(:,3) eulerAngles(:,2) eulerAngles(:,1)]; 27 | endfunction 28 | 29 | 30 | %% method (derived from MadgwickAHRS.m without classdef) 31 | function [outputQuaternion, step, accLPstate] = Update(inputQuaternion, SamplePeriod, alphaMin, alphaGain, BetaMax, BetaGain, oldAccLPstate, GyroscopeData, AccelerometerData, MagnetometerData) 32 | q = inputQuaternion; % short name local variable for readability 33 | 34 | % compute gyro_norm2 35 | gyro_norm2 = GyroscopeData(1)^2 + GyroscopeData(2)^2 + GyroscopeData(3)^2; 36 | 37 | % lowpass Accelerometer data 38 | accLPalpha = alphaMin + (1 - alphaMin) * min(max(alphaGain * gyro_norm2,0),1); 39 | AccelerometerDataLP(1) = accLPalpha * AccelerometerData(1) + (1 - accLPalpha) * oldAccLPstate(1); 40 | AccelerometerDataLP(2) = accLPalpha * AccelerometerData(2) + (1 - accLPalpha) * oldAccLPstate(2); 41 | AccelerometerDataLP(3) = accLPalpha * AccelerometerData(3) + (1 - accLPalpha) * oldAccLPstate(3); 42 | %filter state update 43 | accLPstate(1) = AccelerometerDataLP(1); 44 | accLPstate(2) = AccelerometerDataLP(2); 45 | accLPstate(3) = AccelerometerDataLP(3); 46 | 47 | % Normalise Accelerometer measurement 48 | if(norm(AccelerometerData) == 0), return; end % handle NaN 49 | AccelerometerDataLP = AccelerometerDataLP / norm(AccelerometerDataLP); % normalise magnitude 50 | 51 | % Normalise Magnetometer measurement 52 | if(norm(MagnetometerData) == 0), return; end % handle NaN 53 | MagnetometerData = MagnetometerData / norm(MagnetometerData); % normalise magnitude 54 | 55 | % Reference direction of Earth's magnetic feild 56 | h = quaternProd(q, quaternProd([0 MagnetometerData], quaternConj(q))); 57 | b = [0 norm([h(2) h(3)]) 0 h(4)]; 58 | 59 | % Gradient decent algorithm corrective step 60 | F = [2*(q(2)*q(4) - q(1)*q(3)) - AccelerometerDataLP(1) 61 | 2*(q(1)*q(2) + q(3)*q(4)) - AccelerometerDataLP(2) 62 | 2*(0.5 - q(2)^2 - q(3)^2) - AccelerometerDataLP(3) 63 | 2*b(2)*(0.5 - q(3)^2 - q(4)^2) + 2*b(4)*(q(2)*q(4) - q(1)*q(3)) - MagnetometerData(1) 64 | 2*b(2)*(q(2)*q(3) - q(1)*q(4)) + 2*b(4)*(q(1)*q(2) + q(3)*q(4)) - MagnetometerData(2) 65 | 2*b(2)*(q(1)*q(3) + q(2)*q(4)) + 2*b(4)*(0.5 - q(2)^2 - q(3)^2) - MagnetometerData(3)]; 66 | J = [-2*q(3), 2*q(4), -2*q(1), 2*q(2) 67 | 2*q(2), 2*q(1), 2*q(4), 2*q(3) 68 | 0, -4*q(2), -4*q(3), 0 69 | -2*b(4)*q(3), 2*b(4)*q(4), -4*b(2)*q(3)-2*b(4)*q(1), -4*b(2)*q(4)+2*b(4)*q(2) 70 | -2*b(2)*q(4)+2*b(4)*q(2), 2*b(2)*q(3)+2*b(4)*q(1), 2*b(2)*q(2)+2*b(4)*q(4), -2*b(2)*q(1)+2*b(4)*q(3) 71 | 2*b(2)*q(3), 2*b(2)*q(4)-4*b(4)*q(2), 2*b(2)*q(1)-4*b(4)*q(3), 2*b(2)*q(2)]; 72 | step = (J'*F); 73 | step = step / norm(step); % normalise step magnitude 74 | 75 | 76 | % compute beta 77 | Beta = BetaMax * (1 - min(max(BetaGain * gyro_norm2,0),1)); 78 | 79 | % Compute rate of change of quaternion 80 | qDot = 0.5 * quaternProd(q, [0 GyroscopeData(1) GyroscopeData(2) GyroscopeData(3)]) - Beta * step'; 81 | 82 | % Integrate to yield quaternion 83 | q = q + qDot * SamplePeriod; 84 | outputQuaternion = q / norm(q); % normalise quaternion 85 | end 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hedrot 2 | 3 | ### Note: the development of hedrot has been stopped and the project is currently not maintained. 4 | 5 | ## What is hedrot? 6 | Hedrot (for "head rotation tracker") is a low-cost (around 25 euros with a teensy LC) and efficient open-source hardware/software solution for head tracking. Hedrot is especially suitable for binaural rendering (3D-Audio on headphones), and has been initially designed for use with the binaural renderer Bipan as part of the Bili Project http://www.bili-project.org/. 7 | 8 | Hedrot provides an estimation of the rotation of the sensor (thus of the head if the sensor is attached to headphones) for the most usual x-y-z coordinate systems, either as a quaternion, or as a set of 3 orientation angles yaw, pitch and roll with two different orders (yaw-pitch-roll or roll-pitch-yaw). The main application provided with the distribution, hedrotReceiver, sends this information as OSC streams, with the extra possibility to scale each stream independently. 9 | 10 | Contrary to several generic open-source head tracking solutions, hedrot relies on and has been optimized for specific widely spread and efficient hardware parts, i.e. a Teensy 3 or Teensy LC board (optimized Arduino-like board) combined to a IMU/MARG daughter board with 3 common sensors (Analog Devices ADXL345 accelerometer, Honeywell HMC5883L magnetometer and Invensense ITG-3200 gyroscope). 11 | 12 | The estimation algorithm is based on a modified version of the precise and efficient open-source gradient descent algorithm from Sebastian Madgwick. The technology was dramatically optimized for speed: the head tracker can deliver data at rates up to 2 kHz. The hardware latency of the Teensy board and USB communication relies below 2 ms. The overall latency (including sensor latency and time constant of the algorithm) is being currently measured. 13 | 14 | ## Licensing and Credits 15 | The first development phase of Hedrot has achieved in collaboration with the Conservatoire National Supérieur de Musique et de Danse de Paris (http://www.conservatoiredeparis.fr/) as part of the "Bili" project (http://www.bili-project.org/). 16 | 17 | Matthieu Aussal (CMAP - Ecole Polytechnique / CNRS) contributed to new calibration routines (version > 1.2) 18 | 19 | Hedrot is licensed under the terms of the GNU General Public License (version 3) as published by the Free Software Foundation. 20 | 21 | Part of code is derived from Sebastian Madgwick's open-source gradient descent angle estimation algorithm (http://x-io.co.uk/open-source-imu-and-ahrs-algorithms/) 22 | 23 | 24 | ### Developers and Contributors 25 | * Alexis Baskind (sound engineer, main developer) 26 | * Jean-Christophe Messonnier (sound engineer) 27 | * Jean-Marc Lyzwa (sound engineer) 28 | * Matthieu Aussal, CMAP - Ecole Polytechnique / CNRS (calibration routines) 29 | 30 | 31 | ## Hardware Requirements 32 | - Head tracker parts: 33 | - 1 Teensy 3 board (tested with versions 3.1, 3.2 and LC) 34 | - 1 USB to Micro-USB 2.0 cable, minimum length 1.5 m 35 | - 1 gy85 IMU daughter board with the following sensors: 36 | - 1 Analog Devices ADXL345 accelerometer 37 | - 1 Honeywell HMC5883L compass (magnetometer) 38 | - 1 Invensense ITG3200 gyroscope 39 | 40 | ## Software Requirements 41 | - Mac OS 10.9.5 or later 42 | - Windows: Windows 7 or later 43 | - the teensy.app firmware flash loader 44 | - Windows: Microsoft Visual C++ 2012 Redistributable package (x86 or x64 version, depending on if a 32 or 64 bit version of the hedrot is being used) 45 | - Windows: Teensy serial driver (called "Windows Serial Installer" on https://www.pjrc.com) 46 | 47 | ## Extra Requirements for building from sources: 48 | - Xcode version 8.2 or later (for Mac), or Visual Studio 2012 (for Windows) 49 | - Windows: a windows version of awk (like gawk) and the program 7-zip to make the package 50 | - Max version 6 at least (to rebuild the "hedrotReceiver" application. Not needed otherwise) 51 | - Arduino IDE 1.8.3 52 | - Windows: a distribution of BLAS, Lapack and LAPACKE. See README-BUILD.txt for more information about how to build it 53 | - Teensyduino 1.37 (teensy support for the Arduino IDE and the teensy USB serial driver on Windows), with at least the i2c_t3 library. Note: Teensyduino already includes the Teensy serial driver on Windows 54 | 55 | ## Project organisation 56 | - the empty folder "build" is where the distribution will be built 57 | - the folder "command-line-demo" contains the sources of the command-line demonstration 58 | - the folder "doc" contains the documentation 59 | - the folder "examples" contains application examples 60 | - the folder "firmware" contains the sources of the firmware to be uploaded in the teensy board 61 | - the folder "libhedrot" contains the sources of the receiver library 62 | - the folder "matlab" contains programs for matlab and octave 63 | - the folder "Max" contains the sources of the main receiver application, written in Max 64 | - the folder "scripts" contains the scripts for building binaries and the distribution 65 | -------------------------------------------------------------------------------- /scripts/Mac/makeDistribution.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Before running this script, be sure that: " 3 | echo " 1/ all binaries have been compiled" 4 | echo " 2/ a pdf version of the doc has been created" 5 | echo " 3/ the Max standalone hedrotReceiver has been built." 6 | 7 | today=$(date +"%y-%m-%d") 8 | 9 | thisDirectory=`pwd` 10 | rootDirectory=$thisDirectory/../.. 11 | destDirectory=$rootDirectory/build/forPackaging 12 | 13 | hedrotVersion=`awk '/^#define HEDROT_VERSION / { print $3 }' $rootDirectory/libhedrot/libhedrot.h | sed 's/"//g'` 14 | hedrotVersionMessage="hedrot version: $hedrotVersion" 15 | echo $hedrotVersionMessage 16 | 17 | hedrotFirmwareVersion=`awk '/^#define HEDROT_FIRMWARE_VERSION / { print $3 }' $rootDirectory/firmware/hedrot-firmware/hedrot_comm_protocol.h` 18 | hedrotFirmwareVersionMessage="Headtracker Firmware version: $hedrotFirmwareVersion" 19 | echo $hedrotFirmwareVersionMessage 20 | 21 | packageName="hedrot-$hedrotVersion-${today}-Mac" 22 | packageFolder="$destDirectory/$packageName" 23 | 24 | 25 | ######### create destination folder ############################# 26 | rm -rf $destDirectory/* 27 | mkdir $packageFolder 28 | 29 | ######### prepare and copy Max Standalone ############################# 30 | 31 | #copy the standalone and the default preset file 32 | cp -R $rootDirectory/hedrotReceiver/hedrotReceiver.app $packageFolder 33 | cp -R $rootDirectory/hedrotReceiver/hedrotReceiver.json $packageFolder 34 | 35 | appcontentsdirectory=$packageFolder/hedrotReceiver.app/Contents 36 | 37 | #update the version number and icon in Info.plist 38 | /usr/libexec/PlistBuddy -c "Set :CFBundleGetInfoString '${hedrotVersion}'" $appcontentsdirectory/Info.plist 39 | /usr/libexec/PlistBuddy -c "Set :CFBundleLongVersionString '${hedrotVersion}'" $appcontentsdirectory/Info.plist 40 | /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString '${hedrotVersion}'" $appcontentsdirectory/Info.plist 41 | /usr/libexec/PlistBuddy -c "Set :CFBundleVersion '${hedrotVersion}'" $appcontentsdirectory/Info.plist 42 | /usr/libexec/PlistBuddy -c "Set :CFBundleIconFile 'hedrot.icns'" $appcontentsdirectory/Info.plist 43 | 44 | 45 | rm $appcontentsdirectory/Resources/*.icns 46 | cp ../logo/hedrot.icns $appcontentsdirectory/Resources/ 47 | 48 | 49 | 50 | ######### copy the command-line-demo ############################# 51 | mkdir $packageFolder/command-line-demo 52 | cp "$rootDirectory/command-line-demo/xcode/hedrotReceiverDemo" "$packageFolder/command-line-demo/" 53 | 54 | ######### copy the firmware (both versions) ############################# 55 | mkdir $packageFolder/firmware 56 | cp "$rootDirectory/firmware/hex/hedrot-firmware-teensy31-32.ino.hex" "$packageFolder/firmware/hedrot-firmware-teensy31-32_version_$hedrotFirmwareVersion.hex" 57 | cp "$rootDirectory/firmware/hex/hedrot-firmware-teensyLC.ino.hex" "$packageFolder/firmware/hedrot-firmware-teensyLC_version_$hedrotFirmwareVersion.hex" 58 | cp "$rootDirectory/firmware/CHANGELOG.txt" "$packageFolder/firmware/" 59 | 60 | ######### copy the max source code and external ############################# 61 | mkdir $packageFolder/Max 62 | cp $rootDirectory/hedrotReceiver/hedrotReceiver.json $packageFolder/Max/ 63 | cp $rootDirectory/hedrotReceiver/patches/*.maxpat $packageFolder/Max/ 64 | cp -R $rootDirectory/hedrotReceiver/hedrot_receiver.mxo $packageFolder/Max/ 65 | 66 | ######### copy the examples folder ############################# 67 | mkdir $packageFolder/examples 68 | cp -R $rootDirectory/examples $packageFolder/examples 69 | 70 | ######### copy the doc ############################# 71 | cp "$rootDirectory/doc/hedrot user manual.pdf" "$packageFolder/" 72 | 73 | ######### copy the license file ############################# 74 | cp "$rootDirectory/LICENSE" "$packageFolder/" 75 | 76 | ######### copy the CHANGELOG.txt file ############################# 77 | cp "$rootDirectory/CHANGELOG.txt" "$packageFolder/" 78 | 79 | ######### copy and update the main README.txt file ############################# 80 | cp "$rootDirectory/scripts/README-DISTRIBUTION.txt" "$packageFolder/README.txt" 81 | perl -pi -w -e "s/Hedrot Version: XXXX/Hedrot Version: $hedrotVersion/g;" $packageFolder/README.txt 82 | perl -pi -w -e "s/Firmware Version: YYYY/Firmware Version: $hedrotFirmwareVersion/g;" $packageFolder/README.txt 83 | 84 | ######### change icon of the app folder ############################# 85 | Rez -append ../logo/hedrot.rsrc -o $packageFolder$'/Icon\r' 86 | SetFile -a C $packageFolder/ 87 | SetFile -a V $packageFolder$'/Icon\r' 88 | 89 | 90 | ######### DMG ############################# 91 | 92 | #erase the DMG if it exists 93 | rm "$rootDirectory/build/$packageName.dmg" 94 | 95 | #create the DMG 96 | # the following line (creating a .Trash) is a hocus-pocus work-around that some times works when hdiutils does not succeed and returns an error 5341 (bug) 97 | touch $destDirectory/.Trash 98 | 99 | hdiutil create "$rootDirectory/build/$packageName.dmg" -volname "$packageName" -fs HFS+ -srcfolder $destDirectory 100 | 101 | #erase temp build directory 102 | rm -rf $destDirectory/* -------------------------------------------------------------------------------- /firmware/hedrot-firmware/Mag5883.h: -------------------------------------------------------------------------------- 1 | // Mag5883.h: Mag5883 I2C device methods for both Magnetometers used in gy-85 boards: 2 | // . Honeywell HMC5883L 3 | // . QMC5883L 4 | // part of code derived from [DFRobot](http://www.dfrobot.com), 2017 5 | // part of code derived from I2Cdev library 6 | 7 | #ifndef Mag5883_H 8 | #define Mag5883_H 9 | 10 | #include "I2Ccom.h" 11 | 12 | 13 | #define HMC5883L_ADDRESS 0x1E 14 | #define QMC5883_ADDRESS 0x0D 15 | 16 | 17 | #define HMC5883L_REG_CONFIG_A 0x00 18 | #define HMC5883L_REG_CONFIG_B 0x01 19 | #define HMC5883L_REG_MODE 0x02 20 | #define HMC5883L_REG_OUT_X_M 0x03 21 | #define HMC5883L_REG_OUT_X_L 0x04 22 | #define HMC5883L_REG_OUT_Z_M 0x05 23 | #define HMC5883L_REG_OUT_Z_L 0x06 24 | #define HMC5883L_REG_OUT_Y_M 0x07 25 | #define HMC5883L_REG_OUT_Y_L 0x08 26 | #define HMC5883L_REG_STATUS 0x09 27 | #define HMC5883L_REG_IDENT_A 0x0A 28 | #define HMC5883L_REG_IDENT_B 0x0B 29 | #define HMC5883L_REG_IDENT_C 0x0C 30 | 31 | 32 | #define QMC5883_REG_OUT_X_M 0x01 33 | #define QMC5883_REG_OUT_X_L 0x00 34 | #define QMC5883_REG_OUT_Z_M 0x05 35 | #define QMC5883_REG_OUT_Z_L 0x04 36 | #define QMC5883_REG_OUT_Y_M 0x03 37 | #define QMC5883_REG_OUT_Y_L 0x02 38 | #define QMC5883_REG_STATUS 0x06 39 | #define QMC5883_REG_CONFIG_1 0x09 40 | #define QMC5883_REG_CONFIG_2 0x0A 41 | #define QMC5883_REG_IDENT_B 0x0B 42 | #define QMC5883_REG_IDENT_C 0x20 43 | #define QMC5883_REG_IDENT_D 0x21 44 | 45 | // measurement bias 46 | #define HMC5883L_CRA_BIAS_BIT 1 47 | #define HMC5883L_CRA_BIAS_LENGTH 2 48 | 49 | #define HMC5883L_BIAS_NORMAL 0x00 50 | #define HMC5883L_BIAS_POSITIVE 0x01 51 | #define HMC5883L_BIAS_NEGATIVE 0x02 52 | 53 | // range 54 | #define HMC5883L_CRB_RANGE_BIT 7 55 | #define HMC5883L_CRB_RANGE_LENGTH 3 56 | 57 | #define HMC5883L_RANGE_0_88G 0x00 58 | #define HMC5883L_RANGE_1_3G 0x01 59 | #define HMC5883L_RANGE_1_9G 0x02 60 | #define HMC5883L_RANGE_2_5G 0x03 61 | #define HMC5883L_RANGE_4_G 0x04 62 | #define HMC5883L_RANGE_4_7G 0x05 63 | #define HMC5883L_RANGE_5_6G 0x06 64 | #define HMC5883L_RANGE_8_1G 0x07 65 | 66 | #define QMC5883_CRB_RANGE_BIT 5 67 | #define QMC5883_CRB_RANGE_LENGTH 2 68 | 69 | #define QMC5883_RANGE_2G 0x00, 70 | #define QMC5883_RANGE_8G 0x01 71 | 72 | // sample averaging 73 | #define HMC5883L_CRA_AVERAGE_BIT 6 74 | #define HMC5883L_CRA_AVERAGE_LENGTH 2 75 | 76 | #define HMC5883L_SAMPLES_8 0b11 77 | #define HMC5883L_SAMPLES_4 0b10 78 | #define HMC5883L_SAMPLES_2 0b01 79 | #define HMC5883L_SAMPLES_1 0b00 80 | 81 | #define QMC5883_CRA_AVERAGE_BIT 7 82 | #define QMC5883_CRA_AVERAGE_LENGTH 2 83 | 84 | #define QMC5883_SAMPLES_8 0b11 85 | #define QMC5883_SAMPLES_4 0b10 86 | #define QMC5883_SAMPLES_2 0b01 87 | #define QMC5883_SAMPLES_1 0b00 88 | 89 | // data rate 90 | #define HMC5883L_CRA_RATE_BIT 4 91 | #define HMC5883L_CRA_RATE_LENGTH 3 92 | 93 | #define HMC5883L_DATARATE_75HZ 0b110 94 | #define HMC5883L_DATARATE_30HZ 0b101 95 | #define HMC5883L_DATARATE_15HZ 0b100 96 | #define HMC5883L_DATARATE_7_5HZ 0b011 97 | #define HMC5883L_DATARATE_3HZ 0b010 98 | #define HMC5883L_DATARATE_1_5HZ 0b001 99 | #define HMC5883L_DATARATE_0_75_HZ 0b000 100 | 101 | #define QMC5883_CRA_RATE_BIT 3 102 | #define QMC5883_CRA_RATE_LENGTH 2 103 | 104 | #define QMC5883_DATARATE_10HZ 0b00 105 | #define QMC5883_DATARATE_50HZ 0b01 106 | #define QMC5883_DATARATE_100HZ 0b10 107 | #define QMC5883_DATARATE_200HZ 0b11 108 | 109 | // mode 110 | #define HMC5883L_MODEREG_BIT 1 111 | #define HMC5883L_MODEREG_LENGTH 2 112 | 113 | #define HMC5883L_MODE_IDLE 0b10 114 | #define HMC5883L_MODE_SINGLE 0b01 115 | #define HMC5883L_MODE_CONTINOUS 0b00 116 | 117 | #define QMC5883_MODEREG_BIT 1 118 | #define QMC5883_MODEREG_LENGTH 2 119 | 120 | #define QMC5883_MODE_STANDBY 0b00 121 | #define QMC5883_MODE_CONTINUOUS 0b01 122 | 123 | class Mag5883 124 | { 125 | public: 126 | Mag5883():isHMC_(false),isQMC_(false) 127 | {} 128 | bool initialize(void); 129 | 130 | bool testConnection(); 131 | 132 | uint8_t getMeasurementBias(); 133 | void setMeasurementBias(uint8_t bias); 134 | 135 | uint8_t getRange(); 136 | void setRange(uint8_t gain); 137 | 138 | uint8_t getSampleAveraging(); 139 | void setSampleAveraging(uint8_t averaging); 140 | 141 | uint8_t getDataRate(); 142 | void setDataRate(uint8_t rate); 143 | 144 | uint8_t getMode(); 145 | void setMode(uint8_t newMode); 146 | 147 | void getHeading(int16_t *x, int16_t *y, int16_t *z); 148 | 149 | int getICType(void); 150 | bool isHMC(){return isHMC_;} 151 | bool isQMC(){return isQMC_;} 152 | private: 153 | bool isHMC_; 154 | bool isQMC_; 155 | uint8_t mode; 156 | uint8_t buffer[6]; 157 | }; 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /libhedrot/libhedrot_RTmagCalibration.h: -------------------------------------------------------------------------------- 1 | // 2 | // libhedrot_RTmagCalibration.h 3 | // hedrot_receiver 4 | // 5 | // Created by Alexis Baskind on 06/05/17. 6 | // 7 | // Part of code is derived from Matthieu Aussal, CMAP - Ecole Polytechnique / CNRS 8 | // 9 | 10 | 11 | #ifndef __hedrot_receiver__libhedrot_RTmagCalibration__ 12 | #define __hedrot_receiver__libhedrot_RTmagCalibration__ 13 | 14 | #include 15 | #include 16 | #define _USE_MATH_DEFINES // for C+Windows 17 | #include 18 | #include "libhedrot_utils.h" 19 | #include "libhedrot_calibration.h" 20 | 21 | #define M_GOLDEN_RATIO 1.61803398874989484820 // (1+sqrt(5))/2 22 | #define M_INV_GOLDEN_RATIO 0.61803398874989484820 // 1/M_GOLDEN_RATIO = M_GOLDEN_RATIO - 1 23 | 24 | #define RT_CAL_NUMBER_OF_ZONES 100 // number of zones in the unit sphere (defined by Fibonaci mapping) 25 | #define RT_CAL_NUMBER_OF_POINTS_PER_ZONE 100 // number of points per zone 26 | 27 | #define MAX_CONDITION_NUMBER_REALTIME 100000 28 | 29 | #define TIME_CONSTANT_INDICATOR_OF_REJECTED_POINTS 1600 // in samples 30 | #define MAX_ALLOWED_PROPORTION_OF_REJECTED_POINTS .5 31 | 32 | #define MAX_ALLOWED_STANDARD_DEVIATION_ERROR .1 33 | 34 | #define UPPER_NORM_FOR_ABSURD_VALUES 1.5 // for method RTmagCalibrationUpdateIterative 35 | #define UPPER_NORM2_FOR_ABSURD_VALUES UPPER_NORM_FOR_ABSURD_VALUES*UPPER_NORM_FOR_ABSURD_VALUES // for method RTmagCalibrationUpdateIterative 36 | 37 | //===================================================================================================== 38 | // structure definition: RTmagZoneData (structure that stores information per zone) 39 | //===================================================================================================== 40 | typedef struct _RTmagZoneData { 41 | short points[RT_CAL_NUMBER_OF_POINTS_PER_ZONE][3]; 42 | double averagePoint[3]; 43 | short numberOfPoints; 44 | short indexOfCurrentPoint; 45 | } RTmagZoneData; 46 | 47 | //===================================================================================================== 48 | // structure definition: RTmagCalData (structure that stores RT calibration data) 49 | //===================================================================================================== 50 | typedef struct _RTmagCalData { 51 | // parameters 52 | short calibrationRateFactor; // calibration rate 53 | char calibrationValid; // 0 => step 1 ("brute force" method), 1=> step 2 (with Fibonacci mapping) 54 | float RTmagMaxDistanceError; 55 | 56 | // for step 1 (with raw samples) 57 | long maxNumberOfSamples; 58 | long sampleIndexStep1; // internal 59 | 60 | // for step 2 (with Fibonacci mapping) 61 | float Fibonacci_Points[RT_CAL_NUMBER_OF_ZONES][3]; 62 | RTmagZoneData *zoneData; 63 | float RTmagMinDistance2; //minimum squared distance error to accept or not a new point 64 | float RTmagMaxDistance2; //maximum squared distance error to accept or not a new point 65 | short numberOfFilledZones; 66 | 67 | // estimated values 68 | float estimatedOffset[3]; 69 | float estimatedScaling[3], estimatedScalingFactor[3]; 70 | 71 | // container for calibrating with ellipsoid fit and displaying purposes 72 | calibrationData* calData; 73 | 74 | // temporary container for storing data before filtering 75 | calibrationData* TMPcalData; 76 | 77 | // internal data 78 | short calibrationRateCounter; 79 | float proportionOfRejectedPoints_State; 80 | float proportionOfRejectedPoints_LPcoeff; // coefficient alpha of the low pass filter estimating the proportion of rejected points 81 | float previousEstimatedOffset[3], previousEstimatedScaling[3]; 82 | float previousConditionNumber; 83 | } RTmagCalData; 84 | 85 | //===================================================================================================== 86 | // functions 87 | //===================================================================================================== 88 | RTmagCalData* newRTmagCalData(); 89 | void freeRTmagCalData(RTmagCalData* data); 90 | void initRTmagCalData(RTmagCalData* data, float* initalEstimatedOffset, float* initalEstimatedScaling, float RTmagMaxDistanceError, short calibrationRateFactor, long maxNumberOfSamples); 91 | 92 | void RTmagCalibration_setCalibrationRateFactor(RTmagCalData* data, short calibrationRateFactor); 93 | 94 | void RTmagCalibration_setmaxNumberOfSamples(RTmagCalData* data, long maxNumberOfSamples); 95 | 96 | void RTmagCalibration_setRTmagMaxDistanceError(RTmagCalData* data, float RTmagMaxDistanceError); 97 | 98 | void computeFibonnaciMapping( RTmagCalData* data); 99 | short getClosestFibonacciPoint( RTmagCalData* data, double calPoint[3]); 100 | void addPoint2FibonnaciZone( RTmagCalData* data, short zoneNumber, short point[3]); 101 | 102 | short RTmagCalibrationUpdateDirect( RTmagCalData* data, short rawPoint[3]); 103 | short RTmagCalibrationUpdateIterative( RTmagCalData* data, short rawPoint[3]); 104 | 105 | #endif /* defined(__hedrot_receiver__libhedrot_RTmagCalibration__) */ 106 | -------------------------------------------------------------------------------- /matlab/calibration/ellipsoid_fit.m: -------------------------------------------------------------------------------- 1 | function [ center, radii, evecs, v ] = ellipsoid_fit( X, flag, equals ) 2 | % 3 | % Fit an ellispoid/sphere to a set of xyz data points: 4 | % 5 | % [center, radii, evecs, pars ] = ellipsoid_fit( X ) 6 | % [center, radii, evecs, pars ] = ellipsoid_fit( [x y z] ); 7 | % [center, radii, evecs, pars ] = ellipsoid_fit( X, 1 ); 8 | % [center, radii, evecs, pars ] = ellipsoid_fit( X, 2, 'xz' ); 9 | % [center, radii, evecs, pars ] = ellipsoid_fit( X, 3 ); 10 | % 11 | % Parameters: 12 | % * X, [x y z] - Cartesian data, n x 3 matrix or three n x 1 vectors 13 | % * flag - 0 fits an arbitrary ellipsoid (default), 14 | % - 1 fits an ellipsoid with its axes along [x y z] axes 15 | % - 2 followed by, say, 'xy' fits as 1 but also x_rad = y_rad 16 | % - 3 fits a sphere 17 | % 18 | % Output: 19 | % * center - ellispoid center coordinates [xc; yc; zc] 20 | % * ax - ellipsoid radii [a; b; c] 21 | % * evecs - ellipsoid radii directions as columns of the 3x3 matrix 22 | % * v - the 9 parameters describing the ellipsoid algebraically: 23 | % Ax^2 + By^2 + Cz^2 + 2Dxy + 2Exz + 2Fyz + 2Gx + 2Hy + 2Iz = 1 24 | % 25 | % Author: 26 | % Yury Petrov, Northeastern University, Boston, MA 27 | % 28 | 29 | error( nargchk( 1, 3, nargin ) ); % check input arguments 30 | if nargin == 1 31 | flag = 0; % default to a free ellipsoid 32 | end 33 | if flag == 2 && nargin == 2 34 | equals = 'xy'; 35 | end 36 | 37 | if size( X, 2 ) ~= 3 38 | error( 'Input data must have three columns!' ); 39 | else 40 | x = X( :, 1 ); 41 | y = X( :, 2 ); 42 | z = X( :, 3 ); 43 | end 44 | 45 | % need nine or more data points 46 | if length( x ) < 9 && flag == 0 47 | error( 'Must have at least 9 points to fit a unique ellipsoid' ); 48 | end 49 | if length( x ) < 6 && flag == 1 50 | error( 'Must have at least 6 points to fit a unique oriented ellipsoid' ); 51 | end 52 | if length( x ) < 5 && flag == 2 53 | error( 'Must have at least 5 points to fit a unique oriented ellipsoid with two axes equal' ); 54 | end 55 | if length( x ) < 3 && flag == 3 56 | error( 'Must have at least 4 points to fit a unique sphere' ); 57 | end 58 | 59 | if flag == 0 60 | % fit ellipsoid in the form Ax^2 + By^2 + Cz^2 + 2Dxy + 2Exz + 2Fyz + 2Gx + 2Hy + 2Iz = 1 61 | D = [ x .* x, ... 62 | y .* y, ... 63 | z .* z, ... 64 | 2 * x .* y, ... 65 | 2 * x .* z, ... 66 | 2 * y .* z, ... 67 | 2 * x, ... 68 | 2 * y, ... 69 | 2 * z ]; % ndatapoints x 9 ellipsoid parameters 70 | elseif flag == 1 71 | % fit ellipsoid in the form Ax^2 + By^2 + Cz^2 + 2Gx + 2Hy + 2Iz = 1 72 | D = [ x .* x, ... 73 | y .* y, ... 74 | z .* z, ... 75 | 2 * x, ... 76 | 2 * y, ... 77 | 2 * z ]; % ndatapoints x 6 ellipsoid parameters 78 | elseif flag == 2 79 | % fit ellipsoid in the form Ax^2 + By^2 + Cz^2 + 2Gx + 2Hy + 2Iz = 1, 80 | % where A = B or B = C or A = C 81 | if strcmp( equals, 'yz' ) || strcmp( equals, 'zy' ) 82 | D = [ y .* y + z .* z, ... 83 | x .* x, ... 84 | 2 * x, ... 85 | 2 * y, ... 86 | 2 * z ]; 87 | elseif strcmp( equals, 'xz' ) || strcmp( equals, 'zx' ) 88 | D = [ x .* x + z .* z, ... 89 | y .* y, ... 90 | 2 * x, ... 91 | 2 * y, ... 92 | 2 * z ]; 93 | else 94 | D = [ x .* x + y .* y, ... 95 | z .* z, ... 96 | 2 * x, ... 97 | 2 * y, ... 98 | 2 * z ]; 99 | end 100 | else 101 | % fit sphere in the form A(x^2 + y^2 + z^2) + 2Gx + 2Hy + 2Iz = 1 102 | D = [ x .* x + y .* y + z .* z, ... 103 | 2 * x, ... 104 | 2 * y, ... 105 | 2 * z ]; % ndatapoints x 4 sphere parameters 106 | end 107 | 108 | % solve the normal system of equations 109 | v = ( D' * D ) \ ( D' * ones( size( x, 1 ), 1 ) ); 110 | 111 | % find the ellipsoid parameters 112 | if flag == 0 113 | % form the algebraic form of the ellipsoid 114 | A = [ v(1) v(4) v(5) v(7); ... 115 | v(4) v(2) v(6) v(8); ... 116 | v(5) v(6) v(3) v(9); ... 117 | v(7) v(8) v(9) -1 ]; 118 | % find the center of the ellipsoid 119 | center = -A( 1:3, 1:3 ) \ [ v(7); v(8); v(9) ]; 120 | % form the corresponding translation matrix 121 | T = eye( 4 ); 122 | T( 4, 1:3 ) = center'; 123 | % translate to the center 124 | R = T * A * T'; 125 | % solve the eigenproblem 126 | [ evecs evals ] = eig( R( 1:3, 1:3 ) / -R( 4, 4 ) ); 127 | radii = sqrt( 1 ./ diag( evals ) ); 128 | else 129 | if flag == 1 130 | v = [ v(1) v(2) v(3) 0 0 0 v(4) v(5) v(6) ]; 131 | elseif flag == 2 132 | if strcmp( equals, 'xz' ) || strcmp( equals, 'zx' ) 133 | v = [ v(1) v(2) v(1) 0 0 0 v(3) v(4) v(5) ]; 134 | elseif strcmp( equals, 'yz' ) || strcmp( equals, 'zy' ) 135 | v = [ v(2) v(1) v(1) 0 0 0 v(3) v(4) v(5) ]; 136 | else % xy 137 | v = [ v(1) v(1) v(2) 0 0 0 v(3) v(4) v(5) ]; 138 | end 139 | else 140 | v = [ v(1) v(1) v(1) 0 0 0 v(2) v(3) v(4) ]; 141 | end 142 | center = ( -v( 7:9 ) ./ v( 1:3 ) )'; 143 | gam = 1 + ( v(7)^2 / v(1) + v(8)^2 / v(2) + v(9)^2 / v(3) ); 144 | radii = ( sqrt( gam ./ v( 1:3 ) ) )'; 145 | evecs = eye( 3 ); 146 | end 147 | 148 | 149 | -------------------------------------------------------------------------------- /scripts/Win/makeDistribution.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo This script builds a 64 bit windows distribution of hedrot (including however the 32 bit version of the max object). 3 | echo Before running this script, be sure that: 4 | echo 1/ all binaries have been compiled 5 | echo 2/ a pdf version of the doc has been created 6 | echo 3/ the Max standalone hedrotReceiver has been built. 7 | 8 | set today=%date:~-2%-%date:~3,2%-%date:~0,2% 9 | 10 | set thisDirectory=%cd% 11 | set "rootDirectory=%thisDirectory%\..\.." 12 | set "destDirectory=%rootDirectory%\build\forPackaging" 13 | 14 | set "testfile=%rootDirectory%\libhedrot\libhedrot.h" 15 | awk "/\#define HEDROT_VERSION / { print $3 }" %testfile% > tmp.txt 16 | sed -i 's/"//g' tmp.txt 17 | set /p hedrotVersion= tmp.txt 24 | sed -i 's/"//g' tmp.txt 25 | set /p hedrotFirmwareVersion= nul 43 | 44 | REM ######### copy the command-line-demo ############################# 45 | md "%packageFolder%\command-line-demo" 46 | copy "%rootDirectory%\command-line-demo\visual studio\exe\Release_x64\hedrotReceiverDemo.exe" "%packageFolder%\command-line-demo\" > nul 47 | 48 | REM ######### copy the firmware (both versions) ############################# 49 | md "%packageFolder%\firmware" 50 | copy "%rootDirectory%\firmware\hex\hedrot-firmware-teensy31-32.ino.hex" "%packageFolder%\firmware\hedrot-firmware-teensy31-32_version_%hedrotFirmwareVersion%.hex" > nul 51 | copy "%rootDirectory%\firmware\hex\hedrot-firmware-teensyLC.ino.hex" "%packageFolder%\firmware\hedrot-firmware-teensyLC_version_%hedrotFirmwareVersion%.hex" > nul 52 | copy "%rootDirectory%\firmware\CHANGELOG.txt" "%packageFolder%\firmware\" > nul 53 | 54 | REM ######### copy the max source code and external ############################# 55 | md "%packageFolder%\Max" 56 | copy "%rootDirectory%\hedrotReceiver\hedrotReceiver.json" "%packageFolder%\Max\" > nul 57 | copy "%rootDirectory%\hedrotReceiver\patches\*.maxpat" "%packageFolder%\Max\" > nul 58 | copy "%rootDirectory%\hedrotReceiver\hedrot_receiver.mxe" "%packageFolder%\Max\" > nul 59 | copy "%rootDirectory%\hedrotReceiver\hedrot_receiver.mxe64" "%packageFolder%\Max\" > nul 60 | 61 | REM ######### copy the examples folder ############################# 62 | md "%packageFolder%\examples" 63 | xcopy "%rootDirectory%\examples" "%packageFolder%\examples" /Y /Q /i /s 64 | 65 | REM ######### copy the dll folder ############################# 66 | md "%packageFolder%\dll" 67 | xcopy "%rootDirectory%\dll" "%packageFolder%\dll" /Y /Q /i /s 68 | 69 | REM ######### copy the doc ############################# 70 | copy "%rootDirectory%\doc\hedrot user manual.pdf" "%packageFolder%" > nul 71 | 72 | REM ######### copy the license file ############################# 73 | copy "%rootDirectory%\LICENSE" "%packageFolder%" > nul 74 | 75 | REM ######### copy the CHANGELOG.txt file ############################# 76 | copy "%rootDirectory%\CHANGELOG.txt" "%packageFolder%" > nul 77 | 78 | REM ######### copy and update the main README.txt file ############################# 79 | copy "%rootDirectory%\scripts\README-DISTRIBUTION.txt" "%packageFolder%\README.txt" > nul 80 | sed -i "s/Hedrot Version: XXXX/Hedrot Version: %hedrotVersion%/g;" %packageFolder%\README.txt 81 | sed -i "s/Firmware Version: YYYY/Firmware Version: %hedrotFirmwareVersion%/g;" %packageFolder%\README.txt 82 | 83 | REM ######### change the icon of the standalone folder and of the standalone ############################# 84 | C:\Users\Baskind\Desktop\Developpement\utils\rcedit "%packageFolder%\hedrotReceiver\hedrotReceiver.exe" --set-icon %thisDirectory%\..\logo\hedrot.ico 85 | cd %packageFolder% 86 | echo [.ShellClassInfo] >> hedrotReceiver\desktop.ini 87 | echo IconResource=%thisDirectory%\..\logo\hedrot.ico >> hedrotReceiver\desktop.ini 88 | echo [ViewState] >> hedrotReceiver\desktop.ini 89 | echo Mode= >> hedrotReceiver\desktop.ini 90 | echo Vid= >> hedrotReceiver\desktop.ini 91 | echo FolderType=Documents >> hedrotReceiver\desktop.ini 92 | attrib -A +S +H hedrotReceiver\desktop.ini 93 | attrib +R hedrotReceiver 94 | 95 | REM ######### ZIP ############################# 96 | 97 | REM #erase the ZIP if it exists 98 | del "%rootDirectory%\build\%packageName%.zip" 99 | 100 | REM #create the ZIP 101 | cd "%destDirectory%\tmpPackageFolder\%packageName%" 102 | 7z a -r -tzip "%rootDirectory%\build\%packageName%.zip" * > nul 103 | 104 | REM #erase temp build directory 105 | cd %destDirectory% 106 | rmdir /s /q "%destDirectory%\tmpPackageFolder" 107 | 108 | cd %thisDirectory% -------------------------------------------------------------------------------- /firmware/hedrot-firmware/ITG3200.h: -------------------------------------------------------------------------------- 1 | // ITG3200.cpp: ITG3200 I2C device methods 2 | // based on I2Cdev library collection - ITG3200 I2C device class 3 | // adapted for i2c_t3 through the custom code I2Ccom.cpp 4 | 5 | 6 | #ifndef _ITG3200_H_ 7 | #define _ITG3200_H_ 8 | 9 | #include "I2Ccom.h" 10 | 11 | #define ITG3200_ADDRESS_AD0_LOW 0x68 // address pin low (GND), default for SparkFun IMU Digital Combo board 12 | #define ITG3200_ADDRESS_AD0_HIGH 0x69 // address pin high (VCC), default for SparkFun ITG-3200 Breakout board 13 | #define ITG3200_DEFAULT_ADDRESS ITG3200_ADDRESS_AD0_LOW 14 | 15 | #define ITG3200_RA_WHO_AM_I 0x00 16 | #define ITG3200_RA_SMPLRT_DIV 0x15 17 | #define ITG3200_RA_DLPF_FS 0x16 18 | #define ITG3200_RA_INT_CFG 0x17 19 | #define ITG3200_RA_INT_STATUS 0x1A 20 | #define ITG3200_RA_TEMP_OUT_H 0x1B 21 | #define ITG3200_RA_TEMP_OUT_L 0x1C 22 | #define ITG3200_RA_GYRO_XOUT_H 0x1D 23 | #define ITG3200_RA_GYRO_XOUT_L 0x1E 24 | #define ITG3200_RA_GYRO_YOUT_H 0x1F 25 | #define ITG3200_RA_GYRO_YOUT_L 0x20 26 | #define ITG3200_RA_GYRO_ZOUT_H 0x21 27 | #define ITG3200_RA_GYRO_ZOUT_L 0x22 28 | #define ITG3200_RA_PWR_MGM 0x3E 29 | 30 | #define ITG3200_DEVID_BIT 6 31 | #define ITG3200_DEVID_LENGTH 6 32 | 33 | #define ITG3200_DF_FS_SEL_BIT 4 34 | #define ITG3200_DF_FS_SEL_LENGTH 2 35 | #define ITG3200_DF_DLPF_CFG_BIT 2 36 | #define ITG3200_DF_DLPF_CFG_LENGTH 3 37 | 38 | #define ITG3200_FULLSCALE_2000 0x03 39 | 40 | #define ITG3200_DLPF_BW_256 0x00 41 | #define ITG3200_DLPF_BW_188 0x01 42 | #define ITG3200_DLPF_BW_98 0x02 43 | #define ITG3200_DLPF_BW_42 0x03 44 | #define ITG3200_DLPF_BW_20 0x04 45 | #define ITG3200_DLPF_BW_10 0x05 46 | #define ITG3200_DLPF_BW_5 0x06 47 | 48 | #define ITG3200_INTCFG_ACTL_BIT 7 49 | #define ITG3200_INTCFG_OPEN_BIT 6 50 | #define ITG3200_INTCFG_LATCH_INT_EN_BIT 5 51 | #define ITG3200_INTCFG_INT_ANYRD_2CLEAR_BIT 4 52 | #define ITG3200_INTCFG_ITG_RDY_EN_BIT 2 53 | #define ITG3200_INTCFG_RAW_RDY_EN_BIT 0 54 | 55 | #define ITG3200_INTMODE_ACTIVEHIGH 0x00 56 | #define ITG3200_INTMODE_ACTIVELOW 0x01 57 | 58 | #define ITG3200_INTDRV_PUSHPULL 0x00 59 | #define ITG3200_INTDRV_OPENDRAIN 0x01 60 | 61 | #define ITG3200_INTLATCH_50USPULSE 0x00 62 | #define ITG3200_INTLATCH_WAITCLEAR 0x01 63 | 64 | #define ITG3200_INTCLEAR_STATUSREAD 0x00 65 | #define ITG3200_INTCLEAR_ANYREAD 0x01 66 | 67 | #define ITG3200_INTSTAT_ITG_RDY_BIT 2 68 | #define ITG3200_INTSTAT_RAW_DATA_READY_BIT 0 69 | 70 | #define ITG3200_PWR_H_RESET_BIT 7 71 | #define ITG3200_PWR_SLEEP_BIT 6 72 | #define ITG3200_PWR_STBY_XG_BIT 5 73 | #define ITG3200_PWR_STBY_YG_BIT 4 74 | #define ITG3200_PWR_STBY_ZG_BIT 3 75 | #define ITG3200_PWR_CLK_SEL_BIT 2 76 | #define ITG3200_PWR_CLK_SEL_LENGTH 3 77 | 78 | #define ITG3200_CLOCK_INTERNAL 0x00 79 | #define ITG3200_CLOCK_PLL_XGYRO 0x01 80 | #define ITG3200_CLOCK_PLL_YGYRO 0x02 81 | #define ITG3200_CLOCK_PLL_ZGYRO 0x03 82 | #define ITG3200_CLOCK_PLL_EXT32K 0x04 83 | #define ITG3200_CLOCK_PLL_EXT19M 0x05 84 | 85 | class ITG3200 { 86 | public: 87 | ITG3200(); 88 | ITG3200(uint8_t address); 89 | 90 | void initialize(); 91 | bool testConnection(); 92 | 93 | // WHO_AM_I register 94 | uint8_t getDeviceID(); 95 | void setDeviceID(uint8_t id); 96 | 97 | // SMPLRT_DIV register 98 | uint8_t getRate(); 99 | void setRate(uint8_t rate); 100 | 101 | // DLPF_FS register 102 | uint8_t getFullScaleRange(); 103 | void setFullScaleRange(uint8_t range); 104 | uint8_t getDLPFBandwidth(); 105 | void setDLPFBandwidth(uint8_t bandwidth); 106 | 107 | // INT_CFG register 108 | bool getInterruptMode(); 109 | void setInterruptMode(bool mode); 110 | bool getInterruptDrive(); 111 | void setInterruptDrive(bool drive); 112 | bool getInterruptLatch(); 113 | void setInterruptLatch(bool latch); 114 | bool getInterruptLatchClear(); 115 | void setInterruptLatchClear(bool clear); 116 | bool getIntDeviceReadyEnabled(); 117 | void setIntDeviceReadyEnabled(bool enabled); 118 | bool getIntDataReadyEnabled(); 119 | void setIntDataReadyEnabled(bool enabled); 120 | 121 | // INT_STATUS register 122 | bool getIntDeviceReadyStatus(); 123 | bool getIntDataReadyStatus(); 124 | 125 | // TEMP_OUT_* registers 126 | int16_t getTemperature(); 127 | 128 | // GYRO_*OUT_* registers 129 | void getRotation(int16_t* x, int16_t* y, int16_t* z); 130 | int16_t getRotationX(); 131 | int16_t getRotationY(); 132 | int16_t getRotationZ(); 133 | 134 | // PWR_MGM register 135 | void reset(); 136 | bool getSleepEnabled(); 137 | void setSleepEnabled(bool enabled); 138 | bool getStandbyXEnabled(); 139 | void setStandbyXEnabled(bool enabled); 140 | bool getStandbyYEnabled(); 141 | void setStandbyYEnabled(bool enabled); 142 | bool getStandbyZEnabled(); 143 | void setStandbyZEnabled(bool enabled); 144 | uint8_t getClockSource(); 145 | void setClockSource(uint8_t source); 146 | 147 | private: 148 | uint8_t devAddr; 149 | uint8_t buffer[6]; 150 | }; 151 | 152 | #endif /* _ITG3200_H_ */ 153 | -------------------------------------------------------------------------------- /command-line-demo/source/hedrotReceiverDemo.c: -------------------------------------------------------------------------------- 1 | // 2 | // hedrotReceiverDemo_cmd.c 3 | // 4 | // Created by Alexis Baskind on 16/10/16. 5 | // Copyright (c) 2016 Alexis Baskind. All rights reserved. 6 | // 7 | 8 | #include 9 | 10 | #include "libhedrot.h" 11 | #include "hedrot_comm_protocol.h" 12 | 13 | // time constants 14 | #define TICK_PERIOD .1 // time period in seconds between two ticks 15 | 16 | //===================================================================================================== 17 | // definitions and includes for clocking 18 | //===================================================================================================== 19 | #ifdef __MACH__ // if mach (mac os X) 20 | #include 21 | #include 22 | double getTime() { 23 | clock_serv_t cclock; 24 | mach_timespec_t mts; 25 | host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); 26 | clock_get_time(cclock, &mts); 27 | mach_port_deallocate(mach_task_self(), cclock); 28 | return mts.tv_sec + mts.tv_nsec*1e-9; 29 | } 30 | #else 31 | #if defined(_WIN32) || defined(_WIN64) 32 | #include 33 | double getTime() { 34 | LARGE_INTEGER frequency; 35 | LARGE_INTEGER time; 36 | QueryPerformanceFrequency(&frequency); 37 | QueryPerformanceCounter(&time); 38 | return time.QuadPart / (double)frequency.QuadPart; 39 | } 40 | #endif /* #if defined(_WIN32) || defined(_WIN64) */ 41 | #endif /* #ifdef __MACH__ */ 42 | 43 | 44 | int main(int argc, const char * argv[]) { 45 | double currentTime1, currentTime2, previousTime; 46 | char messageNumber; 47 | int i; 48 | 49 | headtrackerData* trackingData; 50 | 51 | printf("Hedrot command-line demo, based on hedrot version %s, compiled on "__DATE__"\r\n", HEDROT_VERSION); 52 | printf("Required firmware version %d\r\n", HEDROT_FIRMWARE_VERSION); 53 | 54 | trackingData = headtracker_new(); 55 | 56 | // change baudrate (for some reason the command-line version does not accept higher baud rates than 57600) 57 | trackingData->serialcomm->baud = 57600; 58 | 59 | // set verbose to 1 60 | setVerbose(trackingData,1); 61 | 62 | // set autodiscover to 1 63 | setAutoDiscover(trackingData,1); 64 | 65 | // switch on the headtracker 66 | setHeadtrackerOn(trackingData,1); 67 | //headtracker_open(trackingData,1); // if autodiscover = 0 68 | 69 | previousTime = getTime(); 70 | 71 | while(1) { //infinite loop 72 | currentTime1 = getTime(); 73 | 74 | // next tick 75 | headtracker_tick(trackingData); 76 | 77 | // process messages to notify 78 | while( (messageNumber = pullNotificationMessage(trackingData)) ) { 79 | switch( messageNumber ) { 80 | case NOTIFICATION_MESSAGE_COMM_PORT_LIST_UPDATED: 81 | printf("port list updated, %d ports found\r\n", trackingData->serialcomm->numberOfAvailablePorts); 82 | for(i = 0;iserialcomm->numberOfAvailablePorts; i++) { 83 | printf("\t port %d: %s \r\n", i, trackingData->serialcomm->availablePorts[i]); 84 | } 85 | break; 86 | case NOTIFICATION_MESSAGE_PORT_OPENED: 87 | printf("port %s opened\r\n", trackingData->serialcomm->availablePorts[trackingData->serialcomm->portNumber]); 88 | break; 89 | case NOTIFICATION_MESSAGE_WRONG_FIRMWARE_VERSION: 90 | printf("Wrong Headtracker Firmware Version - expected version: %i - actual version: %i\r\n",HEDROT_FIRMWARE_VERSION,trackingData->firmwareVersion); 91 | break; 92 | case NOTIFICATION_MESSAGE_HEADTRACKER_STATUS_CHANGED: 93 | printf("new reception status: %d\r\n",trackingData->infoReceptionStatus); 94 | break; 95 | case NOTIFICATION_MESSAGE_SETTINGS_DATA_READY: 96 | printf("headtracking settings received\r\n"); 97 | break; 98 | case NOTIFICATION_MESSAGE_CALIBRATION_NOT_VALID: 99 | printf("calibration not valid\r\n"); 100 | break; 101 | case NOTIFICATION_MESSAGE_GYRO_CALIBRATION_STARTED: 102 | printf("gyroscope calibration started\r\n"); 103 | break; 104 | case NOTIFICATION_MESSAGE_GYRO_CALIBRATION_FINISHED: 105 | printf("gyroscope calibration finished\r\n"); 106 | break; 107 | case NOTIFICATION_MESSAGE_BOARD_OVERLOAD: 108 | printf("board too slow, reduce samplerate\r\n"); 109 | break; 110 | } 111 | } 112 | currentTime2 = getTime(); 113 | 114 | 115 | // print estimated quaternion and angles if transmitting 116 | if(trackingData->infoReceptionStatus == COMMUNICATION_STATE_HEADTRACKER_TRANSMITTING) { 117 | printf("estimated quaternion: %f %f %f %f\r\n", trackingData->qcent1, trackingData->qcent2, trackingData->qcent3, trackingData->qcent4); 118 | printf("estimated angles: yaw %f - pitch %f - roll %f\r\n", trackingData->yaw, trackingData->pitch, trackingData->roll); 119 | printf("Time elapsed since last tick = %f sec\r\n", currentTime2 - previousTime); 120 | } 121 | 122 | previousTime = currentTime2; 123 | 124 | // sleep so that the next tick starts TICK_PERIOD later 125 | #if defined(_WIN32) || defined(_WIN64) 126 | Sleep((DWORD) (TICK_PERIOD*1000)); 127 | #else /* #if defined(_WIN32) || defined(_WIN64) */ 128 | usleep((int) ((TICK_PERIOD + currentTime2 - currentTime1) * 1000000)); 129 | #endif /* #if defined(_WIN32) || defined(_WIN64) */ 130 | } 131 | 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /libhedrot/libhedrot_utils.c: -------------------------------------------------------------------------------- 1 | // 2 | // libhedrot_utils.c 3 | // hedrot_receiver 4 | // 5 | // Created by Alexis Baskind on 17/04/17. 6 | // 7 | // 8 | 9 | #include 10 | #include 11 | #if defined(_WIN32) || defined(_WIN64) 12 | #include 13 | #endif 14 | #include "libhedrot_utils.h" 15 | 16 | 17 | 18 | //===================================================================================================== 19 | // utils 20 | //===================================================================================================== 21 | 22 | // double floating point modulo 23 | double mod(double a, double N) {return a - N*floor(a/N);} //return in range [0, N] 24 | 25 | // round (not defined in VS2012) 26 | #if defined(_WIN32) || defined(_WIN64) 27 | double round(double value) { 28 | return value < 0 ? -floor(0.5 - value) : floor(0.5 + value); 29 | } 30 | #endif /* #if defined(_WIN32) || defined(_WIN64) */ 31 | 32 | 33 | 34 | //--------------------------------------------------------------------------------------------------- 35 | // Fast inverse square-root 36 | 37 | // single precision version 38 | // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root 39 | float invSqrt(float x) { 40 | float halfx = 0.5f * x; 41 | float y = x; 42 | int32_t i = *(int32_t*)&y; 43 | i = 0x5f3759df - (i>>1); 44 | y = *(float*)&i; 45 | y = y * (1.5f - (halfx * y * y)); 46 | return y; 47 | } 48 | 49 | 50 | /* double precision version 51 | // See: https://tbach.web.cern.ch/tbach/thesis/literature/fastinvsquare_robertson.pdf 52 | double invSqrt(double x) { 53 | uint64_t i; 54 | double x2, y; 55 | x2 = x * 0.5; 56 | y = x; 57 | i = *(uint64_t *) &y; 58 | i = 0x5fe6eb50c7b537a9 - (i >> 1); 59 | y = *(double *) &i; 60 | y = y * (1.5 - (x2 * y * y)); 61 | return y; 62 | } 63 | */ 64 | 65 | /* 66 | // not optimized (but more precise) version 67 | double invSqrt(double x) { 68 | if(x==0) return 1e40; // arbitrary very big number 69 | else return 1./sqrt(x); 70 | }*/ 71 | 72 | void quaternion2YawPitchRoll(float q1, float q2, float q3, float q4, float *yaw, float *pitch, float *roll) { 73 | // zyx Talt-Bryan rotation sequence 74 | 75 | *yaw = (float) (RAD_TO_DEGREE * atan2(2.0f * (q1*q4 + q2*q3), 76 | 1.0f - 2.0f * (q3*q3 + q4*q4) )); 77 | 78 | *pitch = (float) (RAD_TO_DEGREE * asin(min(max(2.0f * (q1*q3 - q4*q2),-1),1))); 79 | 80 | 81 | *roll= (float) (RAD_TO_DEGREE * atan2(2.0f * (q1*q2 + q3*q4), 82 | 1.0f - 2.0f * (q2*q2 + q3*q3))); 83 | } 84 | 85 | void quaternion2RollPitchYaw(float q1, float q2, float q3, float q4, float *yaw, float *pitch, float *roll) { 86 | // xyz Talt-Bryan rotation sequence 87 | 88 | *roll = (float) (RAD_TO_DEGREE * atan2(2.0f * (q1*q2 - q3*q4), 89 | 1.0f - 2.0f * (q2*q2 + q3*q3) )); 90 | 91 | *pitch = (float) (RAD_TO_DEGREE * asin(min(max(2.0f * (q1*q3 + q4*q2),-1),1))); 92 | 93 | 94 | *yaw= (float) (RAD_TO_DEGREE * atan2(2.0f * (q1*q4 - q2*q3), 95 | 1.0f - 2.0f * (q3*q3 + q4*q4))); 96 | } 97 | 98 | void quaternionComposition(float q01, float q02, float q03, float q04, float q11, float q12, float q13, float q14, float *q21, float *q22, float *q23, float *q24) { 99 | // compose two quaternions (Hamilton product) 100 | // the quaternion (q11, q12, q13, q14) is rotated according to the reference quaternion (q01, q02, q03, q04) 101 | *q21 = q01 * q11 - q02 * q12 - q03 * q13 - q04 * q14; 102 | *q22 = q01 * q12 + q02 * q11 + q03 * q14 - q04 * q13; 103 | *q23 = q01 * q13 - q02 * q14 + q03 * q11 + q04 * q12; 104 | *q24 = q01 * q14 + q02 * q13 - q03 * q12 + q04 * q11; 105 | } 106 | 107 | int stringToFloats(char* valueBuffer, float* data, int nvalues) { 108 | int i=0; 109 | 110 | char *delim = " "; // input separated by spaces 111 | char *token = NULL; 112 | char *brkt; 113 | 114 | for (token = strtok_r(valueBuffer, delim, &brkt); token != NULL; token = strtok_r(NULL, delim, &brkt)) 115 | { 116 | char *unconverted; 117 | data[i] = (float) strtod(token, &unconverted); 118 | i++; 119 | } 120 | 121 | if(i 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {F51F214F-1832-4CF4-ACC5-1A6AB701C4CC} 23 | Win32Proj 24 | hedrotReceiverDemo 25 | 26 | 27 | 28 | Application 29 | true 30 | v110 31 | MultiByte 32 | 33 | 34 | Application 35 | true 36 | v110 37 | MultiByte 38 | 39 | 40 | Application 41 | false 42 | v110 43 | true 44 | MultiByte 45 | 46 | 47 | Application 48 | false 49 | v110 50 | true 51 | MultiByte 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | true 72 | build\$(Configuration)_$(PlatformName)\ 73 | exe\$(Configuration)_$(PlatformName)\ 74 | 75 | 76 | true 77 | true 78 | build\$(Configuration)_$(PlatformName)\ 79 | exe\$(Configuration)_$(PlatformName)\ 80 | 81 | 82 | false 83 | build\$(Configuration)_$(PlatformName)\ 84 | exe\$(Configuration)_$(PlatformName)\ 85 | 86 | 87 | false 88 | build\$(Configuration)_$(PlatformName)\ 89 | exe\$(Configuration)_$(PlatformName)\ 90 | 91 | 92 | 93 | NotUsing 94 | Level3 95 | Disabled 96 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 97 | true 98 | ..\..\firmware\hedrot-firmware;..\..\libhedrot;%(AdditionalIncludeDirectories) 99 | 100 | 101 | Console 102 | true 103 | 104 | 105 | 106 | 107 | NotUsing 108 | Level3 109 | Disabled 110 | ADD_;HAVE_LAPACK_CONFIG_H;LAPACK_COMPLEX_STRUCTURE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 111 | true 112 | ..\..\firmware\hedrot-firmware;..\..\libhedrot;C:\Users\Baskind\Desktop\Developpement\libraries\lapack-3.7.0-lib\include;%(AdditionalIncludeDirectories) 113 | 114 | 115 | Console 116 | true 117 | C:\Users\Baskind\Desktop\Developpement\libraries\lapack-3.7.0-lib\lib 118 | libblas.dll.a;liblapack.dll.a;liblapacke.dll.a;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 119 | 120 | 121 | 122 | 123 | Level3 124 | 125 | 126 | MaxSpeed 127 | true 128 | true 129 | ADD_;HAVE_LAPACK_CONFIG_H;LAPACK_COMPLEX_STRUCTURE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 130 | true 131 | C:\Users\Baskind\Desktop\Developpement\libraries\lapack-3.7.0-lib\include;..\..\firmware\hedrot-firmware;..\..\libhedrot;%(AdditionalIncludeDirectories) 132 | 133 | 134 | Console 135 | true 136 | true 137 | true 138 | libblas.lib;liblapack.lib;liblapacke.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 139 | C:\Users\Baskind\Desktop\Developpement\libraries\lapack for windows\dll\win32 140 | 141 | 142 | 143 | 144 | Level3 145 | 146 | 147 | MaxSpeed 148 | true 149 | true 150 | ADD_;HAVE_LAPACK_CONFIG_H;LAPACK_COMPLEX_STRUCTURE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 151 | true 152 | ..\..\firmware\hedrot-firmware;..\..\libhedrot;C:\Users\Baskind\Desktop\Developpement\libraries\lapack-3.7.0-lib\include;%(AdditionalIncludeDirectories) 153 | ProgramDatabase 154 | 155 | 156 | Console 157 | true 158 | true 159 | true 160 | libblas.dll.a;liblapack.dll.a;liblapacke.dll.a;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 161 | C:\Users\Baskind\Desktop\Developpement\libraries\lapack-3.7.0-lib\lib 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /firmware/hedrot-firmware/Mag5883.cpp: -------------------------------------------------------------------------------- 1 | // Mag5883.cpp: Mag5883 I2C device methods for both Magnetometers used in gy-85 boards: 2 | // . Honeywell HMC5883L 3 | // . QMC5883L 4 | // part of code derived from [DFRobot](http://www.dfrobot.com), 2017 5 | // part of code derived from I2Cdev library 6 | 7 | #include "Mag5883.h" 8 | 9 | bool Mag5883::initialize() 10 | { 11 | int retry; 12 | retry = 5; 13 | 14 | while(retry--){ 15 | Wire.beginTransmission(HMC5883L_ADDRESS); 16 | isHMC_ = (0 == Wire.endTransmission()); 17 | if(isHMC_){ 18 | break; 19 | } 20 | delay(20); 21 | } 22 | //Serial.print("isHMC_= "); 23 | //Serial.println(isHMC_); 24 | 25 | if(isHMC_){ 26 | if ((readByte(HMC5883L_ADDRESS, HMC5883L_REG_IDENT_A) != 0x48) 27 | || (readByte(HMC5883L_ADDRESS, HMC5883L_REG_IDENT_B) != 0x34) 28 | || (readByte(HMC5883L_ADDRESS, HMC5883L_REG_IDENT_C) != 0x33)){ 29 | return false; 30 | } 31 | 32 | setMeasurementBias(HMC5883L_BIAS_NORMAL); 33 | setRange(HMC5883L_RANGE_0_88G); 34 | setMode(HMC5883L_MODE_SINGLE); 35 | setDataRate(HMC5883L_DATARATE_75HZ); 36 | setSampleAveraging(HMC5883L_SAMPLES_1); 37 | 38 | return true; 39 | }else{ 40 | retry = 5; 41 | while(retry--){ 42 | Wire.begin(); 43 | Wire.beginTransmission(QMC5883_ADDRESS); 44 | isQMC_ = (0 == Wire.endTransmission()); 45 | if(isHMC_){ 46 | break; 47 | } 48 | delay(20); 49 | } 50 | //Serial.print("isQMC_= "); 51 | //Serial.println(isQMC_); 52 | if(isQMC_){ 53 | writeByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_B, 0X01); 54 | writeByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_C, 0X40); 55 | writeByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_D, 0X01); 56 | writeByte(QMC5883_ADDRESS, QMC5883_REG_CONFIG_1, 0X1D); 57 | 58 | if ((readByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_B) != 0x01) 59 | || (readByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_C) != 0x40) 60 | || (readByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_D) != 0x01)){ 61 | return false; 62 | } 63 | setRange(QMC5883_RANGE_8G); 64 | setMode(QMC5883_MODE_CONTINUOUS); 65 | setDataRate(QMC5883_DATARATE_200HZ); 66 | setSampleAveraging(QMC5883_SAMPLES_1); 67 | 68 | return true; 69 | } 70 | } 71 | return false; 72 | } 73 | 74 | /** Verify the I2C connection. 75 | * Make sure the device is connected and responds as expected. 76 | * @return True if connection is valid, false otherwise 77 | */ 78 | bool Mag5883::testConnection() { 79 | if(isHMC_){ 80 | return ((readByte(HMC5883L_ADDRESS, HMC5883L_REG_IDENT_A) == 0x48) 81 | && (readByte(HMC5883L_ADDRESS, HMC5883L_REG_IDENT_B) == 0x34) 82 | && (readByte(HMC5883L_ADDRESS, HMC5883L_REG_IDENT_C) == 0x33)); 83 | } else { 84 | return ((readByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_B) == 0x01) 85 | && (readByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_C) == 0x40) 86 | && (readByte(QMC5883_ADDRESS, QMC5883_REG_IDENT_D) == 0x01)); 87 | } 88 | } 89 | 90 | /** Get measurement bias value. 91 | * This function has no effect sif QMC5883 92 | @return if HMC5883L: Current bias value (0-2 for normal/positive/negative respectively). If QMC5883 (0) 93 | */ 94 | uint8_t Mag5883::getMeasurementBias() { 95 | if(isHMC_){ 96 | return readBits(HMC5883L_ADDRESS, HMC5883L_REG_CONFIG_A, HMC5883L_CRA_BIAS_BIT, HMC5883L_CRA_BIAS_LENGTH); 97 | } else { 98 | return 0; // no effect 99 | } 100 | } 101 | 102 | /** Set measurement bias value. 103 | * This function has no effect if QMC5883 104 | @@param bias if HMC5883L: New bias value (0-2 for normal/positive/negative respectively) 105 | */ 106 | void Mag5883::setMeasurementBias(uint8_t bias) { 107 | if(isHMC_){ 108 | writeBits(HMC5883L_ADDRESS, HMC5883L_REG_CONFIG_A, HMC5883L_CRA_BIAS_BIT, HMC5883L_CRA_BIAS_LENGTH, bias); 109 | } else { 110 | //do nothing 111 | } 112 | } 113 | 114 | /** Get number of samples averaged per measurement. 115 | * @return Current samples averaged per measurement (0-3 for 1/2/4/8 respectively) 116 | */ 117 | uint8_t Mag5883::getSampleAveraging() { 118 | if(isHMC_){ 119 | return readBits(HMC5883L_ADDRESS, HMC5883L_REG_CONFIG_A, HMC5883L_CRA_AVERAGE_BIT, HMC5883L_CRA_AVERAGE_LENGTH); 120 | } else { 121 | return readBits(QMC5883_ADDRESS, QMC5883_REG_CONFIG_1, QMC5883_CRA_AVERAGE_BIT, QMC5883_CRA_AVERAGE_LENGTH); 122 | } 123 | } 124 | /** Set number of samples averaged per measurement. 125 | * @param averaging New samples averaged per measurement setting(0-3 for 1/2/4/8 respectively) 126 | */ 127 | void Mag5883::setSampleAveraging(uint8_t averaging) { 128 | if(isHMC_){ 129 | writeBits(HMC5883L_ADDRESS, HMC5883L_REG_CONFIG_A, HMC5883L_CRA_AVERAGE_BIT, HMC5883L_CRA_AVERAGE_LENGTH, averaging); 130 | } else { 131 | writeBits(QMC5883_ADDRESS, QMC5883_REG_CONFIG_1, QMC5883_CRA_AVERAGE_BIT, QMC5883_CRA_AVERAGE_LENGTH, averaging); 132 | } 133 | } 134 | 135 | /** get magnetic field gain value 136 | ***** FOR HMC5883L ******* 137 | * The table below shows nominal gain settings. Use the "Gain" column to convert 138 | * counts to Gauss. Choose a lower gain value (higher GN#) when total field 139 | * strength causes overflow in one of the data output registers (saturation). 140 | * The data output range for all settings is 0xF800-0x07FF (-2048 - 2047). 141 | * 142 | * Value | Field Range | Gain (LSB/Gauss) 143 | * ------+-------------+----------------- 144 | * 0 | +/- 0.88 Ga | 1370 145 | * 1 | +/- 1.3 Ga | 1090 (Default) 146 | * 2 | +/- 1.9 Ga | 820 147 | * 3 | +/- 2.5 Ga | 660 148 | * 4 | +/- 4.0 Ga | 440 149 | * 5 | +/- 4.7 Ga | 390 150 | * 6 | +/- 5.6 Ga | 330 151 | * 7 | +/- 8.1 Ga | 230 152 | * 153 | ***** FOR QMC5883 ******* 154 | * 155 | * Value | Recommended Range 156 | * ------+------------ 157 | * 0 | +/- 2 G 158 | * 1 | +/- 8 G 159 | * 160 | * @return Current magnetic field gain value 161 | */ 162 | uint8_t Mag5883::getRange() { 163 | if(isHMC_){ 164 | return readBits(HMC5883L_ADDRESS, HMC5883L_REG_CONFIG_B, HMC5883L_CRB_RANGE_BIT, HMC5883L_CRB_RANGE_LENGTH); 165 | } else { 166 | return readBits(QMC5883_ADDRESS, QMC5883_REG_CONFIG_1, QMC5883_CRB_RANGE_BIT, QMC5883_CRB_RANGE_LENGTH); 167 | } 168 | } 169 | 170 | /** Set magnetic field gain value 171 | */ 172 | void Mag5883::setRange(uint8_t gain) { 173 | if(isHMC_){ 174 | // use this method to guarantee that bits 4-0 are set to zero, which is a 175 | // requirement specified in the datasheet; it's actually more efficient than 176 | // using the I2Cdev.writeBits method 177 | writeByte(HMC5883L_ADDRESS, HMC5883L_REG_CONFIG_B, gain << 5); 178 | } else { 179 | writeBits(QMC5883_ADDRESS, QMC5883_REG_CONFIG_1, QMC5883_CRB_RANGE_BIT, QMC5883_CRB_RANGE_LENGTH, gain); 180 | } 181 | } 182 | 183 | /** Get measurement mode. 184 | ***** FOR HMC5883L ******* 185 | * In continuous-measurement mode, the device continuously performs measurements 186 | * and places the result in the data register. RDY goes high when new data is 187 | * placed in all three registers. After a power-on or a write to the mode or 188 | * configuration register, the first measurement set is available from all three 189 | * data output registers after a period of 2/fDO and subsequent measurements are 190 | * available at a frequency of fDO, where fDO is the frequency of data output. 191 | * 192 | * When single-measurement mode (default) is selected, device performs a single 193 | * measurement, sets RDY high and returned to idle mode. Mode register returns 194 | * to idle mode bit values. The measurement remains in the data output register 195 | * and RDY remains high until the data output register is read or another 196 | * measurement is performed. 197 | * 198 | ***** FOR QMC5883 ******* 199 | * Measurement mode is forced to continous, rate is defined by user 200 | */ 201 | 202 | uint8_t Mag5883::getMode() { 203 | if(isHMC_){ 204 | return readBits(HMC5883L_ADDRESS, HMC5883L_REG_MODE, HMC5883L_MODEREG_BIT, HMC5883L_MODEREG_LENGTH); 205 | } else { 206 | return 1; //measurement mode forced to continuous 207 | } 208 | } 209 | 210 | /** Set measurement mode (forced to continous for QMC5883) 211 | */ 212 | void Mag5883::setMode(uint8_t newMode) { 213 | if(isHMC_){ 214 | // use this method to guarantee that bits 7-2 are set to zero, which is a 215 | // requirement specified in the datasheet; it's actually more efficient than 216 | // using the I2Cdev.writeBits method 217 | writeByte(HMC5883L_ADDRESS, HMC5883L_REG_MODE, newMode << (HMC5883L_MODEREG_BIT - HMC5883L_MODEREG_LENGTH + 1)); 218 | mode = newMode; // track to tell if we have to clear bit 7 after a read 219 | } else { 220 | newMode = 1;// force to 1 (continuous) 221 | mode = newMode; 222 | 223 | writeBits(QMC5883_ADDRESS, QMC5883_REG_CONFIG_1, QMC5883_MODEREG_BIT, QMC5883_MODEREG_LENGTH, newMode); 224 | } 225 | } 226 | 227 | /** Get data output rate value. 228 | ***** FOR HMC5883L ******* 229 | * The Table below shows all selectable output rates in continuous measurement 230 | * mode. All three channels shall be measured within a given output rate. Other 231 | * output rates with maximum rate of 160 Hz can be achieved by monitoring DRDY 232 | * interrupt pin in single measurement mode. 233 | * 234 | * Value | Typical Data Output Rate (Hz) 235 | * ------+------------------------------ 236 | * 0 | 0.75 237 | * 1 | 1.5 238 | * 2 | 3 239 | * 3 | 7.5 240 | * 4 | 15 (Default) 241 | * 5 | 30 242 | * 6 | 75 243 | * 7 | Not used 244 | * 245 | * 246 | ***** FOR QMC5883 ******* 247 | * 248 | * * Value | Typical Data Output Rate (Hz) 249 | * ------+------------------------------ 250 | * 0 | 10 251 | * 1 | 50 252 | * 2 | 100 253 | * 3 | 200 254 | * 255 | * @return Current rate of data output to registers 256 | */ 257 | uint8_t Mag5883::getDataRate() { 258 | return 1; 259 | if(isHMC_){ 260 | return readBits(HMC5883L_ADDRESS, HMC5883L_REG_CONFIG_A, HMC5883L_CRA_RATE_BIT, HMC5883L_CRA_RATE_LENGTH); 261 | } else { 262 | return readBits(QMC5883_ADDRESS, QMC5883_REG_CONFIG_1, QMC5883_CRA_RATE_BIT, QMC5883_CRA_RATE_LENGTH); 263 | } 264 | } 265 | 266 | /** Set data output rate value. 267 | */ 268 | void Mag5883::setDataRate(uint8_t rate) { 269 | if(isHMC_){ 270 | writeBits(HMC5883L_ADDRESS, HMC5883L_REG_CONFIG_A, HMC5883L_CRA_RATE_BIT, HMC5883L_CRA_RATE_LENGTH, rate); 271 | } else { 272 | writeBits(QMC5883_ADDRESS, QMC5883_REG_CONFIG_1, QMC5883_CRA_RATE_BIT, QMC5883_CRA_RATE_LENGTH, rate); 273 | } 274 | } 275 | 276 | 277 | /** Get 3-axis heading measurements. 278 | * In the event the ADC reading overflows or underflows for the given channel, 279 | * or if there is a math overflow during the bias measurement, this data 280 | * register will contain the value -4096. This register value will clear when 281 | * after the next valid measurement is made. Note that this method automatically 282 | * clears the appropriate bit in the MODE register if Single mode is active. 283 | * @param x 16-bit signed integer container for X-axis heading 284 | * @param y 16-bit signed integer container for Y-axis heading 285 | * @param z 16-bit signed integer container for Z-axis heading 286 | * @see HMC5883L_RA_DATAX_H 287 | */ 288 | void Mag5883::getHeading(int16_t *x, int16_t *y, int16_t *z) { 289 | if(isHMC_){ 290 | readBytes(HMC5883L_ADDRESS, HMC5883L_REG_OUT_X_M, 6, buffer); 291 | if (mode == HMC5883L_MODE_SINGLE) writeByte(HMC5883L_ADDRESS, HMC5883L_REG_MODE, HMC5883L_MODE_SINGLE << (HMC5883L_MODEREG_BIT - HMC5883L_MODEREG_LENGTH + 1)); 292 | *x = (((int16_t)buffer[0]) << 8) | buffer[1]; 293 | *y = (((int16_t)buffer[4]) << 8) | buffer[5]; 294 | *z = (((int16_t)buffer[2]) << 8) | buffer[3]; 295 | } else { 296 | readBytes(QMC5883_ADDRESS, QMC5883_REG_OUT_X_L, 6, buffer); 297 | //if (mode == HMC5883L_MODE_SINGLE) writeByte(devAddr, HMC5883L_RA_MODE, HMC5883L_MODE_SINGLE << (HMC5883L_MODEREG_BIT - HMC5883L_MODEREG_LENGTH + 1)); 298 | *x = (((int16_t)buffer[1]) << 8) | buffer[0]; // careful LSB before MSB 299 | *z = (((int16_t)buffer[5]) << 8) | buffer[4]; // careful LSB before MSB 300 | *y = (((int16_t)buffer[3]) << 8) | buffer[2]; // careful LSB before MSB 301 | } 302 | } 303 | 304 | 305 | -------------------------------------------------------------------------------- /firmware/hedrot-firmware/ADXL345.h: -------------------------------------------------------------------------------- 1 | // ADXL345.cpp: ADXL345 I2C device methods 2 | // based on I2Cdev library collection - ADXL345 I2C device class 3 | // adapted for i2c_t3 through the custom code I2Ccom.cpp 4 | 5 | #ifndef _ADXL345_H_ 6 | #define _ADXL345_H_ 7 | 8 | #include "I2Ccom.h" 9 | 10 | #define ADXL345_ADDRESS_ALT_LOW 0x53 // alt address pin low (GND) 11 | #define ADXL345_ADDRESS_ALT_HIGH 0x1D // alt address pin high (VCC) 12 | #define ADXL345_DEFAULT_ADDRESS ADXL345_ADDRESS_ALT_LOW 13 | 14 | #define ADXL345_RA_DEVID 0x00 15 | #define ADXL345_RA_RESERVED1 0x01 16 | #define ADXL345_RA_THRESH_TAP 0x1D 17 | #define ADXL345_RA_OFSX 0x1E 18 | #define ADXL345_RA_OFSY 0x1F 19 | #define ADXL345_RA_OFSZ 0x20 20 | #define ADXL345_RA_DUR 0x21 21 | #define ADXL345_RA_LATENT 0x22 22 | #define ADXL345_RA_WINDOW 0x23 23 | #define ADXL345_RA_THRESH_ACT 0x24 24 | #define ADXL345_RA_THRESH_INACT 0x25 25 | #define ADXL345_RA_TIME_INACT 0x26 26 | #define ADXL345_RA_ACT_INACT_CTL 0x27 27 | #define ADXL345_RA_THRESH_FF 0x28 28 | #define ADXL345_RA_TIME_FF 0x29 29 | #define ADXL345_RA_TAP_AXES 0x2A 30 | #define ADXL345_RA_ACT_TAP_STATUS 0x2B 31 | #define ADXL345_RA_BW_RATE 0x2C 32 | #define ADXL345_RA_POWER_CTL 0x2D 33 | #define ADXL345_RA_INT_ENABLE 0x2E 34 | #define ADXL345_RA_INT_MAP 0x2F 35 | #define ADXL345_RA_INT_SOURCE 0x30 36 | #define ADXL345_RA_DATA_FORMAT 0x31 37 | #define ADXL345_RA_DATAX0 0x32 38 | #define ADXL345_RA_DATAX1 0x33 39 | #define ADXL345_RA_DATAY0 0x34 40 | #define ADXL345_RA_DATAY1 0x35 41 | #define ADXL345_RA_DATAZ0 0x36 42 | #define ADXL345_RA_DATAZ1 0x37 43 | #define ADXL345_RA_FIFO_CTL 0x38 44 | #define ADXL345_RA_FIFO_STATUS 0x39 45 | 46 | #define ADXL345_AIC_ACT_AC_BIT 7 47 | #define ADXL345_AIC_ACT_X_BIT 6 48 | #define ADXL345_AIC_ACT_Y_BIT 5 49 | #define ADXL345_AIC_ACT_Z_BIT 4 50 | #define ADXL345_AIC_INACT_AC_BIT 3 51 | #define ADXL345_AIC_INACT_X_BIT 2 52 | #define ADXL345_AIC_INACT_Y_BIT 1 53 | #define ADXL345_AIC_INACT_Z_BIT 0 54 | 55 | #define ADXL345_TAPAXIS_SUP_BIT 3 56 | #define ADXL345_TAPAXIS_X_BIT 2 57 | #define ADXL345_TAPAXIS_Y_BIT 1 58 | #define ADXL345_TAPAXIS_Z_BIT 0 59 | 60 | #define ADXL345_TAPSTAT_ACTX_BIT 6 61 | #define ADXL345_TAPSTAT_ACTY_BIT 5 62 | #define ADXL345_TAPSTAT_ACTZ_BIT 4 63 | #define ADXL345_TAPSTAT_ASLEEP_BIT 3 64 | #define ADXL345_TAPSTAT_TAPX_BIT 2 65 | #define ADXL345_TAPSTAT_TAPY_BIT 1 66 | #define ADXL345_TAPSTAT_TAPZ_BIT 0 67 | 68 | #define ADXL345_BW_LOWPOWER_BIT 4 69 | #define ADXL345_BW_RATE_BIT 3 70 | #define ADXL345_BW_RATE_LENGTH 4 71 | 72 | #define ADXL345_RATE_3200 0b1111 73 | #define ADXL345_RATE_1600 0b1110 74 | #define ADXL345_RATE_800 0b1101 75 | #define ADXL345_RATE_400 0b1100 76 | #define ADXL345_RATE_200 0b1011 77 | #define ADXL345_RATE_100 0b1010 78 | #define ADXL345_RATE_50 0b1001 79 | #define ADXL345_RATE_25 0b1000 80 | #define ADXL345_RATE_12P5 0b0111 81 | #define ADXL345_RATE_6P25 0b0110 82 | #define ADXL345_RATE_3P13 0b0101 83 | #define ADXL345_RATE_1P56 0b0100 84 | #define ADXL345_RATE_0P78 0b0011 85 | #define ADXL345_RATE_0P39 0b0010 86 | #define ADXL345_RATE_0P20 0b0001 87 | #define ADXL345_RATE_0P10 0b0000 88 | 89 | #define ADXL345_PCTL_LINK_BIT 5 90 | #define ADXL345_PCTL_AUTOSLEEP_BIT 4 91 | #define ADXL345_PCTL_MEASURE_BIT 3 92 | #define ADXL345_PCTL_SLEEP_BIT 2 93 | #define ADXL345_PCTL_WAKEUP_BIT 1 94 | #define ADXL345_PCTL_WAKEUP_LENGTH 2 95 | 96 | #define ADXL345_WAKEUP_8HZ 0b00 97 | #define ADXL345_WAKEUP_4HZ 0b01 98 | #define ADXL345_WAKEUP_2HZ 0b10 99 | #define ADXL345_WAKEUP_1HZ 0b11 100 | 101 | #define ADXL345_INT_DATA_READY_BIT 7 102 | #define ADXL345_INT_SINGLE_TAP_BIT 6 103 | #define ADXL345_INT_DOUBLE_TAP_BIT 5 104 | #define ADXL345_INT_ACTIVITY_BIT 4 105 | #define ADXL345_INT_INACTIVITY_BIT 3 106 | #define ADXL345_INT_FREE_FALL_BIT 2 107 | #define ADXL345_INT_WATERMARK_BIT 1 108 | #define ADXL345_INT_OVERRUN_BIT 0 109 | 110 | #define ADXL345_FORMAT_SELFTEST_BIT 7 111 | #define ADXL345_FORMAT_SPIMODE_BIT 6 112 | #define ADXL345_FORMAT_INTMODE_BIT 5 113 | #define ADXL345_FORMAT_FULL_RES_BIT 3 114 | #define ADXL345_FORMAT_JUSTIFY_BIT 2 115 | #define ADXL345_FORMAT_RANGE_BIT 1 116 | #define ADXL345_FORMAT_RANGE_LENGTH 2 117 | 118 | #define ADXL345_RANGE_2G 0b00 119 | #define ADXL345_RANGE_4G 0b01 120 | #define ADXL345_RANGE_8G 0b10 121 | #define ADXL345_RANGE_16G 0b11 122 | 123 | #define ADXL345_FIFO_MODE_BIT 7 124 | #define ADXL345_FIFO_MODE_LENGTH 2 125 | #define ADXL345_FIFO_TRIGGER_BIT 5 126 | #define ADXL345_FIFO_SAMPLES_BIT 4 127 | #define ADXL345_FIFO_SAMPLES_LENGTH 5 128 | 129 | #define ADXL345_FIFO_MODE_BYPASS 0b00 130 | #define ADXL345_FIFO_MODE_FIFO 0b01 131 | #define ADXL345_FIFO_MODE_STREAM 0b10 132 | #define ADXL345_FIFO_MODE_TRIGGER 0b11 133 | 134 | #define ADXL345_FIFOSTAT_TRIGGER_BIT 7 135 | #define ADXL345_FIFOSTAT_LENGTH_BIT 5 136 | #define ADXL345_FIFOSTAT_LENGTH_LENGTH 6 137 | 138 | class ADXL345 { 139 | public: 140 | ADXL345(); 141 | ADXL345(uint8_t address); 142 | 143 | void initialize(); 144 | bool testConnection(); 145 | 146 | // DEVID register 147 | uint8_t getDeviceID(); 148 | 149 | // THRESH_TAP register 150 | uint8_t getTapThreshold(); 151 | void setTapThreshold(uint8_t threshold); 152 | 153 | // OFS* registers 154 | void getOffset(int8_t* x, int8_t* y, int8_t* z); 155 | void setOffset(int8_t x, int8_t y, int8_t z); 156 | int8_t getOffsetX(); 157 | void setOffsetX(int8_t x); 158 | int8_t getOffsetY(); 159 | void setOffsetY(int8_t y); 160 | int8_t getOffsetZ(); 161 | void setOffsetZ(int8_t z); 162 | 163 | // DUR register 164 | uint8_t getTapDuration(); 165 | void setTapDuration(uint8_t duration); 166 | 167 | // LATENT register 168 | uint8_t getDoubleTapLatency(); 169 | void setDoubleTapLatency(uint8_t latency); 170 | 171 | // WINDOW register 172 | uint8_t getDoubleTapWindow(); 173 | void setDoubleTapWindow(uint8_t window); 174 | 175 | // THRESH_ACT register 176 | uint8_t getActivityThreshold(); 177 | void setActivityThreshold(uint8_t threshold); 178 | 179 | // THRESH_INACT register 180 | uint8_t getInactivityThreshold(); 181 | void setInactivityThreshold(uint8_t threshold); 182 | 183 | // TIME_INACT register 184 | uint8_t getInactivityTime(); 185 | void setInactivityTime(uint8_t time); 186 | 187 | // ACT_INACT_CTL register 188 | bool getActivityAC(); 189 | void setActivityAC(bool enabled); 190 | bool getActivityXEnabled(); 191 | void setActivityXEnabled(bool enabled); 192 | bool getActivityYEnabled(); 193 | void setActivityYEnabled(bool enabled); 194 | bool getActivityZEnabled(); 195 | void setActivityZEnabled(bool enabled); 196 | bool getInactivityAC(); 197 | void setInactivityAC(bool enabled); 198 | bool getInactivityXEnabled(); 199 | void setInactivityXEnabled(bool enabled); 200 | bool getInactivityYEnabled(); 201 | void setInactivityYEnabled(bool enabled); 202 | bool getInactivityZEnabled(); 203 | void setInactivityZEnabled(bool enabled); 204 | 205 | // THRESH_FF register 206 | uint8_t getFreefallThreshold(); 207 | void setFreefallThreshold(uint8_t threshold); 208 | 209 | // TIME_FF register 210 | uint8_t getFreefallTime(); 211 | void setFreefallTime(uint8_t time); 212 | 213 | // TAP_AXES register 214 | bool getTapAxisSuppress(); 215 | void setTapAxisSuppress(bool enabled); 216 | bool getTapAxisXEnabled(); 217 | void setTapAxisXEnabled(bool enabled); 218 | bool getTapAxisYEnabled(); 219 | void setTapAxisYEnabled(bool enabled); 220 | bool getTapAxisZEnabled(); 221 | void setTapAxisZEnabled(bool enabled); 222 | 223 | // ACT_TAP_STATUS register 224 | bool getActivitySourceX(); 225 | bool getActivitySourceY(); 226 | bool getActivitySourceZ(); 227 | bool getAsleep(); 228 | bool getTapSourceX(); 229 | bool getTapSourceY(); 230 | bool getTapSourceZ(); 231 | 232 | // BW_RATE register 233 | bool getLowPowerEnabled(); 234 | void setLowPowerEnabled(bool enabled); 235 | uint8_t getRate(); 236 | void setRate(uint8_t rate); 237 | 238 | // POWER_CTL register 239 | bool getLinkEnabled(); 240 | void setLinkEnabled(bool enabled); 241 | bool getAutoSleepEnabled(); 242 | void setAutoSleepEnabled(bool enabled); 243 | bool getMeasureEnabled(); 244 | void setMeasureEnabled(bool enabled); 245 | bool getSleepEnabled(); 246 | void setSleepEnabled(bool enabled); 247 | uint8_t getWakeupFrequency(); 248 | void setWakeupFrequency(uint8_t frequency); 249 | 250 | // INT_ENABLE register 251 | bool getIntDataReadyEnabled(); 252 | void setIntDataReadyEnabled(bool enabled); 253 | bool getIntSingleTapEnabled(); 254 | void setIntSingleTapEnabled(bool enabled); 255 | bool getIntDoubleTapEnabled(); 256 | void setIntDoubleTapEnabled(bool enabled); 257 | bool getIntActivityEnabled(); 258 | void setIntActivityEnabled(bool enabled); 259 | bool getIntInactivityEnabled(); 260 | void setIntInactivityEnabled(bool enabled); 261 | bool getIntFreefallEnabled(); 262 | void setIntFreefallEnabled(bool enabled); 263 | bool getIntWatermarkEnabled(); 264 | void setIntWatermarkEnabled(bool enabled); 265 | bool getIntOverrunEnabled(); 266 | void setIntOverrunEnabled(bool enabled); 267 | 268 | // INT_MAP register 269 | uint8_t getIntDataReadyPin(); 270 | void setIntDataReadyPin(uint8_t pin); 271 | uint8_t getIntSingleTapPin(); 272 | void setIntSingleTapPin(uint8_t pin); 273 | uint8_t getIntDoubleTapPin(); 274 | void setIntDoubleTapPin(uint8_t pin); 275 | uint8_t getIntActivityPin(); 276 | void setIntActivityPin(uint8_t pin); 277 | uint8_t getIntInactivityPin(); 278 | void setIntInactivityPin(uint8_t pin); 279 | uint8_t getIntFreefallPin(); 280 | void setIntFreefallPin(uint8_t pin); 281 | uint8_t getIntWatermarkPin(); 282 | void setIntWatermarkPin(uint8_t pin); 283 | uint8_t getIntOverrunPin(); 284 | void setIntOverrunPin(uint8_t pin); 285 | 286 | // INT_SOURCE register 287 | uint8_t getIntDataReadySource(); 288 | uint8_t getIntSingleTapSource(); 289 | uint8_t getIntDoubleTapSource(); 290 | uint8_t getIntActivitySource(); 291 | uint8_t getIntInactivitySource(); 292 | uint8_t getIntFreefallSource(); 293 | uint8_t getIntWatermarkSource(); 294 | uint8_t getIntOverrunSource(); 295 | 296 | // DATA_FORMAT register 297 | uint8_t getSelfTestEnabled(); 298 | void setSelfTestEnabled(uint8_t enabled); 299 | uint8_t getSPIMode(); 300 | void setSPIMode(uint8_t mode); 301 | uint8_t getInterruptMode(); 302 | void setInterruptMode(uint8_t mode); 303 | uint8_t getFullResolution(); 304 | void setFullResolution(uint8_t resolution); 305 | uint8_t getDataJustification(); 306 | void setDataJustification(uint8_t justification); 307 | uint8_t getRange(); 308 | void setRange(uint8_t range); 309 | 310 | // DATA* registers 311 | void getAcceleration(int16_t* x, int16_t* y, int16_t* z); 312 | int16_t getAccelerationX(); 313 | int16_t getAccelerationY(); 314 | int16_t getAccelerationZ(); 315 | 316 | // FIFO_CTL register 317 | uint8_t getFIFOMode(); 318 | void setFIFOMode(uint8_t mode); 319 | uint8_t getFIFOTriggerInterruptPin(); 320 | void setFIFOTriggerInterruptPin(uint8_t interrupt); 321 | uint8_t getFIFOSamples(); 322 | void setFIFOSamples(uint8_t size); 323 | 324 | // FIFO_STATUS register 325 | bool getFIFOTriggerOccurred(); 326 | uint8_t getFIFOLength(); 327 | 328 | private: 329 | uint8_t devAddr; 330 | uint8_t buffer[6]; 331 | }; 332 | 333 | #endif /* _ADXL345_H_ */ 334 | -------------------------------------------------------------------------------- /command-line-demo/xcode/hedrotReceiverDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 164863FC1F27940E00698E6C /* libhedrot_calibration.c in Sources */ = {isa = PBXBuildFile; fileRef = 164863F61F27940E00698E6C /* libhedrot_calibration.c */; }; 11 | 164863FD1F27940E00698E6C /* libhedrot_RTmagCalibration.c in Sources */ = {isa = PBXBuildFile; fileRef = 164863F81F27940E00698E6C /* libhedrot_RTmagCalibration.c */; }; 12 | 164863FE1F27940E00698E6C /* libhedrot_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 164863FA1F27940E00698E6C /* libhedrot_utils.c */; }; 13 | 16FEAF4E1DCBDB1B007B9E47 /* hedrotReceiverDemo.c in Sources */ = {isa = PBXBuildFile; fileRef = 16FEAF4D1DCBDB1B007B9E47 /* hedrotReceiverDemo.c */; }; 14 | 16FEAF5A1DCBDB51007B9E47 /* libhedrot.c in Sources */ = {isa = PBXBuildFile; fileRef = 16FEAF561DCBDB4A007B9E47 /* libhedrot.c */; }; 15 | 16FEAF5B1DCBDB53007B9E47 /* libhedrot_serialcomm.c in Sources */ = {isa = PBXBuildFile; fileRef = 16FEAF581DCBDB4A007B9E47 /* libhedrot_serialcomm.c */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 164863F61F27940E00698E6C /* libhedrot_calibration.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libhedrot_calibration.c; sourceTree = ""; }; 20 | 164863F71F27940E00698E6C /* libhedrot_calibration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libhedrot_calibration.h; sourceTree = ""; }; 21 | 164863F81F27940E00698E6C /* libhedrot_RTmagCalibration.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libhedrot_RTmagCalibration.c; sourceTree = ""; }; 22 | 164863F91F27940E00698E6C /* libhedrot_RTmagCalibration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libhedrot_RTmagCalibration.h; sourceTree = ""; }; 23 | 164863FA1F27940E00698E6C /* libhedrot_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libhedrot_utils.c; sourceTree = ""; }; 24 | 164863FB1F27940E00698E6C /* libhedrot_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libhedrot_utils.h; sourceTree = ""; }; 25 | 166D0E481DB3E54D007B85B9 /* hedrotReceiverDemo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hedrotReceiverDemo; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 16FEAF4D1DCBDB1B007B9E47 /* hedrotReceiverDemo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hedrotReceiverDemo.c; path = ../source/hedrotReceiverDemo.c; sourceTree = ""; }; 27 | 16FEAF561DCBDB4A007B9E47 /* libhedrot.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = libhedrot.c; sourceTree = ""; }; 28 | 16FEAF571DCBDB4A007B9E47 /* libhedrot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libhedrot.h; sourceTree = ""; }; 29 | 16FEAF581DCBDB4A007B9E47 /* libhedrot_serialcomm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = libhedrot_serialcomm.c; sourceTree = ""; }; 30 | 16FEAF591DCBDB4A007B9E47 /* libhedrot_serialcomm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libhedrot_serialcomm.h; sourceTree = ""; }; 31 | 16FEAF5C1DCBDB6A007B9E47 /* hedrot_comm_protocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hedrot_comm_protocol.h; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 166D0E451DB3E54D007B85B9 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | 166D0E3F1DB3E54D007B85B9 = { 46 | isa = PBXGroup; 47 | children = ( 48 | 16FEAF5D1DCBDB6E007B9E47 /* firmware */, 49 | 16FEAF4D1DCBDB1B007B9E47 /* hedrotReceiverDemo.c */, 50 | 16FEAF551DCBDB4A007B9E47 /* libhedrot */, 51 | 166D0E491DB3E54D007B85B9 /* Products */, 52 | ); 53 | sourceTree = ""; 54 | }; 55 | 166D0E491DB3E54D007B85B9 /* Products */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | 166D0E481DB3E54D007B85B9 /* hedrotReceiverDemo */, 59 | ); 60 | name = Products; 61 | sourceTree = ""; 62 | }; 63 | 16FEAF551DCBDB4A007B9E47 /* libhedrot */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 16FEAF561DCBDB4A007B9E47 /* libhedrot.c */, 67 | 16FEAF571DCBDB4A007B9E47 /* libhedrot.h */, 68 | 16FEAF581DCBDB4A007B9E47 /* libhedrot_serialcomm.c */, 69 | 16FEAF591DCBDB4A007B9E47 /* libhedrot_serialcomm.h */, 70 | 164863F61F27940E00698E6C /* libhedrot_calibration.c */, 71 | 164863F71F27940E00698E6C /* libhedrot_calibration.h */, 72 | 164863F81F27940E00698E6C /* libhedrot_RTmagCalibration.c */, 73 | 164863F91F27940E00698E6C /* libhedrot_RTmagCalibration.h */, 74 | 164863FA1F27940E00698E6C /* libhedrot_utils.c */, 75 | 164863FB1F27940E00698E6C /* libhedrot_utils.h */, 76 | ); 77 | name = libhedrot; 78 | path = ../../libhedrot; 79 | sourceTree = ""; 80 | }; 81 | 16FEAF5D1DCBDB6E007B9E47 /* firmware */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 16FEAF5C1DCBDB6A007B9E47 /* hedrot_comm_protocol.h */, 85 | ); 86 | name = firmware; 87 | path = "../../firmware/hedrot-firmware"; 88 | sourceTree = SOURCE_ROOT; 89 | }; 90 | /* End PBXGroup section */ 91 | 92 | /* Begin PBXNativeTarget section */ 93 | 166D0E471DB3E54D007B85B9 /* hedrotReceiverDemo */ = { 94 | isa = PBXNativeTarget; 95 | buildConfigurationList = 166D0E4F1DB3E54D007B85B9 /* Build configuration list for PBXNativeTarget "hedrotReceiverDemo" */; 96 | buildPhases = ( 97 | 166D0E441DB3E54D007B85B9 /* Sources */, 98 | 166D0E451DB3E54D007B85B9 /* Frameworks */, 99 | 16728FBB1DCBDD4500F780CB /* ShellScript */, 100 | ); 101 | buildRules = ( 102 | ); 103 | dependencies = ( 104 | ); 105 | name = hedrotReceiverDemo; 106 | productName = headtracker_rcv_cmd; 107 | productReference = 166D0E481DB3E54D007B85B9 /* hedrotReceiverDemo */; 108 | productType = "com.apple.product-type.tool"; 109 | }; 110 | /* End PBXNativeTarget section */ 111 | 112 | /* Begin PBXProject section */ 113 | 166D0E401DB3E54D007B85B9 /* Project object */ = { 114 | isa = PBXProject; 115 | attributes = { 116 | LastUpgradeCheck = 0820; 117 | ORGANIZATIONNAME = "Alexis Baskind"; 118 | TargetAttributes = { 119 | 166D0E471DB3E54D007B85B9 = { 120 | CreatedOnToolsVersion = 6.2; 121 | }; 122 | }; 123 | }; 124 | buildConfigurationList = 166D0E431DB3E54D007B85B9 /* Build configuration list for PBXProject "hedrotReceiverDemo" */; 125 | compatibilityVersion = "Xcode 3.2"; 126 | developmentRegion = English; 127 | hasScannedForEncodings = 0; 128 | knownRegions = ( 129 | en, 130 | ); 131 | mainGroup = 166D0E3F1DB3E54D007B85B9; 132 | productRefGroup = 166D0E491DB3E54D007B85B9 /* Products */; 133 | projectDirPath = ""; 134 | projectRoot = ""; 135 | targets = ( 136 | 166D0E471DB3E54D007B85B9 /* hedrotReceiverDemo */, 137 | ); 138 | }; 139 | /* End PBXProject section */ 140 | 141 | /* Begin PBXShellScriptBuildPhase section */ 142 | 16728FBB1DCBDD4500F780CB /* ShellScript */ = { 143 | isa = PBXShellScriptBuildPhase; 144 | buildActionMask = 2147483647; 145 | files = ( 146 | ); 147 | inputPaths = ( 148 | ); 149 | outputPaths = ( 150 | ); 151 | runOnlyForDeploymentPostprocessing = 0; 152 | shellPath = /bin/sh; 153 | shellScript = "cp ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME} ."; 154 | }; 155 | /* End PBXShellScriptBuildPhase section */ 156 | 157 | /* Begin PBXSourcesBuildPhase section */ 158 | 166D0E441DB3E54D007B85B9 /* Sources */ = { 159 | isa = PBXSourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 164863FD1F27940E00698E6C /* libhedrot_RTmagCalibration.c in Sources */, 163 | 164863FC1F27940E00698E6C /* libhedrot_calibration.c in Sources */, 164 | 16FEAF4E1DCBDB1B007B9E47 /* hedrotReceiverDemo.c in Sources */, 165 | 164863FE1F27940E00698E6C /* libhedrot_utils.c in Sources */, 166 | 16FEAF5B1DCBDB53007B9E47 /* libhedrot_serialcomm.c in Sources */, 167 | 16FEAF5A1DCBDB51007B9E47 /* libhedrot.c in Sources */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXSourcesBuildPhase section */ 172 | 173 | /* Begin XCBuildConfiguration section */ 174 | 166D0E4D1DB3E54D007B85B9 /* Debug */ = { 175 | isa = XCBuildConfiguration; 176 | buildSettings = { 177 | ALWAYS_SEARCH_USER_PATHS = NO; 178 | ARCHS = "$(ARCHS_STANDARD)"; 179 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 180 | CLANG_CXX_LIBRARY = "libc++"; 181 | CLANG_ENABLE_MODULES = YES; 182 | CLANG_ENABLE_OBJC_ARC = YES; 183 | CLANG_WARN_BOOL_CONVERSION = YES; 184 | CLANG_WARN_CONSTANT_CONVERSION = YES; 185 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 186 | CLANG_WARN_EMPTY_BODY = YES; 187 | CLANG_WARN_ENUM_CONVERSION = YES; 188 | CLANG_WARN_INFINITE_RECURSION = YES; 189 | CLANG_WARN_INT_CONVERSION = YES; 190 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 191 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 192 | CLANG_WARN_UNREACHABLE_CODE = YES; 193 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 194 | COPY_PHASE_STRIP = NO; 195 | ENABLE_STRICT_OBJC_MSGSEND = YES; 196 | ENABLE_TESTABILITY = YES; 197 | GCC_C_LANGUAGE_STANDARD = gnu99; 198 | GCC_DYNAMIC_NO_PIC = NO; 199 | GCC_NO_COMMON_BLOCKS = YES; 200 | GCC_OPTIMIZATION_LEVEL = 0; 201 | GCC_PREPROCESSOR_DEFINITIONS = ( 202 | "DEBUG=1", 203 | "$(inherited)", 204 | ); 205 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 206 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 207 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 208 | GCC_WARN_UNDECLARED_SELECTOR = YES; 209 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 210 | GCC_WARN_UNUSED_FUNCTION = YES; 211 | GCC_WARN_UNUSED_VARIABLE = YES; 212 | MACOSX_DEPLOYMENT_TARGET = 10.9; 213 | MTL_ENABLE_DEBUG_INFO = YES; 214 | ONLY_ACTIVE_ARCH = YES; 215 | SDKROOT = macosx10.9; 216 | }; 217 | name = Debug; 218 | }; 219 | 166D0E4E1DB3E54D007B85B9 /* Release */ = { 220 | isa = XCBuildConfiguration; 221 | buildSettings = { 222 | ALWAYS_SEARCH_USER_PATHS = NO; 223 | ARCHS = "$(ARCHS_STANDARD)"; 224 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 225 | CLANG_CXX_LIBRARY = "libc++"; 226 | CLANG_ENABLE_MODULES = YES; 227 | CLANG_ENABLE_OBJC_ARC = YES; 228 | CLANG_WARN_BOOL_CONVERSION = YES; 229 | CLANG_WARN_CONSTANT_CONVERSION = YES; 230 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 231 | CLANG_WARN_EMPTY_BODY = YES; 232 | CLANG_WARN_ENUM_CONVERSION = YES; 233 | CLANG_WARN_INFINITE_RECURSION = YES; 234 | CLANG_WARN_INT_CONVERSION = YES; 235 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 236 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 237 | CLANG_WARN_UNREACHABLE_CODE = YES; 238 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 239 | COPY_PHASE_STRIP = NO; 240 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 241 | ENABLE_NS_ASSERTIONS = NO; 242 | ENABLE_STRICT_OBJC_MSGSEND = YES; 243 | GCC_C_LANGUAGE_STANDARD = gnu99; 244 | GCC_NO_COMMON_BLOCKS = YES; 245 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 246 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 247 | GCC_WARN_UNDECLARED_SELECTOR = YES; 248 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 249 | GCC_WARN_UNUSED_FUNCTION = YES; 250 | GCC_WARN_UNUSED_VARIABLE = YES; 251 | MACOSX_DEPLOYMENT_TARGET = 10.9; 252 | MTL_ENABLE_DEBUG_INFO = NO; 253 | SDKROOT = macosx10.9; 254 | }; 255 | name = Release; 256 | }; 257 | 166D0E501DB3E54D007B85B9 /* Debug */ = { 258 | isa = XCBuildConfiguration; 259 | buildSettings = { 260 | PRODUCT_NAME = hedrotReceiverDemo; 261 | SDKROOT = macosx10.9; 262 | }; 263 | name = Debug; 264 | }; 265 | 166D0E511DB3E54D007B85B9 /* Release */ = { 266 | isa = XCBuildConfiguration; 267 | buildSettings = { 268 | PRODUCT_NAME = hedrotReceiverDemo; 269 | SDKROOT = macosx10.9; 270 | }; 271 | name = Release; 272 | }; 273 | /* End XCBuildConfiguration section */ 274 | 275 | /* Begin XCConfigurationList section */ 276 | 166D0E431DB3E54D007B85B9 /* Build configuration list for PBXProject "hedrotReceiverDemo" */ = { 277 | isa = XCConfigurationList; 278 | buildConfigurations = ( 279 | 166D0E4D1DB3E54D007B85B9 /* Debug */, 280 | 166D0E4E1DB3E54D007B85B9 /* Release */, 281 | ); 282 | defaultConfigurationIsVisible = 0; 283 | defaultConfigurationName = Release; 284 | }; 285 | 166D0E4F1DB3E54D007B85B9 /* Build configuration list for PBXNativeTarget "hedrotReceiverDemo" */ = { 286 | isa = XCConfigurationList; 287 | buildConfigurations = ( 288 | 166D0E501DB3E54D007B85B9 /* Debug */, 289 | 166D0E511DB3E54D007B85B9 /* Release */, 290 | ); 291 | defaultConfigurationIsVisible = 0; 292 | defaultConfigurationName = Release; 293 | }; 294 | /* End XCConfigurationList section */ 295 | }; 296 | rootObject = 166D0E401DB3E54D007B85B9 /* Project object */; 297 | } 298 | -------------------------------------------------------------------------------- /hedrotReceiver/source/hedrot_receiver.h: -------------------------------------------------------------------------------- 1 | // hedrot_receiver.h 2 | // 3 | // Copyright 2016 Alexis Baskind 4 | 5 | #ifndef hedrot_receiver_h 6 | #define hedrot_receiver_h 7 | 8 | #include "ext.h" 9 | #include "ext_common.h" 10 | #include "ext_strings.h" 11 | #include "ext_proto.h" 12 | #include "ext_support.h" 13 | #include "ext_maxtypes.h" 14 | #include "ext_mess.h" 15 | #include "ext_user.h" 16 | #include "ext_critical.h" 17 | #include "ext_dictobj.h" 18 | #include "jit.common.h" 19 | #include "z_dsp.h" 20 | #include "ext_buffer.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "libhedrot.h" 27 | #include "hedrot_comm_protocol.h" 28 | 29 | // time constants 30 | #define SEARCHING_DEVICE_TIME 200 //time period between two ticks when the headtracker has still not been found 31 | 32 | typedef struct hedrot_receiver 33 | { 34 | t_object x_obj; 35 | 36 | //outlets 37 | void *x_rawData_outlet; 38 | void *x_calData_outlet; 39 | void *x_cookedAngles_outlet; 40 | void *x_cookedQuaternions_outlet; 41 | void *x_status_outlet; 42 | void *x_error_outlet; 43 | void *x_debug_outlet; 44 | 45 | 46 | // general variables about information reception 47 | t_object *receive_and_output_clock; 48 | 49 | headtrackerData *trackingData; 50 | 51 | // mirror of the internal settings of the structure trackingData that are used as attributes by Max 52 | // unfortunately necessary, since attributes can be only linked to variables on the top level of the Max object struct 53 | char verbose; 54 | char headtracker_on; 55 | char autoDiscover; 56 | char outputCenteredAngles; 57 | long samplerate; 58 | unsigned char gyroDataRate; 59 | unsigned char gyroClockSource; 60 | unsigned char gyroDLPFBandwidth; 61 | unsigned char gyroOffsetAutocalOn; 62 | unsigned char accRange; 63 | long accHardOffset[3]; // the Max API does not seem to handle signed char arrays => need to handle it as long 64 | unsigned char accFullResolutionBit; 65 | unsigned char accDataRate; 66 | unsigned char magMeasurementBias; 67 | unsigned char magSampleAveraging; 68 | unsigned char magDataRate; 69 | unsigned char magRange; 70 | unsigned char magMeasurementMode; 71 | float gyroOffsetAutocalTime; // in ms 72 | long gyroOffsetAutocalThreshold; //in LSB units 73 | float accOffset[3]; 74 | float accScaling[3]; 75 | float magOffset[3]; 76 | float magScaling[3]; 77 | 78 | char estimationMethod; 79 | float MadgwickBetaMax; 80 | float MadgwickBetaGain; 81 | float accLPtimeConstant; 82 | char axesReference; 83 | char rotationOrder; 84 | char invertRotation; 85 | float accCalMaxGyroNorm; 86 | char offlineCalibrationMethod; //0 = double ellipsoid fit, 1 = Aussal 87 | char RTmagCalibrationMethod; //0 = direct, 1 = iterative 88 | char RTmagCalOn; 89 | float RTmagMaxMemoryDuration; // RT mag calibration step 1: maximum duration of the memory used for calibration, in seconds 90 | float RTmagMaxDistanceError; // for RT mag calibration step 2, tolerance on the radius for new points 91 | float RTMagCalibrationPeriod; // RT mag calibration period in seconds 92 | 93 | 94 | // output data 95 | t_atom t_estimatedAngles[3]; 96 | t_atom t_estimatedQuaternion[4]; 97 | 98 | t_dictionary *magCalInfoDict; 99 | t_symbol *magCalInfoDictName; 100 | t_jit_object *magCalDataCalSamples_Matrix; 101 | t_buffer_obj *magCalDataCalNorm_BufferObj; 102 | t_symbol *magCalDataCalNorm_BufferObjName; 103 | 104 | t_dictionary *accCalInfoDict; 105 | t_symbol *accCalInfoDictName; 106 | t_jit_object *accCalDataCalSamples_Matrix; 107 | t_buffer_obj *accCalDataCalNorm_BufferObj; 108 | t_symbol *accCalDataCalNorm_BufferObjName; 109 | 110 | t_dictionary *RTmagCalInfoDict; 111 | t_symbol *RTmagCalInfoDictName; 112 | void *RTmagCalDataCalSamples_Matrix; 113 | t_buffer_obj *RTmagCalDataCalNorm_BufferObj; 114 | t_symbol *RTmagCalDataCalNorm_BufferObjName; 115 | 116 | 117 | // (control) output data rate 118 | long outputDataPeriod; 119 | 120 | // list to be send after formating... 121 | t_atom rawData[9]; 122 | // ... and after calibration 123 | t_atom calData[9]; 124 | 125 | // rec into text file 126 | char filename[MAX_PATH_CHARS]; 127 | t_filehandle fh_write; 128 | char recordingDataFlag; 129 | long recsampleCount; 130 | char tmpStr[1024]; 131 | 132 | } t_hedrot_receiver; 133 | 134 | 135 | t_class *hedrot_receiver_class; 136 | 137 | 138 | void *hedrot_receiver_new(t_symbol *s, short ac, t_atom *av); 139 | void hedrot_receiver_init(t_hedrot_receiver *x); 140 | void hedrot_receiver_tick(t_hedrot_receiver *x); 141 | void hedrot_receiver_free_clock(t_hedrot_receiver *x); 142 | void hedrot_receiver_free(t_hedrot_receiver *x); 143 | 144 | // methods 145 | void hedrot_receiver_open(t_hedrot_receiver *x, int n); 146 | void hedrot_receiver_close(t_hedrot_receiver *x); 147 | void hedrot_receiver_devices(t_hedrot_receiver *x); 148 | void hedrot_receiver_assist(t_hedrot_receiver *x, void *b, long m, long a, char *s); 149 | void hedrot_receiver_center_angles(t_hedrot_receiver *x); 150 | 151 | // methods for importing/exporting headtracker settings 152 | void hedrot_receiver_export_settings(t_hedrot_receiver *x, t_symbol *s); 153 | void hedrot_receiver_defered_export_settings(t_hedrot_receiver *x, t_symbol *s); 154 | void hedrot_receiver_import_settings(t_hedrot_receiver *x, t_symbol *s); 155 | void hedrot_receiver_defered_import_settings(t_hedrot_receiver *x, t_symbol *s); 156 | void hedrot_receiver_printVersion(t_hedrot_receiver *x, t_symbol *s); 157 | 158 | // methods for recording data into a text file 159 | void hedrot_receiver_opendestinationtextfile(t_hedrot_receiver *x, t_symbol *s); 160 | void hedrot_receiver_doopenforwrite(t_hedrot_receiver *x, t_symbol *s); 161 | void hedrot_receiver_startrec(t_hedrot_receiver *x); 162 | void hedrot_receiver_stoprec(t_hedrot_receiver *x); 163 | 164 | // generic methods for calibration 165 | char hedrot_receiver_createCalDataDictionary( float offset[], float scaling[], calibrationData *calData, 166 | t_dictionary *calDict, void *sampleMatrix, 167 | t_buffer_obj *normBufferObj, t_symbol *normBufferObjName); 168 | 169 | // methods for mag calibration 170 | void hedrot_receiver_startMagCalibration(t_hedrot_receiver *x); 171 | void hedrot_receiver_stopMagCalibration(t_hedrot_receiver *x); 172 | void hedrot_receiver_redoMagCalibration(t_hedrot_receiver *x); 173 | void hedrot_receiver_saveMagCalibration(t_hedrot_receiver *x); 174 | void hedrot_receiver_dumpMagCalInfo(t_hedrot_receiver *x); 175 | void hedrot_receiver_exportMagRawCalData(t_hedrot_receiver *x, t_symbol *s); 176 | void hedrot_receiver_defered_exportMagRawCalData(t_hedrot_receiver *x, t_symbol *s); 177 | 178 | // methods for acc calibration 179 | void hedrot_receiver_startAccCalibration(t_hedrot_receiver *x); 180 | void hedrot_receiver_stopAccCalibration(t_hedrot_receiver *x); 181 | void hedrot_receiver_redoAccCalibration(t_hedrot_receiver *x); 182 | void hedrot_receiver_saveAccCalibration(t_hedrot_receiver *x); 183 | void hedrot_receiver_dumpAccCalInfo(t_hedrot_receiver *x); 184 | void hedrot_receiver_exportAccRawCalData(t_hedrot_receiver *x, t_symbol *s); 185 | void hedrot_receiver_defered_exportAccRawCalData(t_hedrot_receiver *x, t_symbol *s); 186 | 187 | // methods for mag RT calibration 188 | void hedrot_receiver_dumpRTmagCalInfo(t_hedrot_receiver *x); 189 | void hedrot_receiver_exportRTmagRawCalData(t_hedrot_receiver *x, t_symbol *s); 190 | void hedrot_receiver_defered_exportRTmagRawCalData(t_hedrot_receiver *x, t_symbol *s); 191 | 192 | void hedrot_receiver_output_data(t_hedrot_receiver *x); 193 | 194 | 195 | void hedrot_receiver_autodiscover_deferedTick(t_hedrot_receiver *x, t_symbol *s, long argc, t_atom *argv); 196 | 197 | 198 | // output messages 199 | void hedrot_receiver_outputPortList(t_hedrot_receiver *x); 200 | void hedrot_receiver_selectOpenedPortInList(t_hedrot_receiver *x); 201 | void hedrot_receiver_outputWrongFirmwareVersionNotice(t_hedrot_receiver *x); 202 | void hedrot_receiver_outputReceptionStatus(t_hedrot_receiver *x); 203 | void hedrot_receiver_mirrorHeadtrackerInfo(t_hedrot_receiver *x); 204 | void hedrot_receiver_outputCalibrationNotValidNotice(t_hedrot_receiver *x); 205 | void hedrot_receiver_outputGyroCalibrationStartedNotice(t_hedrot_receiver *x); 206 | void hedrot_receiver_outputGyroCalibrationFinishedNotice(t_hedrot_receiver *x); 207 | void hedrot_receiver_outputMagCalibrationStartedNotice(t_hedrot_receiver *x); 208 | void hedrot_receiver_outputMagCalibrationSucceededNotice(t_hedrot_receiver *x); 209 | void hedrot_receiver_outputMagCalibrationFailedNotice(t_hedrot_receiver *x); 210 | void hedrot_receiver_outputAccCalibrationStartedNotice(t_hedrot_receiver *x); 211 | void hedrot_receiver_outputAccCalibrationSucceededNotice(t_hedrot_receiver *x); 212 | void hedrot_receiver_outputAccCalibrationFailedNotice(t_hedrot_receiver *x); 213 | void hedrot_receiver_outputAccCalibrationPausedNotice(t_hedrot_receiver *x); 214 | void hedrot_receiver_outputAccCalibrationResumedNotice(t_hedrot_receiver *x); 215 | void hedrot_receiver_boardOverloadNotice(t_hedrot_receiver *x); 216 | 217 | 218 | //getters and setters 219 | t_max_err hedrot_receiver_verbose_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 220 | t_max_err hedrot_receiver_headtracker_on_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 221 | t_max_err hedrot_receiver_autoDiscover_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 222 | t_max_err hedrot_receiver_samplerate_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 223 | t_max_err hedrot_receiver_outputCenteredAngles_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 224 | t_max_err hedrot_receiver_gyroDataRate_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 225 | t_max_err hedrot_receiver_gyroClockSource_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 226 | t_max_err hedrot_receiver_gyroDLPFBandwidth_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 227 | t_max_err hedrot_receiver_accRange_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 228 | t_max_err hedrot_receiver_accHardOffset_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 229 | t_max_err hedrot_receiver_accFullResolutionBit_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 230 | t_max_err hedrot_receiver_accDataRate_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 231 | t_max_err hedrot_receiver_magMeasurementBias_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 232 | t_max_err hedrot_receiver_magSampleAveraging_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 233 | t_max_err hedrot_receiver_magDataRate_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 234 | t_max_err hedrot_receiver_magRange_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv) ; 235 | t_max_err hedrot_receiver_magMeasurementMode_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 236 | t_max_err hedrot_receiver_gyroOffsetAutocalOn_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 237 | t_max_err hedrot_receiver_gyroOffsetAutocalTime_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 238 | t_max_err hedrot_receiver_gyroOffsetAutocalThreshold_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 239 | void hedrot_receiver_do_set_gyroOffsetAutocalOn(t_hedrot_receiver *x, char gyroOffsetAutocalOn); 240 | t_max_err hedrot_receiver_accOffset_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 241 | t_max_err hedrot_receiver_accScaling_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 242 | t_max_err hedrot_receiver_magOffset_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 243 | t_max_err hedrot_receiver_magScaling_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 244 | t_max_err hedrot_receiver_outputDataPeriod_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 245 | 246 | 247 | t_max_err hedrot_receiver_estimationMethod_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 248 | t_max_err hedrot_receiver_MadgwickBetaGain_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 249 | t_max_err hedrot_receiver_MadgwickBetaMax_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 250 | t_max_err hedrot_receiver_accLPtimeConstant_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 251 | t_max_err hedrot_receiver_axesReference_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 252 | t_max_err hedrot_receiver_rotationOrder_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 253 | t_max_err hedrot_receiver_invertRotation_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 254 | t_max_err hedrot_receiver_accCalMaxGyroNorm_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 255 | t_max_err hedrot_receiver_offlineCalibrationMethod_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 256 | t_max_err hedrot_receiver_RTmagCalibrationMethod_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 257 | t_max_err hedrot_receiver_RTmagCalOn_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 258 | t_max_err hedrot_receiver_RTmagMaxMemoryDuration_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 259 | t_max_err hedrot_receiver_RTmagMaxDistanceError_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 260 | t_max_err hedrot_receiver_RTMagCalibrationPeriod_set(t_hedrot_receiver *x, t_object *attr, long argc, t_atom *argv); 261 | 262 | 263 | #endif 264 | -------------------------------------------------------------------------------- /hedrotReceiver/xcode/hedrot_receiver.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1629E7D31DCBBC70006ACD46 /* hedrot_comm_protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 1629E7D21DCBBC70006ACD46 /* hedrot_comm_protocol.h */; }; 11 | 166427351E9F949D0081EE9E /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 166427341E9F949D0081EE9E /* Accelerate.framework */; }; 12 | 167539AD1EA3A0F60062BDCE /* commonsyms.c in Sources */ = {isa = PBXBuildFile; fileRef = 167539AC1EA3A0F60062BDCE /* commonsyms.c */; }; 13 | 16904B091EACA9F100517871 /* JitterAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16904B081EACA9F100517871 /* JitterAPI.framework */; }; 14 | 16904B0B1EACBE1D00517871 /* MaxAudioAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16904B0A1EACBE1D00517871 /* MaxAudioAPI.framework */; }; 15 | 1695F0051A87997F00708733 /* hedrot_receiver.c in Sources */ = {isa = PBXBuildFile; fileRef = 1695F0041A87997F00708733 /* hedrot_receiver.c */; }; 16 | 16B2FC731DC9F69B003EECB3 /* libhedrot_serialcomm.c in Sources */ = {isa = PBXBuildFile; fileRef = 16B2FC6F1DC9F69B003EECB3 /* libhedrot_serialcomm.c */; }; 17 | 16B2FC741DC9F69B003EECB3 /* libhedrot_serialcomm.h in Headers */ = {isa = PBXBuildFile; fileRef = 16B2FC701DC9F69B003EECB3 /* libhedrot_serialcomm.h */; }; 18 | 16B2FC751DC9F69B003EECB3 /* libhedrot.c in Sources */ = {isa = PBXBuildFile; fileRef = 16B2FC711DC9F69B003EECB3 /* libhedrot.c */; }; 19 | 16B2FC761DC9F69B003EECB3 /* libhedrot.h in Headers */ = {isa = PBXBuildFile; fileRef = 16B2FC721DC9F69B003EECB3 /* libhedrot.h */; }; 20 | 16F0E6821EA4CAC500365603 /* libhedrot_calibration.c in Sources */ = {isa = PBXBuildFile; fileRef = 16F0E6801EA4CAC500365603 /* libhedrot_calibration.c */; }; 21 | 16F0E6831EA4CAC500365603 /* libhedrot_calibration.h in Headers */ = {isa = PBXBuildFile; fileRef = 16F0E6811EA4CAC500365603 /* libhedrot_calibration.h */; }; 22 | 16F0E6861EA4CB6F00365603 /* libhedrot_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 16F0E6841EA4CB6F00365603 /* libhedrot_utils.c */; }; 23 | 16F0E6871EA4CB6F00365603 /* libhedrot_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 16F0E6851EA4CB6F00365603 /* libhedrot_utils.h */; }; 24 | 16F55E0E1EBDAC4800253AEB /* libhedrot_RTmagCalibration.c in Sources */ = {isa = PBXBuildFile; fileRef = 16F55E0C1EBDAC4800253AEB /* libhedrot_RTmagCalibration.c */; }; 25 | 16F55E0F1EBDAC4800253AEB /* libhedrot_RTmagCalibration.h in Headers */ = {isa = PBXBuildFile; fileRef = 16F55E0D1EBDAC4800253AEB /* libhedrot_RTmagCalibration.h */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 1629E7D21DCBBC70006ACD46 /* hedrot_comm_protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hedrot_comm_protocol.h; sourceTree = ""; }; 30 | 16609A3C1A362064003CC1DC /* hedrot_receiver.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = hedrot_receiver.xcconfig; sourceTree = ""; }; 31 | 166427341E9F949D0081EE9E /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = ""; }; 32 | 167539AC1EA3A0F60062BDCE /* commonsyms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = commonsyms.c; path = "../../../../SDKs/MaxSDK-6.1.4/c74support/max-includes/common/commonsyms.c"; sourceTree = ""; }; 33 | 16904B081EACA9F100517871 /* JitterAPI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JitterAPI.framework; path = "../../../../SDKs/MaxSDK-6.1.4/c74support/jit-includes/JitterAPI.framework"; sourceTree = ""; }; 34 | 16904B0A1EACBE1D00517871 /* MaxAudioAPI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MaxAudioAPI.framework; path = "../../../../SDKs/MaxSDK-6.1.4/c74support/msp-includes/MaxAudioAPI.framework"; sourceTree = ""; }; 35 | 1695F0041A87997F00708733 /* hedrot_receiver.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hedrot_receiver.c; path = ../source/hedrot_receiver.c; sourceTree = ""; }; 36 | 16B2FC6F1DC9F69B003EECB3 /* libhedrot_serialcomm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libhedrot_serialcomm.c; sourceTree = ""; }; 37 | 16B2FC701DC9F69B003EECB3 /* libhedrot_serialcomm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libhedrot_serialcomm.h; sourceTree = ""; }; 38 | 16B2FC711DC9F69B003EECB3 /* libhedrot.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libhedrot.c; sourceTree = ""; }; 39 | 16B2FC721DC9F69B003EECB3 /* libhedrot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libhedrot.h; sourceTree = ""; }; 40 | 16B6BF111E193823009E5E99 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | 16DD60A41A5A7879005AE0FF /* hedrot_receiver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = hedrot_receiver.h; path = ../source/hedrot_receiver.h; sourceTree = ""; }; 42 | 16F0E6801EA4CAC500365603 /* libhedrot_calibration.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libhedrot_calibration.c; sourceTree = ""; }; 43 | 16F0E6811EA4CAC500365603 /* libhedrot_calibration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libhedrot_calibration.h; sourceTree = ""; }; 44 | 16F0E6841EA4CB6F00365603 /* libhedrot_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libhedrot_utils.c; sourceTree = ""; }; 45 | 16F0E6851EA4CB6F00365603 /* libhedrot_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libhedrot_utils.h; sourceTree = ""; }; 46 | 16F55E0C1EBDAC4800253AEB /* libhedrot_RTmagCalibration.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libhedrot_RTmagCalibration.c; sourceTree = ""; }; 47 | 16F55E0D1EBDAC4800253AEB /* libhedrot_RTmagCalibration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libhedrot_RTmagCalibration.h; sourceTree = ""; }; 48 | 2FBBEAE508F335360078DB84 /* hedrot_receiver.mxo */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = hedrot_receiver.mxo; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | 2FBBEADC08F335360078DB84 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | 16904B0B1EACBE1D00517871 /* MaxAudioAPI.framework in Frameworks */, 57 | 166427351E9F949D0081EE9E /* Accelerate.framework in Frameworks */, 58 | 16904B091EACA9F100517871 /* JitterAPI.framework in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 089C166AFE841209C02AAC07 /* iterator */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 16904B071EACA9D300517871 /* Frameworks */, 69 | 16B6BF111E193823009E5E99 /* Info.plist */, 70 | 1629E7D11DCBBC61006ACD46 /* hedrot-firmware */, 71 | 16B2FC6E1DC9F68E003EECB3 /* libhedrot */, 72 | 1695F0041A87997F00708733 /* hedrot_receiver.c */, 73 | 16DD60A41A5A7879005AE0FF /* hedrot_receiver.h */, 74 | 167539AC1EA3A0F60062BDCE /* commonsyms.c */, 75 | 16609A3C1A362064003CC1DC /* hedrot_receiver.xcconfig */, 76 | 19C28FB4FE9D528D11CA2CBB /* Products */, 77 | ); 78 | name = iterator; 79 | sourceTree = ""; 80 | }; 81 | 1629E7D11DCBBC61006ACD46 /* hedrot-firmware */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 1629E7D21DCBBC70006ACD46 /* hedrot_comm_protocol.h */, 85 | ); 86 | name = "hedrot-firmware"; 87 | path = "../../firmware/hedrot-firmware"; 88 | sourceTree = SOURCE_ROOT; 89 | }; 90 | 16904B071EACA9D300517871 /* Frameworks */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 16904B0A1EACBE1D00517871 /* MaxAudioAPI.framework */, 94 | 16904B081EACA9F100517871 /* JitterAPI.framework */, 95 | 166427341E9F949D0081EE9E /* Accelerate.framework */, 96 | ); 97 | name = Frameworks; 98 | sourceTree = ""; 99 | }; 100 | 16B2FC6E1DC9F68E003EECB3 /* libhedrot */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 16B2FC711DC9F69B003EECB3 /* libhedrot.c */, 104 | 16B2FC721DC9F69B003EECB3 /* libhedrot.h */, 105 | 16F0E6801EA4CAC500365603 /* libhedrot_calibration.c */, 106 | 16F0E6811EA4CAC500365603 /* libhedrot_calibration.h */, 107 | 16B2FC6F1DC9F69B003EECB3 /* libhedrot_serialcomm.c */, 108 | 16B2FC701DC9F69B003EECB3 /* libhedrot_serialcomm.h */, 109 | 16F0E6841EA4CB6F00365603 /* libhedrot_utils.c */, 110 | 16F0E6851EA4CB6F00365603 /* libhedrot_utils.h */, 111 | 16F55E0C1EBDAC4800253AEB /* libhedrot_RTmagCalibration.c */, 112 | 16F55E0D1EBDAC4800253AEB /* libhedrot_RTmagCalibration.h */, 113 | ); 114 | name = libhedrot; 115 | path = ../../libhedrot; 116 | sourceTree = ""; 117 | }; 118 | 19C28FB4FE9D528D11CA2CBB /* Products */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 2FBBEAE508F335360078DB84 /* hedrot_receiver.mxo */, 122 | ); 123 | name = Products; 124 | sourceTree = ""; 125 | }; 126 | /* End PBXGroup section */ 127 | 128 | /* Begin PBXHeadersBuildPhase section */ 129 | 2FBBEAD708F335360078DB84 /* Headers */ = { 130 | isa = PBXHeadersBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | 1629E7D31DCBBC70006ACD46 /* hedrot_comm_protocol.h in Headers */, 134 | 16F0E6831EA4CAC500365603 /* libhedrot_calibration.h in Headers */, 135 | 16B2FC761DC9F69B003EECB3 /* libhedrot.h in Headers */, 136 | 16F0E6871EA4CB6F00365603 /* libhedrot_utils.h in Headers */, 137 | 16B2FC741DC9F69B003EECB3 /* libhedrot_serialcomm.h in Headers */, 138 | 16F55E0F1EBDAC4800253AEB /* libhedrot_RTmagCalibration.h in Headers */, 139 | ); 140 | runOnlyForDeploymentPostprocessing = 0; 141 | }; 142 | /* End PBXHeadersBuildPhase section */ 143 | 144 | /* Begin PBXNativeTarget section */ 145 | 2FBBEAD608F335360078DB84 /* max-external */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = 2FBBEAE008F335360078DB84 /* Build configuration list for PBXNativeTarget "max-external" */; 148 | buildPhases = ( 149 | 2FBBEAD708F335360078DB84 /* Headers */, 150 | 2FBBEAD808F335360078DB84 /* Resources */, 151 | 2FBBEADA08F335360078DB84 /* Sources */, 152 | 2FBBEADC08F335360078DB84 /* Frameworks */, 153 | 2FBBEADF08F335360078DB84 /* Rez */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = "max-external"; 160 | productName = iterator; 161 | productReference = 2FBBEAE508F335360078DB84 /* hedrot_receiver.mxo */; 162 | productType = "com.apple.product-type.bundle"; 163 | }; 164 | /* End PBXNativeTarget section */ 165 | 166 | /* Begin PBXProject section */ 167 | 089C1669FE841209C02AAC07 /* Project object */ = { 168 | isa = PBXProject; 169 | attributes = { 170 | LastUpgradeCheck = 0820; 171 | }; 172 | buildConfigurationList = 2FBBEACF08F335010078DB84 /* Build configuration list for PBXProject "hedrot_receiver" */; 173 | compatibilityVersion = "Xcode 3.2"; 174 | developmentRegion = English; 175 | hasScannedForEncodings = 1; 176 | knownRegions = ( 177 | en, 178 | ); 179 | mainGroup = 089C166AFE841209C02AAC07 /* iterator */; 180 | projectDirPath = ""; 181 | projectRoot = ""; 182 | targets = ( 183 | 2FBBEAD608F335360078DB84 /* max-external */, 184 | ); 185 | }; 186 | /* End PBXProject section */ 187 | 188 | /* Begin PBXResourcesBuildPhase section */ 189 | 2FBBEAD808F335360078DB84 /* Resources */ = { 190 | isa = PBXResourcesBuildPhase; 191 | buildActionMask = 2147483647; 192 | files = ( 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | }; 196 | /* End PBXResourcesBuildPhase section */ 197 | 198 | /* Begin PBXRezBuildPhase section */ 199 | 2FBBEADF08F335360078DB84 /* Rez */ = { 200 | isa = PBXRezBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | /* End PBXRezBuildPhase section */ 207 | 208 | /* Begin PBXSourcesBuildPhase section */ 209 | 2FBBEADA08F335360078DB84 /* Sources */ = { 210 | isa = PBXSourcesBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | 1695F0051A87997F00708733 /* hedrot_receiver.c in Sources */, 214 | 16B2FC731DC9F69B003EECB3 /* libhedrot_serialcomm.c in Sources */, 215 | 167539AD1EA3A0F60062BDCE /* commonsyms.c in Sources */, 216 | 16F0E6861EA4CB6F00365603 /* libhedrot_utils.c in Sources */, 217 | 16B2FC751DC9F69B003EECB3 /* libhedrot.c in Sources */, 218 | 16F55E0E1EBDAC4800253AEB /* libhedrot_RTmagCalibration.c in Sources */, 219 | 16F0E6821EA4CAC500365603 /* libhedrot_calibration.c in Sources */, 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | }; 223 | /* End PBXSourcesBuildPhase section */ 224 | 225 | /* Begin XCBuildConfiguration section */ 226 | 2FBBEAD008F335010078DB84 /* Development */ = { 227 | isa = XCBuildConfiguration; 228 | baseConfigurationReference = 16609A3C1A362064003CC1DC /* hedrot_receiver.xcconfig */; 229 | buildSettings = { 230 | CLANG_WARN_BOOL_CONVERSION = YES; 231 | CLANG_WARN_CONSTANT_CONVERSION = YES; 232 | CLANG_WARN_EMPTY_BODY = YES; 233 | CLANG_WARN_ENUM_CONVERSION = YES; 234 | CLANG_WARN_INFINITE_RECURSION = YES; 235 | CLANG_WARN_INT_CONVERSION = YES; 236 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 237 | CLANG_WARN_UNREACHABLE_CODE = YES; 238 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 239 | ENABLE_STRICT_OBJC_MSGSEND = YES; 240 | ENABLE_TESTABILITY = YES; 241 | GCC_NO_COMMON_BLOCKS = YES; 242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 243 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 244 | GCC_WARN_UNDECLARED_SELECTOR = YES; 245 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 246 | GCC_WARN_UNUSED_FUNCTION = YES; 247 | GCC_WARN_UNUSED_VARIABLE = YES; 248 | ONLY_ACTIVE_ARCH = NO; 249 | SDKROOT = macosx10.9; 250 | }; 251 | name = Development; 252 | }; 253 | 2FBBEAD108F335010078DB84 /* Deployment */ = { 254 | isa = XCBuildConfiguration; 255 | baseConfigurationReference = 16609A3C1A362064003CC1DC /* hedrot_receiver.xcconfig */; 256 | buildSettings = { 257 | CLANG_WARN_BOOL_CONVERSION = YES; 258 | CLANG_WARN_CONSTANT_CONVERSION = YES; 259 | CLANG_WARN_EMPTY_BODY = YES; 260 | CLANG_WARN_ENUM_CONVERSION = YES; 261 | CLANG_WARN_INFINITE_RECURSION = YES; 262 | CLANG_WARN_INT_CONVERSION = YES; 263 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 264 | CLANG_WARN_UNREACHABLE_CODE = YES; 265 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_NO_COMMON_BLOCKS = YES; 268 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 269 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 270 | GCC_WARN_UNDECLARED_SELECTOR = YES; 271 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 272 | GCC_WARN_UNUSED_FUNCTION = YES; 273 | GCC_WARN_UNUSED_VARIABLE = YES; 274 | ONLY_ACTIVE_ARCH = NO; 275 | SDKROOT = macosx10.9; 276 | }; 277 | name = Deployment; 278 | }; 279 | 2FBBEAE108F335360078DB84 /* Development */ = { 280 | isa = XCBuildConfiguration; 281 | baseConfigurationReference = 16609A3C1A362064003CC1DC /* hedrot_receiver.xcconfig */; 282 | buildSettings = { 283 | COMBINE_HIDPI_IMAGES = YES; 284 | COPY_PHASE_STRIP = NO; 285 | FRAMEWORK_SEARCH_PATHS = ( 286 | "$(inherited)", 287 | "/Volumes/Data/Developpement/SDKs/MaxSDK-6.1.4/c74support/jit-includes", 288 | "/Volumes/Data/Developpement/SDKs/MaxSDK-6.1.4/c74support/msp-includes", 289 | ); 290 | GCC_OPTIMIZATION_LEVEL = 0; 291 | INFOPLIST_PREFIX_HEADER = ""; 292 | INFOPLIST_PREPROCESS = NO; 293 | OTHER_LDFLAGS = "$(C74_SYM_LINKER_FLAGS)"; 294 | PRODUCT_BUNDLE_IDENTIFIER = "com.hedrot.${PRODUCT_NAME:rfc1034identifier}"; 295 | PRODUCT_NAME = hedrot_receiver; 296 | }; 297 | name = Development; 298 | }; 299 | 2FBBEAE208F335360078DB84 /* Deployment */ = { 300 | isa = XCBuildConfiguration; 301 | baseConfigurationReference = 16609A3C1A362064003CC1DC /* hedrot_receiver.xcconfig */; 302 | buildSettings = { 303 | COMBINE_HIDPI_IMAGES = YES; 304 | COPY_PHASE_STRIP = YES; 305 | FRAMEWORK_SEARCH_PATHS = ( 306 | "$(inherited)", 307 | "/Volumes/Data/Developpement/SDKs/MaxSDK-6.1.4/c74support/jit-includes", 308 | "/Volumes/Data/Developpement/SDKs/MaxSDK-6.1.4/c74support/msp-includes", 309 | ); 310 | INFOPLIST_PREFIX_HEADER = ""; 311 | INFOPLIST_PREPROCESS = NO; 312 | OTHER_LDFLAGS = "$(C74_SYM_LINKER_FLAGS)"; 313 | PRODUCT_BUNDLE_IDENTIFIER = "com.hedrot.${PRODUCT_NAME:rfc1034identifier}"; 314 | PRODUCT_NAME = hedrot_receiver; 315 | }; 316 | name = Deployment; 317 | }; 318 | /* End XCBuildConfiguration section */ 319 | 320 | /* Begin XCConfigurationList section */ 321 | 2FBBEACF08F335010078DB84 /* Build configuration list for PBXProject "hedrot_receiver" */ = { 322 | isa = XCConfigurationList; 323 | buildConfigurations = ( 324 | 2FBBEAD008F335010078DB84 /* Development */, 325 | 2FBBEAD108F335010078DB84 /* Deployment */, 326 | ); 327 | defaultConfigurationIsVisible = 0; 328 | defaultConfigurationName = Development; 329 | }; 330 | 2FBBEAE008F335360078DB84 /* Build configuration list for PBXNativeTarget "max-external" */ = { 331 | isa = XCConfigurationList; 332 | buildConfigurations = ( 333 | 2FBBEAE108F335360078DB84 /* Development */, 334 | 2FBBEAE208F335360078DB84 /* Deployment */, 335 | ); 336 | defaultConfigurationIsVisible = 0; 337 | defaultConfigurationName = Development; 338 | }; 339 | /* End XCConfigurationList section */ 340 | }; 341 | rootObject = 089C1669FE841209C02AAC07 /* Project object */; 342 | } 343 | --------------------------------------------------------------------------------