I have been trying to compile a code for a accelerometer which is avaiable from two sources but referring to the same code on github:
https://github.com/ayildirim/OpenVR
https://github.com/ptrbrtz/razor-9dof-ahrs/
Both of this sources contain the following arduino code(c++):
#define HW__VERSION_CODE 10736 // SparkFun "9DOF Razor IMU" version "SEN-10736" (HMC5883L magnetometer)
// OUTPUT OPTIONS
/*****************************************************************/
// Set your serial port baud rate used to send out data here!
#define OUTPUT__BAUD_RATE 57600
// Sensor data output interval in milliseconds
// This may not work, if faster than 20ms (=50Hz)
// Code is tuned for 20ms, so better leave it like that
#define OUTPUT__DATA_INTERVAL 20 // in milliseconds
// Output mode definitions (do not change)
#define OUTPUT__MODE_CALIBRATE_SENSORS 0 // Outputs sensor min/max values as text for manual calibration
#define OUTPUT__MODE_ANGLES 1 // Outputs yaw/pitch/roll in degrees
#define OUTPUT__MODE_SENSORS_CALIB 2 // Outputs calibrated sensor values for all 9 axes
#define OUTPUT__MODE_SENSORS_RAW 3 // Outputs raw (uncalibrated) sensor values for all 9 axes
#define OUTPUT__MODE_SENSORS_BOTH 4 // Outputs calibrated AND raw sensor values for all 9 axes
// Output format definitions (do not change)
#define OUTPUT__FORMAT_TEXT 0 // Outputs data as text
#define OUTPUT__FORMAT_BINARY 1 // Outputs data as binary float
// Select your startup output mode and format here!
int output_mode = OUTPUT__MODE_ANGLES;
int output_format = OUTPUT__FORMAT_TEXT;
// Select if serial continuous streaming output is enabled per default on startup.
#define OUTPUT__STARTUP_STREAM_ON true // true or false
// If set true, an error message will be output if we fail to read sensor data.
// Message format: "!ERR: reading <sensor>", followed by "\r\n".
boolean output_errors = false; // true or false
// Bluetooth
// You can set this to true, if you have a Rovering Networks Bluetooth Module attached.
// The connect/disconnect message prefix of the module has to be set to "#".
// (Refer to manual, it can be set like this: SO,#)
// When using this, streaming output will only be enabled as long as we're connected. That way
// receiver and sender are synchronzed easily just by connecting/disconnecting.
// It is not necessary to set this! It just makes life easier when writing code for
// the receiving side. The Processing test sketch also works without setting this.
// NOTE: When using this, OUTPUT__STARTUP_STREAM_ON has no effect!
#define OUTPUT__HAS_RN_BLUETOOTH false // true or false
// SENSOR CALIBRATION
/*****************************************************************/
// How to calibrate? Read the tutorial at http://dev.qu.tu-berlin.de/projects/sf-razor-9dof-ahrs
// Put MIN/MAX and OFFSET readings for your board here!
// Accelerometer
// "accel x,y,z (min/max) = X_MIN/X_MAX Y_MIN/Y_MAX Z_MIN/Z_MAX"
#define ACCEL_X_MIN ((float) -289)
#define ACCEL_X_MAX ((float) 294)
#define ACCEL_Y_MIN ((float) -268)
#define ACCEL_Y_MAX ((float) 288)
#define ACCEL_Z_MIN ((float) -294)
#define ACCEL_Z_MAX ((float) 269)
// Magnetometer (standard calibration)
// "magn x,y,z (min/max) = X_MIN/X_MAX Y_MIN/Y_MAX Z_MIN/Z_MAX"
//#define MAGN_X_MIN ((float) -600)
//#define MAGN_X_MAX ((float) 600)
//#define MAGN_Y_MIN ((float) -600)
//#define MAGN_Y_MAX ((float) 600)
//#define MAGN_Z_MIN ((float) -600)
//#define MAGN_Z_MAX ((float) 600)
// Magnetometer (extended calibration)
// Uncommend to use extended magnetometer calibration (compensates hard & soft iron errors)
#define CALIBRATION__MAGN_USE_EXTENDED true
const float magn_ellipsoid_center[3] = {
3.80526, -16.4455, 87.4052};
const float magn_ellipsoid_transform[3][3] = {
{
0.970991, 0.00583310, -0.00265756 }
, {
0.00583310, 0.952958, 2.76726e-05 }
, {
-0.00265756, 2.76726e-05, 0.999751 }
};
// Gyroscope
// "gyro x,y,z (current/average) = .../OFFSET_X .../OFFSET_Y .../OFFSET_Z
#define GYRO_AVERAGE_OFFSET_X ((float) 23.85)
#define GYRO_AVERAGE_OFFSET_Y ((float) -53.41)
#define GYRO_AVERAGE_OFFSET_Z ((float) -15.32)
/*
// Calibration example:
// "accel x,y,z (min/max) = -278.00/270.00 -254.00/284.00 -294.00/235.00"
#define ACCEL_X_MIN ((float) -278)
#define ACCEL_X_MAX ((float) 270)
#define ACCEL_Y_MIN ((float) -254)
#define ACCEL_Y_MAX ((float) 284)
#define ACCEL_Z_MIN ((float) -294)
#define ACCEL_Z_MAX ((float) 235)
// "magn x,y,z (min/max) = -511.00/581.00 -516.00/568.00 -489.00/486.00"
//#define MAGN_X_MIN ((float) -511)
//#define MAGN_X_MAX ((float) 581)
//#define MAGN_Y_MIN ((float) -516)
//#define MAGN_Y_MAX ((float) 568)
//#define MAGN_Z_MIN ((float) -489)
//#define MAGN_Z_MAX ((float) 486)
// Extended magn
#define CALIBRATION__MAGN_USE_EXTENDED true
const float magn_ellipsoid_center[3] = {91.5, -13.5, -48.1};
const float magn_ellipsoid_transform[3][3] = {{0.902, -0.00354, 0.000636}, {-0.00354, 0.9, -0.00599}, {0.000636, -0.00599, 1}};
// Extended magn (with Sennheiser HD 485 headphones)
//#define CALIBRATION__MAGN_USE_EXTENDED true
//const float magn_ellipsoid_center[3] = {72.3360, 23.0954, 53.6261};
//const float magn_ellipsoid_transform[3][3] = {{0.879685, 0.000540833, -0.0106054}, {0.000540833, 0.891086, -0.0130338}, {-0.0106054, -0.0130338, 0.997494}};
//"gyro x,y,z (current/average) = -32.00/-34.82 102.00/100.41 -16.00/-16.38"
#define GYRO_AVERAGE_OFFSET_X ((float) -34.82)
#define GYRO_AVERAGE_OFFSET_Y ((float) 100.41)
#define GYRO_AVERAGE_OFFSET_Z ((float) -16.38)
*/
// DEBUG OPTIONS
/*****************************************************************/
// When set to true, gyro drift correction will not be applied
#define DEBUG__NO_DRIFT_CORRECTION false
// Print elapsed time after each I/O loop
#define DEBUG__PRINT_LOOP_TIME false
/*****************************************************************/
/****************** END OF USER SETUP AREA! *********************/
/*****************************************************************/
// Check if hardware version code is defined
#ifndef HW__VERSION_CODE
// Generate compile error
#error YOU HAVE TO SELECT THE HARDWARE YOU ARE USING! See "HARDWARE OPTIONS" in "USER SETUP AREA" at top of Razor_AHRS.pde (or .ino)!
#endif
#include <Wire.h>
#include <Compass.h>
#include <DCM.h>
#include <Math.h>
#include <Output.h>
#include <Sensors.h>
// Sensor calibration scale and offset values
#define ACCEL_X_OFFSET ((ACCEL_X_MIN + ACCEL_X_MAX) / 2.0f)
#define ACCEL_Y_OFFSET ((ACCEL_Y_MIN + ACCEL_Y_MAX) / 2.0f)
#define ACCEL_Z_OFFSET ((ACCEL_Z_MIN + ACCEL_Z_MAX) / 2.0f)
#define ACCEL_X_SCALE (GRAVITY / (ACCEL_X_MAX - ACCEL_X_OFFSET))
#define ACCEL_Y_SCALE (GRAVITY / (ACCEL_Y_MAX - ACCEL_Y_OFFSET))
#define ACCEL_Z_SCALE (GRAVITY / (ACCEL_Z_MAX - ACCEL_Z_OFFSET))
#define MAGN_X_OFFSET ((MAGN_X_MIN + MAGN_X_MAX) / 2.0f)
#define MAGN_Y_OFFSET ((MAGN_Y_MIN + MAGN_Y_MAX) / 2.0f)
#define MAGN_Z_OFFSET ((MAGN_Z_MIN + MAGN_Z_MAX) / 2.0f)
#define MAGN_X_SCALE (100.0f / (MAGN_X_MAX - MAGN_X_OFFSET))
#define MAGN_Y_SCALE (100.0f / (MAGN_Y_MAX - MAGN_Y_OFFSET))
#define MAGN_Z_SCALE (100.0f / (MAGN_Z_MAX - MAGN_Z_OFFSET))
// Gain for gyroscope (ITG-3200)
#define GYRO_GAIN 0.06957 // Same gain on all axes
#define GYRO_SCALED_RAD(x) (x * TO_RAD(GYRO_GAIN)) // Calculate the scaled gyro readings in radians per second
// DCM parameters
#define Kp_ROLLPITCH 0.02f
#define Ki_ROLLPITCH 0.00002f
#define Kp_YAW 1.2f
#define Ki_YAW 0.00002f
// Stuff
#define STATUS_LED_PIN 13 // Pin number of status LED
#define GRAVITY 256.0f // "1G reference" used for DCM filter and accelerometer calibration
#define TO_RAD(x) (x * 0.01745329252) // *pi/180
#define TO_DEG(x) (x * 57.2957795131) // *180/pi
// Sensor variables
float accel[3]; // Actually stores the NEGATED acceleration (equals gravity, if board not moving).
float accel_min[3];
float accel_max[3];
float magnetom[3];
float magnetom_min[3];
float magnetom_max[3];
float magnetom_tmp[3];
float gyro[3];
float gyro_average[3];
int gyro_num_samples = 0;
// DCM variables
float MAG_Heading;
float Accel_Vector[3]= {
0, 0, 0}; // Store the acceleration in a vector
float Gyro_Vector[3]= {
0, 0, 0}; // Store the gyros turn rate in a vector
float Omega_Vector[3]= {
0, 0, 0}; // Corrected Gyro_Vector data
float Omega_P[3]= {
0, 0, 0}; // Omega Proportional correction
float Omega_I[3]= {
0, 0, 0}; // Omega Integrator
float Omega[3]= {
0, 0, 0};
float errorRollPitch[3] = {
0, 0, 0};
float errorYaw[3] = {
0, 0, 0};
float DCM_Matrix[3][3] = {
{
1, 0, 0 }
, {
0, 1, 0 }
, {
0, 0, 1 }
};
float Update_Matrix[3][3] = {
{
0, 1, 2 }
, {
3, 4, 5 }
, {
6, 7, 8 }
};
float Temporary_Matrix[3][3] = {
{
0, 0, 0 }
, {
0, 0, 0 }
, {
0, 0, 0 }
};
// Euler angles
float yaw;
float pitch;
float roll;
// DCM timing in the main loop
unsigned long timestamp;
unsigned long timestamp_old;
float G_Dt; // Integration time for DCM algorithm
// More output-state variables
boolean output_stream_on;
boolean output_single_on;
int curr_calibration_sensor = 0;
boolean reset_calibration_session_flag = true;
int num_accel_errors = 0;
int num_magn_errors = 0;
int num_gyro_errors = 0;
void read_sensors() {
Read_Gyro(); // Read gyroscope
Read_Accel(); // Read accelerometer
Read_Magn(); // Read magnetometer
}
// Read every sensor and record a time stamp
// Init DCM with unfiltered orientation
// TODO re-init global vars?
void reset_sensor_fusion() {
float temp1[3];
float temp2[3];
float xAxis[] = {
1.0f, 0.0f, 0.0f };
read_sensors();
timestamp = millis();
// GET PITCH
// Using y-z-plane-component/x-component of gravity vector
pitch = -atan2(accel[0], sqrt(accel[1] * accel[1] + accel[2] * accel[2]));
// GET ROLL
// Compensate pitch of gravity vector
Vector_Cross_Product(temp1, accel, xAxis);
Vector_Cross_Product(temp2, xAxis, temp1);
// Normally using x-z-plane-component/y-component of compensated gravity vector
// roll = atan2(temp2[1], sqrt(temp2[0] * temp2[0] + temp2[2] * temp2[2]));
// Since we compensated for pitch, x-z-plane-component equals z-component:
roll = atan2(temp2[1], temp2[2]);
// GET YAW
Compass_Heading();
yaw = MAG_Heading;
// Init rotation matrix
init_rotation_matrix(DCM_Matrix, yaw, pitch, roll);
}
// Apply calibration to raw sensor readings
void compensate_sensor_errors() {
// Compensate accelerometer error
accel[0] = (accel[0] - ACCEL_X_OFFSET) * ACCEL_X_SCALE;
accel[1] = (accel[1] - ACCEL_Y_OFFSET) * ACCEL_Y_SCALE;
accel[2] = (accel[2] - ACCEL_Z_OFFSET) * ACCEL_Z_SCALE;
// Compensate magnetometer error
#if CALIBRATION__MAGN_USE_EXTENDED == true
for (int i = 0; i < 3; i++)
magnetom_tmp[i] = magnetom[i] - magn_ellipsoid_center[i];
Matrix_Vector_Multiply(magn_ellipsoid_transform, magnetom_tmp, magnetom);
#else
magnetom[0] = (magnetom[0] - MAGN_X_OFFSET) * MAGN_X_SCALE;
magnetom[1] = (magnetom[1] - MAGN_Y_OFFSET) * MAGN_Y_SCALE;
magnetom[2] = (magnetom[2] - MAGN_Z_OFFSET) * MAGN_Z_SCALE;
#endif
// Compensate gyroscope error
gyro[0] -= GYRO_AVERAGE_OFFSET_X;
gyro[1] -= GYRO_AVERAGE_OFFSET_Y;
gyro[2] -= GYRO_AVERAGE_OFFSET_Z;
}
// Reset calibration session if reset_calibration_session_flag is set
void check_reset_calibration_session()
{
// Raw sensor values have to be read already, but no error compensation applied
// Reset this calibration session?
if (!reset_calibration_session_flag) return;
// Reset acc and mag calibration variables
for (int i = 0; i < 3; i++) {
accel_min[i] = accel_max[i] = accel[i];
magnetom_min[i] = magnetom_max[i] = magnetom[i];
}
// Reset gyro calibration variables
gyro_num_samples = 0; // Reset gyro calibration averaging
gyro_average[0] = gyro_average[1] = gyro_average[2] = 0.0f;
reset_calibration_session_flag = false;
}
void turn_output_stream_on()
{
output_stream_on = true;
digitalWrite(STATUS_LED_PIN, HIGH);
}
void turn_output_stream_off()
{
output_stream_on = false;
digitalWrite(STATUS_LED_PIN, LOW);
}
// Blocks until another byte is available on serial port
char readChar()
{
while (Serial.available() < 1) {
} // Block
return Serial.read();
}
void setup()
{
// Init serial output
Serial.begin(OUTPUT__BAUD_RATE);
// Init status LED
pinMode (STATUS_LED_PIN, OUTPUT);
digitalWrite(STATUS_LED_PIN, LOW);
// Init sensors
delay(50); // Give sensors enough time to start
I2C_Init();
Accel_Init();
Magn_Init();
Gyro_Init();
// Read sensors, init DCM algorithm
delay(20); // Give sensors enough time to collect data
reset_sensor_fusion();
// Init output
#if (OUTPUT__HAS_RN_BLUETOOTH == true) || (OUTPUT__STARTUP_STREAM_ON == false)
turn_output_stream_off();
#else
turn_output_stream_on();
#endif
}
// Main loop
void loop()
{
// Read incoming control messages
if (Serial.available() >= 2)
{
if (Serial.read() == '#') // Start of new control message
{
int command = Serial.read(); // Commands
if (command == 'f') // request one output _f_rame
output_single_on = true;
else if (command == 's') // _s_ynch request
{
// Read ID
byte id[2];
id[0] = readChar();
id[1] = readChar();
// Reply with synch message
Serial.print("#SYNCH");
Serial.write(id, 2);
Serial.println();
}
else if (command == 'o') // Set _o_utput mode
{
char output_param = readChar();
if (output_param == 'n') // Calibrate _n_ext sensor
{
curr_calibration_sensor = (curr_calibration_sensor + 1) % 3;
reset_calibration_session_flag = true;
}
else if (output_param == 't') // Output angles as _t_ext
{
output_mode = OUTPUT__MODE_ANGLES;
output_format = OUTPUT__FORMAT_TEXT;
}
else if (output_param == 'b') // Output angles in _b_inary format
{
output_mode = OUTPUT__MODE_ANGLES;
output_format = OUTPUT__FORMAT_BINARY;
}
else if (output_param == 'c') // Go to _c_alibration mode
{
output_mode = OUTPUT__MODE_CALIBRATE_SENSORS;
reset_calibration_session_flag = true;
}
else if (output_param == 's') // Output _s_ensor values
{
char values_param = readChar();
char format_param = readChar();
if (values_param == 'r') // Output _r_aw sensor values
output_mode = OUTPUT__MODE_SENSORS_RAW;
else if (values_param == 'c') // Output _c_alibrated sensor values
output_mode = OUTPUT__MODE_SENSORS_CALIB;
else if (values_param == 'b') // Output _b_oth sensor values (raw and calibrated)
output_mode = OUTPUT__MODE_SENSORS_BOTH;
if (format_param == 't') // Output values as _t_text
output_format = OUTPUT__FORMAT_TEXT;
else if (format_param == 'b') // Output values in _b_inary format
output_format = OUTPUT__FORMAT_BINARY;
}
else if (output_param == '0') // Disable continuous streaming output
{
turn_output_stream_off();
reset_calibration_session_flag = true;
}
else if (output_param == '1') // Enable continuous streaming output
{
reset_calibration_session_flag = true;
turn_output_stream_on();
}
else if (output_param == 'e') // _e_rror output settings
{
char error_param = readChar();
if (error_param == '0') output_errors = false;
else if (error_param == '1') output_errors = true;
else if (error_param == 'c') // get error count
{
Serial.print("#AMG-ERR:");
Serial.print(num_accel_errors);
Serial.print(",");
Serial.print(num_magn_errors);
Serial.print(",");
Serial.println(num_gyro_errors);
}
}
}
#if OUTPUT__HAS_RN_BLUETOOTH == true
// Read messages from bluetooth module
// For this to work, the connect/disconnect message prefix of the module has to be set to "#".
else if (command == 'C') // Bluetooth "#CONNECT" message (does the same as "#o1")
turn_output_stream_on();
else if (command == 'D') // Bluetooth "#DISCONNECT" message (does the same as "#o0")
turn_output_stream_off();
#endif // OUTPUT__HAS_RN_BLUETOOTH == true
}
else
{
} // Skip character
}
// Time to read the sensors again?
if((millis() - timestamp) >= OUTPUT__DATA_INTERVAL)
{
timestamp_old = timestamp;
timestamp = millis();
if (timestamp > timestamp_old)
G_Dt = (float) (timestamp - timestamp_old) / 1000.0f; // Real time of loop run. We use this on the DCM algorithm (gyro integration time)
else G_Dt = 0;
// Update sensor readings
read_sensors();
if (output_mode == OUTPUT__MODE_CALIBRATE_SENSORS) // We're in calibration mode
{
check_reset_calibration_session(); // Check if this session needs a reset
if (output_stream_on || output_single_on) output_calibration(curr_calibration_sensor);
}
else if (output_mode == OUTPUT__MODE_ANGLES) // Output angles
{
// Apply sensor calibration
compensate_sensor_errors();
// Run DCM algorithm
Compass_Heading(); // Calculate magnetic heading
Matrix_update();
Normalize();
Drift_correction();
Euler_angles();
if (output_stream_on || output_single_on) output_angles();
}
else // Output sensor values
{
if (output_stream_on || output_single_on) output_sensors();
}
output_single_on = false;
#if DEBUG__PRINT_LOOP_TIME == true
Serial.print("loop time (ms) = ");
Serial.println(millis() - timestamp);
#endif
}
#if DEBUG__PRINT_LOOP_TIME == true
else
{
Serial.println("waiting...");
}
#endif
}
And well, the code only includes the library which is for I2C communication, but there are 5 more files (.ino which is simply an .cpp) that have few functions being declared.
By just simply trying to compile the code, the following error is given:
Final_arduino_code.ino: In function ‘void read_sensors()’:
Final_arduino_code:427: error: ‘Read_Gyro’ was not declared in this scope
Final_arduino_code:428: error: ‘Read_Accel’ was not declared in this scope
Final_arduino_code:429: error: ‘Read_Magn’ was not declared in this scope
Final_arduino_code.ino: In function ‘void reset_sensor_fusion()’:
Final_arduino_code:450: error: ‘Vector_Cross_Product’ was not declared in this scope
Final_arduino_code:458: error: ‘Compass_Heading’ was not declared in this scope
Final_arduino_code:462: error: ‘init_rotation_matrix’ was not declared in this scope
Final_arduino_code.ino: In function ‘void compensate_sensor_errors()’:
Final_arduino_code:476: error: ‘Matrix_Vector_Multiply’ was not declared in this scope
Final_arduino_code.ino: In function ‘void setup()’:
Final_arduino_code:541: error: ‘I2C_Init’ was not declared in this scope
Final_arduino_code:542: error: ‘Accel_Init’ was not declared in this scope
Final_arduino_code:543: error: ‘Magn_Init’ was not declared in this scope
Final_arduino_code:544: error: ‘Gyro_Init’ was not declared in this scope
Final_arduino_code.ino: In function ‘void loop()’:
Final_arduino_code:675: error: ‘output_calibration’ was not declared in this scope
Final_arduino_code:683: error: ‘Compass_Heading’ was not declared in this scope
Final_arduino_code:684: error: ‘Matrix_update’ was not declared in this scope
Final_arduino_code:685: error: ‘Normalize’ was not declared in this scope
Final_arduino_code:686: error: ‘Drift_correction’ was not declared in this scope
Final_arduino_code:687: error: ‘Euler_angles’ was not declared in this scope
Final_arduino_code:689: error: ‘output_angles’ was not declared in this scope
Final_arduino_code:693: error: ‘output_sensors’ was not declared in this scope
Well, most of those functions have being declared in the other files in the same folder of the this main code, BUT, I have tried making a header (.h) to each of the files, just declaring the functions, it didn't work, I have tried including the files as they are, didn't work, tried to change them to .cpp and including, didn't work.
I posted as an issue to both of the github pages but still got no answer.
Please help me to fix these errors, thanks in advance.
but there are 5 more files (.ino which is simply an .cpp)
It is not that simple, they are not .cpp files. They are supposed to be built with the Ino toolkit, the project's home page is here. Judging from the compiler errors you get, you are not using this toolkit.
The core part that's missing are the .h files that the compiler normally needs to understand what functions like Read_Gyro() look like. Currently the projects you listed have no .h file and no corresponding #include directives. Not actually sure how Ino works but I'd guess it acts like a preprocessor that merges the .ino files into one big ball of source code before letting the compiler lose on it.
Using the toolkit is strongly recommended to get ahead and avoid substantial changes.
As I do not have enough reputation, I'll tell how the Guilherme Garcia da Rosa's answer put me on the right direction.
Unfortunately his contribution appears to be no longer valid with Arduino IDE 1.6.5
I managed to open the project this way :
1- Close Arduino IDE first
2- Create a directory named Final_arduino_code (maybe case sensitive)
3- Open Arduino IDE, and the sketch Final_arduino_code.ino
The IDE will automatically load all files.
The program uploaded successfully for me this way.
The original project owner "Ahmet YILDIRIM" replied to my problem and helped me to compile the project, this was his answer:
You know when you try opening an INO file, Arduino IDE asks you if you
would like to create a new folder for that specific file.
If you click yes, it seperates that file into a new folder.
If I remember correctly you should either press “No” then add other
files as new tabs. If you click “Yes”, then add other files into new
created folder and then open them all in new tabs.
I hope it helps
Related
This is my program:
#include "Arduino.h"
#include "MotorDriver.h"
#include "encoders.h"
//Define the global variables to configure the motors
//Right Motor Configuration Variables
int motR_pins[3] = {4, 15, 18}; //Define the Motor Pins
int motR_sign = -1; //Define the motor rotation sign
//Left Motor configuration variables
int motL_pins[3] = {2, 12, 0};
int motL_sign = 1;
//Encoders
Encoders Encr;
Encoders Encl;
int signal_R=-1;
int signal_L=1;
MotorDriver Mr;
MotorDriver Ml;
//Setup
void setup()
{
//Set up the Motors
//Setup the Right Motor object
Mr.SetBaseFreq(5000); //PWM base frequency setup
Mr.SetSign(motR_sign); //Setup motor sign
Mr.DriverSetup(motR_pins[0], 0, motR_pins[1], motR_pins[2]); //Setup motor pins and channel
Mr.MotorWrite(0); //Write 0 velocity to the motor when initialising
//Setup the Left Motor object
Ml.SetBaseFreq(5000);
Ml.SetSign(motL_sign);
Ml.DriverSetup(motL_pins[0], 1, motL_pins[1], motL_pins[2]);
Ml.MotorWrite(0);
//Encoder setup
Encr.EncodersSetup(34, 36);
Encl.EncodersSetup(35, 39);
//Begin Serial Communication
Serial.begin(9600);
}
long positionLeft = -999;
long positionRight = -999;
//Loop
void loop()
{
Mr.MotorWrite(-0.5); //Set Velocity percentage to the Motors (-1 to 1)
Ml.MotorWrite(0.4);
long newLeft, newRight;
newLeft = Encl.readenc(signal_L);
newRight = Encr.readenc(signal_R);
Serial.print("Left = ");
Serial.print(newLeft);
Serial.print(", Right = ");
Serial.print(newRight);
Serial.println();
positionLeft = newLeft;
positionRight = newRight; //Delay before next loop iteration
}
This is my library which is supposed to read the rpm values and change them to the linear values so that I can work on PID implementation later on:
#ifndef Encoders_h
#define Encoders_h
#include <Arduino.h>
class Encoders
{
private:
int PinA;
int PinB;
float current_time=0;
int sample=10;
float ticks=1632.67;
float previous_time=0;
float pinAStateCurrent = LOW;
float pinAStateLast = LOW;
float rotation = 0;
float counter = 0;
public:
Encoders();
void EncodersSetup(int A, int B)
{
PinA=A;
PinB=B;
};
float readenc(int enc_signal)
{
pinMode(PinA, INPUT);
pinMode(PinB, INPUT);
pinAStateCurrent = digitalRead(PinA);
if ((digitalRead(PinA)) == HIGH)
{
update();
}
else
{
update();
}
current_time=millis();
if (current_time-previous_time > sample)
{
rotation = (counter*enc_signal)/ticks;
rotation = (rotation * 1000) / (current_time-previous_time);
previous_time=current_time;
counter=0;
}
pinAStateLast = pinAStateCurrent;
return rotation*0.1*3.1415;
};
void update()
{
if((pinAStateLast == LOW) && (pinAStateCurrent == HIGH))
{
if (digitalRead(PinB) == HIGH)
{
counter++;
}
else
{
counter--;
}
}
};
};
#endif
I'm getting errors which I can't understand:
sketch\task2.ino.cpp.o:(.literal.startup._GLOBAL__sub_I_motR_pins+0x4): undefined reference to `Encoders::Encoders()'
sketch\task2.ino.cpp.o: In function `_GLOBAL__sub_I_motR_pins':
C:\Users\hubno\OneDrive\Pulpit\ESP - reports\TD3\task2/task2.ino:67: undefined reference to `Encoders::Encoders()'
C:\Users\hubno\OneDrive\Pulpit\ESP - reports\TD3\task2/task2.ino:17: undefined reference to `Encoders::Encoders()'
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board ESP32 Dev Module.
I can't notice anything wrong in the lines 17 and 67. The MotorDriver part should be alright since it was provided externally and it has been tested before and it proved to be working. So I guess the problem must be with my implementation of encoder library. I would be grateful for any help.
You have declared the default constructor for Encoders but not actually defined it anywhere. Either define it yourself or remove the declaration and let the compiler do it for you.
See Difference between a definition and a declaration.
You may also refer to Paul T.'s comment.
This code is not mine, but found on How To Mechatronics.
I am working on an Arduino gimbal and am using this code. It brings up an error, which I will paste at the bottom.
I searched this sort of error and it seems it is because it has an output that is negative but is not defined to come out as negative or may be too large.
I am not quite sure what to change or how to change this in order to function. I also have a problem with the yaw motor, which I believe may be fried because my brother connected it to a 12 V battery and it is only supposed to be 5 V.
I am sure I can disable the yaw (although not sure if this would solve the other issue), but I don't know which lines to code out in order to do so.
/*
DIY Gimbal - MPU6050 Arduino Tutorial
by Dejan, www.HowToMechatronics.com
Code based on the MPU6050_DMP6 example from the i2cdevlib library by Jeff Rowberg:
https://github.com/jrowberg/i2cdevlib
*/
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
#include <Servo.h>
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
// Define the 3 servo motors
Servo servo0;
Servo servo1;
Servo servo2;
float correct;
int j = 0;
#define OUTPUT_READABLE_YAWPITCHROLL
#define INTERRUPT_PIN 2 // use pin 2 on Arduino Uno & most boards
bool blinkState = false;
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00, '\r', '\n' };
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize serial communication
// (115200 chosen because it is required for Teapot Demo output, but it's
// really up to you depending on your project)
Serial.begin(38400);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// initialize device
//Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(17);
mpu.setYGyroOffset(-69);
mpu.setZGyroOffset(27);
mpu.setZAccelOffset(1551); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
// Serial.println(F("Enabling DMP..."));
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
mpu.PrintActiveOffsets();
mpu.setDMPEnabled(true);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
//Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
// Serial.print(F("DMP Initialization failed (code "));
//Serial.print(devStatus);
//Serial.println(F(")"));
}
// Define the pins to which the 3 servo motors are connected
servo0.attach(10);
servo1.attach(9);
servo2.attach(8);
}
// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================
void loop() {
// if programming failed, don't try to do anything
if (!dmpReady) return;
// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize) {
if (mpuInterrupt && fifoCount < packetSize) {
// try to get out of the infinite loop
fifoCount = mpu.getFIFOCount();
}
}
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024) {
// reset so we can continue cleanly
mpu.resetFIFO();
fifoCount = mpu.getFIFOCount();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
} else if (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT)) {
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
// Get Yaw, Pitch and Roll values
#ifdef OUTPUT_READABLE_YAWPITCHROLL
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
// Yaw, Pitch, Roll values - Radians to degrees
ypr[0] = ypr[0] * 180 / M_PI;
ypr[1] = ypr[1] * 180 / M_PI;
ypr[2] = ypr[2] * 180 / M_PI;
// Skip 300 readings (self-calibration process)
if (j <= 300) {
correct = ypr[0]; // Yaw starts at random value, so we capture last value after 300 readings
j++;
}
// After 300 readings
else {
ypr[0] = ypr[0] - correct; // Set the Yaw to 0 deg - subtract the last random Yaw value from the currrent value to make the Yaw 0 degrees
// Map the values of the MPU6050 sensor from -90 to 90 to values suatable for the servo control from 0 to 180
int servo0Value = map(ypr[0], -90, 90, 0, 180);
int servo1Value = map(ypr[1], -90, 90, 0, 180);
int servo2Value = map(ypr[2], -90, 90, 180, 0);
// Control the servos according to the MPU6050 orientation
servo0.write(servo0Value);
servo1.write(servo1Value);
servo2.write(servo2Value);
}
#endif
}
}
See image for error code. There is only one exit condition, so I believe this is the only issue.
the arrow in the error code (~~^~~~~~~) points at (2*16384);
This is a warning for an int overflow in the MPU6050 library code, not in your code.
On Github, an issue was raised about this some time ago, which also has the fix in the same posting.
Another solution suggested in the comments there to get rid of this warning is to simply change the "16384" to "16384L" in the library code.
Note that i2cdevlib has 247 open issues; I don't think the owner/maintainer will fix this particular problem any time soon.
I''m working on GNURadio. Included math.h in my program but still get an error saying that abs was not declared in this scope.
Here is my header file.
#ifndef INCLUDED_SLM_H
#define INCLUDED_SLM_H
#include "candidate_t.h"
namespace gr {
namespace uwspr {
class SLM {
public:
// returns frequency drift according to the straight line model
float slmFrequencyDrift(mode_nonlinear m_nl, float cf, float t);
// generator of trajectory parameters for the straight line model
bool slmGenerator(mode_nonlinear *m_nl);
// initialize the generator
void slmGeneratorInit();
// index of current instances
int current;
SLM(){};
~SLM(){};
};
} // namespace uwspr
} // namespace gr
#endif /* INCLUDED_SLM_H */
Here is my code snippet for main function.
#include "slm.h"
#include <math.h>
#ifndef DEBUG
#define DEBUG 1 // set debug mode
#endif
#include "debugmacro.h"
namespace gr {
namespace uwspr {
// Returns frequency drift (in Hz) due to the Doppler effect according to
// the straight line model, described in paper:
float SLM::slmFrequencyDrift(mode_nonlinear m_nl, float cf, float t)
// m_nl = trajectory parameters
// t = time, in seconds
{
const float c = 1500.0; // sound speed (m/s)
// sign of velocity vector
float Sign = (((m_nl.V1 * t + m_nl.p1) * m_nl.V1 +
(m_nl.V2 * t + m_nl.p2) * m_nl.V2) > 0) *
2 -
1;
//
double numerator = abs(m_nl.V1 * (m_nl.V1 * t + m_nl.p1) +
m_nl.V2 * (m_nl.V2 * t + m_nl.p2));
// norm of connectiong vector (Eq. 16)
double denominator =
sqrt(pow(m_nl.V1 * t + m_nl.p1, 2) + pow(m_nl.V2 * t + m_nl.p2, 2));
if (denominator == 0) {
return 0.0;
} else {
// return -Sign;
return -Sign * numerator / denominator * cf / c;
}
}
// Generators of trajectory parameters for the straight line model
bool SLM::slmGenerator(mode_nonlinear *m_nl) {
// control variables for init velocity
const double V1_min = -2, V1_max = 2, V1_step = 1;
const int nV1 = (V1_max - V1_min) / V1_step + 1;
const double V2_min = -2, V2_max = 2, V2_step = 1;
const int nV2 = (V2_max - V2_min) / V2_step + 1;
// control variables for init position on y-axis
const int p2_min = 50, p2_max = 850, p2_step = 200;
const int np2 = (p2_max - p2_min) / p2_step + 1;
// number of generated instances
const int last = nV1 * nV2 * np2;
// indices into the instances
static int ip2, iV1, iV2;
if (current == 0) {
ip2 = 0;
iV1 = 0;
iV2 = 0;
}
if (current < last) { // not generated all instances?
if (ip2 >= np2) {
ip2 = 0; // reset index into the list positions
iV1++; // next horizontal velocity
if (iV1 >= nV1) {
iV1 = 0; // reset index into the list horiz. velocities
iV2++; // next vertical velocity
}
}
// map horizontal velocity index to horizontal velocity (m/s)
m_nl->V1 = iV1 * V1_step + V1_min;
// map vertical velocity index to vertical velocity (m/s)
m_nl->V2 = iV2 * V2_step + V2_min;
// init coordinate on x-axis is always null
m_nl->p1 = 0;
// map y-axis coordinate index to y-axis coordinate (m)
m_nl->p2 = ip2 * p2_step + p2_min;
ip2++; // next position on y-axis
current++; // index of next instance
return true;
} else {
return false; // reach the end
}
}
void SLM::slmGeneratorInit() { current = 0; }
} /* namespace uwspr */
} /* namespace gr */
abs is not defined in <math.h>. It can be found in <stdlib.h> and it is also defined as std::abs in <cmath>.
Surprisingly, the abs function is defined in <stdlib.h> rather than <math.h>. (At least, that's the case since C++17). Try including <stdlib.h> or <cstdlib> and see if that fixes things.
Hope this helps!
The problem is that you were using the C header file, math.h. The C standard already defined (the global scope) int ::abs(int) to take an int and return an int, and this is defined in stdlib.h. The float version, double ::fabs(double) is defined in math.h, which is the one you need to use.
C++ has overloads, so std::abs has double std::abs(double) and int std::abs(int) overloads. So you could just use the C++ header, cmath, and use std::abs (or std::fabs to prevent conversions) instead.
thank you in advance for the community's help.
As of right now, we are looking to get consistent data to output to the serial monitor.
We are seeing output to the monitor several seconds after turning on the device, and sometimes the output takes more than 15 seconds. Furthermore, we are getting a oxogyn concentration of a value well above 100%.
There are times when we get a HR value, and a O2 value which seem reasonable, however, this is not always the case and rather inconsistent.
Is there something wrong with the timing of the interrupts or even the frequency in which we write to the serial monitor?
The code is as follows:
#include <LiquidCrystal.h> //Including this so we can test the code as is
//We can always remove the LCD code later
#include "floatToString.h" //SEE COMMENTS BELOW
/*
* You need to include the float to string header file. I am unsure if this goes in the
* main direcotry withe the code or just the library. For completness I have incouded it on my
* computer in both locations. Please do the same untill we can test further.
*/
#include "Arduino.h" //Formally floatToString.h This changed years ago, using Arduino.h
#include <SoftwareSerial.h> //bluetooth
#include <TimerOne.h> //interrupts SEE COMMENT BELOW
//**********************************************************
//Read Below..........................................
/*
* Need a library for the above timeerOne file
* without the library, you will get an error.
* See Github at https://github.com/PaulStoffregen/TimerOne
* Download the timerOne-master.zip file and place the entire
* TimerOne-master folder in my Documents > Arduino > libraries
*/
//**********************************************************
#define analogPin A0
#define Theta 0.6
#define RxD 1 //bluetooth read
#define TxD 0 //bluetooth transmit
#define DEBUG_ENABLED //bluetooth
#define redLED 5 //High is Red led on, Low is Infrared on.
//#define iredLED 6
volatile int maxTemp,minTemp; //shared variables between interrupts and loop
volatile int lastcount,count;
int Rmax, Rmin, IRmax, IRmin;
float R, Spo2,HeartR_frq;
int Sp02_int;
int HeartRate, HeartR;
float LastHeartRate = 70; //default
int average = 140; //average is average crossing
//int average2 = 220;
int interrupts_counter =0; //count the times of interrupts
float value=0.5;
float Spo2_float;
char buffer[25];
SoftwareSerial blueToothSerial(RxD,TxD); //define bluetooth
void setup() {
pinMode(redLED, OUTPUT); //define LED
pinMode(RxD, INPUT); //bluetooth input
pinMode(TxD, OUTPUT); //bluetooth output
pinMode(analogPin, INPUT); //analog signal input
//initially switch on Red LED, after each interrupt will turn on the other
digitalWrite(redLED, HIGH);
Serial.begin(115200);
//bluetooth
setupBlueToothConnection();
//We might not need this, this might be for the LCD display. Leaving it in for now
init_interrupts();
Timer1.initialize(40000); //terrupt every 0.04 seconds
Timer1.attachInterrupt(max_min_num); //interrupt call max_min_num function
Rmax = 0;
IRmax = 0;
Rmin = 0;
IRmin = 0;
LastHeartRate = 70;
}
void loop() {
//initialize LCD
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // initialize LCD, the pins are all depends
lcd.begin(8, 2); //set up the LCD's number of columns and rows:
while(1){ //the whole while is used to avoid LCD reinitialize
digitalWrite(redLED,HIGH);
delay(2000); //let red led signal to be stable
//interrupts();
while(!((lastcount>average )&& (count<average)) ){ }
digitalWrite(redLED,HIGH);
init_interrupts();
while(!((lastcount>average )&& (count<average)) ){ }
noInterrupts(); // temporarily disabel interrupts, to be sure it will not change while we are reading
Rmax = maxTemp;
Rmin = minTemp;
delay(100);
HeartR_frq = 1/(0.04*interrupts_counter); //d is the times of ISR in 1 second,
interrupts(); //enable interrupts
HeartRate = HeartR_frq * 60;
if(HeartRate> 60 && HeartRate< 120){
HeartR = Theta*HeartRate + (1 - Theta)*LastHeartRate; //Use theta to smooth
LastHeartRate = HeartR;
}
digitalWrite(redLED, LOW);
//initialize lcd
lcd.setCursor(0,0);
lcd.print("HR:");
lcd.setCursor(5,0);
lcd.print(HeartR);
R = (Rmax - Rmin);
Spo2 = (R-180)*0.01 +97.838;
int Spo2_int = (int)Spo2; //float Spo2 to int Spo2_int
String Spo2_float = floatToString(buffer,Spo2,2);
lcd.setCursor(0,1);
lcd.print("SPO2:");
lcd.setCursor(5,1);
lcd.print(Spo2_int);
//transmit data to phone app through bluetooth
String H = String("H: ")+HeartR +String("S: ") +Spo2_float;
Serial.println(H);
delay(1000);
init_interrupts();
}
}
void setupBlueToothConnection() //initialize bluetooth
{
blueToothSerial.begin(115200); //Set BluetoothBee BaudRate to default baud rate 38400
blueToothSerial.print("\r\n+STWMOD=0\r\n"); //t the bluetooth work in slave mode
blueToothSerial.print("\r\n+STNA=HC-06\r\n"); //t the bluetooth name as "HC-05"
blueToothSerial.print("\r\n+STOAUT=1\r\n"); // Permit Paired device to connect me
blueToothSerial.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
delay(2000); // This delay is required.
//blueToothSerial.print("\r\n+INQ=1\r\n"); //make the slave bluetooth inquirable
blueToothSerial.print("bluetooth connected!\n");
delay(2000); // This delay is required.
blueToothSerial.flush();
}
void init_interrupts()
{
maxTemp = 0;
minTemp = 1023;
count = 0;
lastcount =0;
interrupts_counter = 0;
}
void max_min_num()
{
lastcount = count;
count = analogRead(analogPin); //read signa
if(count> maxTemp){
maxTemp = count;
}
else if(count<minTemp){
minTemp = count;
}
interrupts_counter++; //interrupt counter
}
Thank you in advance for your time!
I realize issue has been asked many times, but after reading many many similar questions I am still unable to understand and solve this issue. I am a novice coder and am still learning, and for many days i have been unable to solve this issue.
I am using a demo code library from arduino and trying to compile it in c++ Atmel Studio 7 (compiling for a custom board i made based on ATSAMD21). Here is my relevant code (removed all unrelated parts):
#include <Arduino.h>
#include <Wire.h>
#include "Kalman.h" // Source: https://github.com/TKJElectronics/KalmanFilter
//Beginning of Auto generated function prototypes by Atmel Studio
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, bool sendStop);
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, uint8_t length, bool sendStop);
uint8_t i2cRead(uint8_t registerAddress, uint8_t data, uint8_t nbytes);
//End of Auto generated function prototypes by Atmel Studio
#define RESTRICT_PITCH // Comment out to restrict roll to ±90deg instead - please read: http://www.freescale.com/files/sensors/doc/app_note/AN3461.pdf
Kalman kalmanX; // Create the Kalman instances
Kalman kalmanY;
/* IMU Data */
double accX, accY, accZ;
double gyroX, gyroY, gyroZ;
int16_t tempRaw;
double gyroXangle, gyroYangle; // Angle calculate using the gyro only
double compAngleX, compAngleY; // Calculated angle using a complementary filter
double kalAngleX, kalAngleY; // Calculated angle using a Kalman filter
uint32_t timer;
uint8_t i2cData[14]; // Buffer for I2C data
// TODO: Make calibration routine
#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
// Required for Serial on Zero based boards
#define Serial SERIAL_PORT_USBVIRTUAL
#endif
void setup() {
Serial.begin(115200);
Wire.begin();
//TWBR = ((F_CPU / 400000L) - 16) / 2; // Set I2C frequency to 400kHz
i2cData[0] = 7; // Set the sample rate to 1000Hz - 8kHz/(7+1) = 1000Hz
i2cData[1] = 0x00; // Disable FSYNC and set 260 Hz Acc filtering, 256 Hz Gyro filtering, 8 KHz sampling
i2cData[2] = 0x00; // Set Gyro Full Scale Range to ±250deg/s
i2cData[3] = 0x00; // Set Accelerometer Full Scale Range to ±2g
while (i2cWrite(0x19, *i2cData, 4, false)); // Write to all four registers at once
while (i2cWrite(0x6B, 0x01, true)); // PLL with X axis gyroscope reference and disable sleep mode
while (i2cRead(0x75, *i2cData, 1));
if (i2cData[0] != 0x68) { // Read "WHO_AM_I" register
Serial.print(F("Error reading sensor"));
while (1);
}
//delay(100); // Wait for sensor to stabilize
/* Set kalman and gyro starting angle */
while (i2cRead(0x3B, *i2cData, 6));
accX = (i2cData[0] << 8) | i2cData[1];
accY = (i2cData[2] << 8) | i2cData[3];
accZ = (i2cData[4] << 8) | i2cData[5];
// Source: http://www.freescale.com/files/sensors/doc/app_note/AN3461.pdf eq. 25 and eq. 26
// atan2 outputs the value of -π to π (radians) - see http://en.wikipedia.org/wiki/Atan2
// It is then converted from radians to degrees
#ifdef RESTRICT_PITCH // Eq. 25 and 26
double roll = atan2(accY, accZ) * RAD_TO_DEG;
double pitch = atan(-accX / sqrt(accY * accY + accZ * accZ)) * RAD_TO_DEG;
#else // Eq. 28 and 29
double roll = atan(accY / sqrt(accX * accX + accZ * accZ)) * RAD_TO_DEG;
double pitch = atan2(-accX, accZ) * RAD_TO_DEG;
#endif
kalmanX.setAngle(roll); // Set starting angle
kalmanY.setAngle(pitch);
gyroXangle = roll;
gyroYangle = pitch;
compAngleX = roll;
compAngleY = pitch;
timer = micros();
}
void loop() {
/* Update all the values */
while (i2cRead(0x3B, *i2cData, 14));
accX = ((i2cData[0] << 8) | i2cData[1]);
accY = ((i2cData[2] << 8) | i2cData[3]);
accZ = ((i2cData[4] << 8) | i2cData[5]);
tempRaw = (i2cData[6] << 8) | i2cData[7];
gyroX = (i2cData[8] << 8) | i2cData[9];
gyroY = (i2cData[10] << 8) | i2cData[11];
gyroZ = (i2cData[12] << 8) | i2cData[13];
double dt = (double)(micros() - timer) / 1000000; // Calculate delta time
timer = micros();
// Source: http://www.freescale.com/files/sensors/doc/app_note/AN3461.pdf eq. 25 and eq. 26
// atan2 outputs the value of -π to π (radians) - see http://en.wikipedia.org/wiki/Atan2
// It is then converted from radians to degrees
#ifdef RESTRICT_PITCH // Eq. 25 and 26
double roll = atan2(accY, accZ) * RAD_TO_DEG;
double pitch = atan(-accX / sqrt(accY * accY + accZ * accZ)) * RAD_TO_DEG;
#else // Eq. 28 and 29
double roll = atan(accY / sqrt(accX * accX + accZ * accZ)) * RAD_TO_DEG;
double pitch = atan2(-accX, accZ) * RAD_TO_DEG;
#endif
double gyroXrate = gyroX / 131.0; // Convert to deg/s
double gyroYrate = gyroY / 131.0; // Convert to deg/s
#ifdef RESTRICT_PITCH
// This fixes the transition problem when the accelerometer angle jumps between -180 and 180 degrees
if ((roll < -90 && kalAngleX > 90) || (roll > 90 && kalAngleX < -90)) {
kalmanX.setAngle(roll);
compAngleX = roll;
kalAngleX = roll;
gyroXangle = roll;
} else
kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter
if (abs(kalAngleX) > 90)
gyroYrate = -gyroYrate; // Invert rate, so it fits the restriced accelerometer reading
kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt);
#else
// This fixes the transition problem when the accelerometer angle jumps between -180 and 180 degrees
if ((pitch < -90 && kalAngleY > 90) || (pitch > 90 && kalAngleY < -90)) {
kalmanY.setAngle(pitch);
compAngleY = pitch;
kalAngleY = pitch;
gyroYangle = pitch;
} else
kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt); // Calculate the angle using a Kalman filter
if (abs(kalAngleY) > 90)
gyroXrate = -gyroXrate; // Invert rate, so it fits the restriced accelerometer reading
kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter
#endif
gyroXangle += gyroXrate * dt; // Calculate gyro angle without any filter
gyroYangle += gyroYrate * dt;
//gyroXangle += kalmanX.getRate() * dt; // Calculate gyro angle using the unbiased rate
//gyroYangle += kalmanY.getRate() * dt;
compAngleX = 0.93 * (compAngleX + gyroXrate * dt) + 0.07 * roll; // Calculate the angle using a Complimentary filter
compAngleY = 0.93 * (compAngleY + gyroYrate * dt) + 0.07 * pitch;
// Reset the gyro angle when it has drifted too much
if (gyroXangle < -180 || gyroXangle > 180)
gyroXangle = kalAngleX;
if (gyroYangle < -180 || gyroYangle > 180)
gyroYangle = kalAngleY;
uint32_t time = millis();
/* Print Data */
#if 1 // Set to 1 to activate
Serial.print(accX); Serial.print("\t");
Serial.print(accY); Serial.print("\t");
Serial.print(accZ); Serial.print("\t");
Serial.print(gyroX); Serial.print("\t");
Serial.print(gyroY); Serial.print("\t");
Serial.print(gyroZ); Serial.print("\t");
Serial.print(time); Serial.print("\t");
Serial.print("\t");
#endif
#if 0
Serial.print(roll); Serial.print("\t");
Serial.print(gyroXangle); Serial.print("\t");
Serial.print(compAngleX); Serial.print("\t");
Serial.print(kalAngleX); Serial.print("\t");
Serial.print("\t");
Serial.print(pitch); Serial.print("\t");
Serial.print(gyroYangle); Serial.print("\t");
Serial.print(compAngleY); Serial.print("\t");
Serial.print(kalAngleY); Serial.print("\t");
#endif
#if 1 // Set to 1 to print the temperature
Serial.print("\t");
double temperature = (double)tempRaw / 340.0 + 36.53;
Serial.print(temperature); Serial.print("\t");
#endif
Serial.print("\r\n");
//delay(2);
}
const uint8_t IMUAddress = 0x68; // AD0 is logic low on the PCB
const uint16_t I2C_TIMEOUT = 1000; // Used to check for errors in I2C communication
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, bool sendStop) {
return i2cWrite(registerAddress, &data, 1, sendStop); // INVALID CONVERSION ERROR HERE
}
uint8_t i2cWrite(uint8_t registerAddress, uint8_t *data, uint8_t length, bool sendStop) {
Wire.beginTransmission(IMUAddress);
Wire.write(registerAddress);
Wire.write(data, length);
uint8_t rcode = Wire.endTransmission(sendStop); // Returns 0 on success
if (rcode) {
Serial.print(F("i2cWrite failed: "));
Serial.println(rcode);
}
return rcode; // See: http://arduino.cc/en/Reference/WireEndTransmission
}
uint8_t i2cRead(uint8_t registerAddress, uint8_t *data, uint8_t nbytes) {
uint32_t timeOutTimer;
Wire.beginTransmission(IMUAddress);
Wire.write(registerAddress);
uint8_t rcode = Wire.endTransmission(false); // Don't release the bus
if (rcode) {
Serial.print(F("i2cRead failed: "));
Serial.println(rcode);
return rcode; // See: http://arduino.cc/en/Reference/WireEndTransmission
}
Wire.requestFrom(IMUAddress, nbytes, (uint8_t)true); // Send a repeated start and then release the bus after reading
for (uint8_t i = 0; i < nbytes; i++) {
if (Wire.available())
data[i] = Wire.read();
else {
timeOutTimer = micros();
while (((micros() - timeOutTimer) < I2C_TIMEOUT) && !Wire.available());
if (Wire.available())
data[i] = Wire.read();
else {
Serial.println(F("i2cRead timeout"));
return 5; // This error value is not already taken by endTransmission
}
}
}
return 0; // Success
}
The above code gives error in the i2cWrite function at line 195 Col 54:
invalid conversion from 'uint8_t* {aka unsigned char*}' to 'uint8_t {aka unsigned char}' -fpermissive
Note that i modified the above code first and added an *asterisk to i2cWrite/i2cRead array on lines 43, 46, 55, 83. If i don't add those then the same exact error on ALL those lines as well. Since the original code didn't have those *references maybe I wasn't supposed to add those pointers...?
I am trying to learn about pointers and references, but struggling. For the life of me i cannot understand how to solve this error. I've tried various & and * but for the life of me can't understand and correct this issue. I just cant seem to understand how/where my code is trying to assign a uint8_t* to uint8_t.
Per other topics, do i need to cast or use volatile or const to any of these variables? I don't think so but again i'm a beginner.
I'd be very grateful for anyone to point me in the right direction or help me understand a solution. In Arduino i can compile and run this code, but not in Atmel Studio. Any help is much appreciated.
EDIT: I've updated the code and removed the comments so that the error and line numbers match up with my post. Apologies for confusion on the line #s.
You need to declare the function before calling it.
In the definition of i2cWrite, it cannot see the declaration of the overload that receives a pointer as argument. Because of that, the compiler is assuming you are calling the function recursively, in which has a argument with wrong type.
This is a problem:
uint8_t i2cWrite(uint8_t registerAddress, uint8_t data, bool sendStop) {
return i2cWrite(registerAddress, &data, 1, sendStop); // Returns 0 on success
}
As shown by the first line, i2cWrite takes 3 arguments: uint8_t, uint8_t, and bool. But then you call it with 4 arguments: uint8_t, uint8_t *, int, bool.
Then after that you declare another function called i2cWrite that takes 4 arguments. This is not allowed .
It's hard to say but I'm guessing that you wanted these functions to have different names, the 3-argument one and the 4-argument one.
Thanks to both answers. The solution was simply my function prototypes at the very beginning were slightly different. The 2nd i2cWrite declaration was missing the derefernce *asterisk. That fixed it right up.