Need help to understand some code!

#include <Wire.h>
#include <I2Cdev.h>
#include <MPU6050.h>

MPU6050 mpu;

int16_t ax, ay, az;

int16_t gx, gy, gz; 

#define pin1 3
#define pin2 5

void setup(){
 Serial.begin(9600);
 Serial.println("Initialize MPU");
 mpu.initialize();
 //Serial.println(mpu.testConnection() ? "Connected" : "Connection failed"); 
 pinMode(pin1,OUTPUT);
 pinMode(pin2,OUTPUT);

}

void loop(){
 mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

 ax = map(ax, -17000, 17000, -1500, 1500);

 //Serial.println(ax);
 if(ax > 0){
  if(ax<255){
  Serial.println(ax);
  analogWrite(pin2,ax);
 }
 else{
  Serial.println("+255");
  analogWrite(pin2,255);
 }

 }
 if(ax<0){
  if(ax>-255){
  Serial.println(ax);
  analogWrite(pin1, ax-ax-ax);
 }
 else{
  Serial.println("-255");
  analogWrite(pin1, 255);
 }
 }
 delay(1000);
}

My team is working on a project which requires me to control the inclination of a plane using 4 lead screw mechanisms mounted on 4 corners of the plane.we are going to use a MPU 6050 for feedback ,so as to stop the motors when a particular angle is reached , while searching about the topic I came across this code but really couldn't understand why some commands have been used there it would prove helpful for me if someone explained just a few parts of the code and get me going.

mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

 ax = map(ax, -17000, 17000, -1500, 1500);

What is the map function doing here ? and why is there a variable ax and rest all of it are constants?

 if(ax > 0){
  if(ax<255){
  Serial.println(ax);
  analogWrite(pin2,ax);
 }
 else{
  Serial.println("+255");
  analogWrite(pin2,255);
 }

 }
 if(ax<0){
  if(ax>-255){
  Serial.println(ax);
  analogWrite(pin1, ax-ax-ax);
 }
 else{
  Serial.println("-255");
  analogWrite(pin1, 255);
 }

what does this logic code here do?

What is the map function doing here ? and why is there a variable ax and rest all of it are constants?

map() is remapping the value of ax to a different range. I see no constants. I do see arguments passed by reference so that the setMotion() function can change their values.

what does this logic code here do?

It looks simple. If ax is between 0 and 255 its value is written to pin 3 otherwise 255 is written to pin2. If ax is between 0 and -255 then it is made into a positive number (ax - ax - ax) and written to pin1, otherwise 255 is written to pin1

NOTE abs(ax); would perhaps have been better than ax - ax - ax

so what should I do if I want to control 4 motors using 4 switches and let the motors run until the surface reaches a required Inclination ?
BTW the inclination data will be acquired from gyroscope ,pointing me in the right direction will be helpful or a sample code will kickstart my work !

Here is some code I've shared several times I find it to be reliable without any glitchy data. it uses the MPU6050's DMP capability to calculate angles this is set into a FIFO buffer that is prepped about every 10 milliseconds
you could alter the code to handle multiple MPU6050's if you toggle the AD0 pin between 3.3V and Gnd changing the address on all other MPU6050's to a different I2c address while getting the data from the one your are sampling.

Z

MPU6050_Latest_code.ino (7.46 KB)

MPU6050_calibration.ino (7.64 KB)

You know four motors will twist your plane into a potato chip? Three would be a much better choice.

Yes the main() which handles the loop calls a function related to serial communications

int main(void)
{
	init();

	initVariant();

#if defined(USBCON)
	USBDevice.attach();
#endif

	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

To avoid this Create your own while( 1 ) { your code } loop to avoid ending the loop function and handing control back to main.
You can also disable the interrupt timer of millis() to completely eliminate interruptions. I'm not aware of any other interrupts that will steal clock ticks from your program.

Z

MorganS:
You know four motors will twist your plane into a potato chip? Three would be a much better choice.

yes that may happen if I don't have any sort of feedback for the motors ,I mean the motors will stop when the MPU6050 gives me Roll ,Pitch and Yaw data and this is the angle at which my surface needs to be inclined.
3 motors don't properly balance my surface...been there done that.

zhomeslice:
Here is some code I've shared several times I find it to be reliable without any glitchy data. it uses the MPU6050's DMP capability to calculate angles this is set into a FIFO buffer that is prepped about every 10 milliseconds
you could alter the code to handle multiple MPU6050's if you toggle the AD0 pin between 3.3V and Gnd changing the address on all other MPU6050's to a different I2c address while getting the data from the one your are sampling.

Z

can i change the baud rate used in your code to 57600?

shan_bhede29:
can i change the baud rate used in your code to 57600?

yes search for Serial.begin( 115200 ) ;
and change it to Serial.begin( 57600 ) ;

When using the code I realized that the yaw values took some time to get to a stable point .why is this so?
is there a way to use the yaw values only when they have stabilized?
my application of this sensor requires stable values from the start so is there any way out of this?

is there a way to use the yaw values only when they have stabilized?

Read the value and compare it with the previous value. When they have not changed, or have changed by a sufficiently small amount they have stabilized.

shan_bhede29:
When using the code I realized that the yaw values took some time to get to a stable point .why is this so?
is there a way to use the yaw values only when they have stabilized?
my application of this sensor requires stable values from the start so is there any way out of this?

I posted the mpu6050_calibration.ino.
Try running it again. The other axis have gravity to help the gyro stabilize there values yaw doesn't. And it will drift. The better calibration values used the better stability you will find.
The numbers you get need to replace the calibration numbers in the mpu6050 every time this is powered on. It loses this information on power failure. The MPU6050_Latest_code.ino file i posted earlier has an example of how to do this.

Z

shan_bhede29:
When using the code I realized that the yaw values took some time to get to a stable point .why is this so?
is there a way to use the yaw values only when they have stabilized?
my application of this sensor requires stable values from the start so is there any way out of this?

Yaw will never stabilise. There will always be drift. You need another reference such as a compass to zero out the drift.

This seems like a complex platform. Can you share a photo or CAD rendering so we know what it looks like?

shan_bhede29:
3 motors don't properly balance my surface

Eh? Why won't three motors work?

DaveEvans:
Eh? Why won't three motors work?

Because he has more degrees of freedom than just tilt and roll. Yaw has been mentioned and there may be more we haven't been told about yet.

MorganS:
Yaw will never stabilise. There will always be drift. You need another reference such as a compass to zero out the drift.

This seems like a complex platform. Can you share a photo or CAD rendering so we know what it looks like?

can you help me out if I use a GY-273 HMC5883L Module with the MPU 6050 ? just getting me compass data would be enough to perfectly get feedback for the "yaw" part of my code

shan_bhede29:
yes that may happen if I don't have any sort of feedback for the motors ,I mean the motors will stop when the MPU6050 gives me Roll ,Pitch and Yaw data and this is the angle at which my surface needs to be inclined.
3 motors don't properly balance my surface...been there done that.

That doesn't make sense - you have 3 degrees of freedom, you need 3 motors. Anything else will
break stuff.

shan_bhede29:
can you help me out if I use a GY-273 HMC5883L Module with the MPU 6050 ? just getting me compass data would be enough to perfectly get feedback for the "yaw" part of my code


this seems to be close to your needs for hooking it up.
WARNING! the **** 4.7 kOm ***** resistor is on the address changing pin of the mpu6050 you will not need that!!!! (unless you need the alternate address set! the board has its own 4.7k pull down resistor so you would be applying 2.5v to the mpu6050's address change pin with this arrangement.

I was not able to personally get the MPU6050 code to "auto calibrate" using the compass in the mpu9055 9 degree of freedom chip but it could be caused by the chip I was using. You only need to understand that the MPU9050 9 axis, is exactly the same as you see above just it is all in one chip.
so the mpu6050 library has a 9 degree of motion sketch included allowing you to attach the compass through the MPU6050 auxiliary i2c connections as shown in the schematic above. the mpu6050 datasheet goes into details as to how this all works.
I would use the MPU6050_latest_code.ino sketch I provided in an earlier post and add a simple compass reading sketch that handles the last 3 degrees of motion. then I would watch for differences in the two averaging the compass over time to get a stable reading to tweek an offset for the MPU6050 yaw value after the FIFO buffer has given it to the UNO. this will allow your code keep it from wandering too much. the yaw should be stable after using the calibration routines. but it will always find some drift over time.
Z

Part 2:
I did some additional research into the MPU6050 library we are using. It already has code set for accessing the raw compass values which should be in radians or degrees you compass datasheet should tell you.

code from MPU6050.cpp library showing how to enable the aux i2c buss and request data from the magnometer.

void MPU6050::InitMag(){
	int Mag[3];
	// enable MPU AUX I2C bypass mode
	Serial.println(F("Enabling AUX I2C bypass mode..."));
	setI2CBypassEnabled(true);
	byte d;
	I2Cdev::readByte(0x0C, 0x00, &d); // 0x00 // Read WHO_AM_I register for AK8963
	Serial.print("AK8963 ");  Serial.print("I AM ");  Serial.print(d);  Serial.print(" I should be ");  Serial.println(0x48);
	Serial.println(F("Setting magnetometer mode to power-down..."));
	//mag -> setMode(0);
	I2Cdev::writeByte(0x0C, 0x0A, 0x00);//0x0A Control
	delay(10);
	Serial.println(F("Setting magnetometer mode to fuse access..."));
	//mag -> setMode(0x0F);
	I2Cdev::writeByte(0x0C, 0x0A, 0x0F);//0x0A Control

	Serial.println(F("Reading mag magnetometer factory calibration..."));
	int8_t asax, asay, asaz;
	//mag -> getAdjustment(&asax, &asay, &asaz);
	I2Cdev::readBytes(0x0C, 0x10, 3, buffer);
	asax = (int8_t)buffer[0];
	asay = (int8_t)buffer[1];
	asaz = (int8_t)buffer[2];
	Serial.print(F("Adjustment X/Y/Z = "));
	Serial.print(asax);
	Serial.print(F(" / "));
	Serial.print(asay);
	Serial.print(F(" / "));
	Serial.println(asaz);

	Serial.println(F("Setting magnetometer mode to power-down..."));
	//mag -> setMode(0);
	I2Cdev::writeByte(0x0C, 0x0A, 0x00);
	delay(10);
	I2Cdev::writeByte(0x0C, 0x0A, 0x00 << 4 | 0x02);// 16bit at 8hz
	for(int ii = 0; ii < 10;ii++){
		readMagData(Mag);
		Serial.print("Mag X ");
		Serial.print(Mag[0]);
		Serial.print("\tMag Y ");
		Serial.print(Mag[1]);
		Serial.print("\tMag Z ");
		Serial.print(Mag[2]);
		Serial.println("\t");
	}
	
}
void MPU6050::readMagData(int16_t * destination)
{
	byte d;
	uint8_t rawData[7];  // x/y/z gyro register data, ST2 register stored here, must read ST2 at end of data acquisition
	I2Cdev::readByte(0x0C, 0x02, &d);
	if (d & 0x01) { // 0x02 // wait for magnetometer data ready bit to be set
		I2Cdev::readBytes(0x0C, 0x03, 7, &rawData[0]); // 0x03 // Read the six raw data and ST2 registers sequentially into data array
		uint8_t c = rawData[6]; // End data read by reading ST2 register
		if (!(c & 0x08)) { // Check if magnetic sensor overflow set, if not then report data
			destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ;  // Turn the MSB and LSB into a signed 16-bit value
			destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;  // Data stored as little Endian
			destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
		}
	}
}

Z