Need help with ROV with arm

Here is what I want to do:
Make a RC car with an arm on top.

What I am using:

  • Nrf24L01 modules(for transmitter and receiver)
  • 4x12V DC motors (300rpm at 21kg/cm torque)
  • 5x Servo motors (MG995){for the arm}
  • 12V lead acid battery
  • Arduino Mega(for the vehicle)(receiver)
  • Arduino UNo(for the transmitter part)
  • Some cheap driver circuits which have PWM, direction and brake pins

What have I reached :
Communicating a data package from transmitter to receiver and printing it on serial monitor.

What is the problem at hand:
I still have no clue why my code for the control of the motor isn’t working.As in the motor does not even work on the data from the data structure transmitted.

What I want:
I will be really grateful if someone can guide me on this or just let me know of a link, a website,anything.

p.s It is not the final work , so there are some credits that I haven’t mentioned yet in the comments of the code.

EDIT:I forgot to mention that I am using MPU-6050 (gyroscope and acceleretometer module) for controlling the ROV

Receiver_code_for_project.ino (2.25 KB)

transmitter_code_for_project.ino (6.05 KB)

Many folk read the forum on devices where they can't open .ino files.

Rather paste your code in the post for all to see, like you have done in other threads. (Unless they're too long?)

my apologies for that,
transmitter code is 173 lines

//CODE FOR TRANSMITER//
#include<nRF24L01.h>
#include<SPI.h>
#include<RF24.h>
#include<Wire.h>

struct mydata
{
  uint8_t X;
  uint8_t Y;
  uint8_t S;
};
mydata data;


RF24 radio(7, 8); // setting up the radio
const uint64_t pipes[1] = {0xf0f0f0f0E1LL}; //defining the pipes

const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY;
float angleX, angleY;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY;
float elapsedTime, currentTime, previousTime;
int c = 0;
//pinMode(2, INPUT);
//pinMode(2, INPUT_PULLUP);


void setup() {
  Serial.begin(115200);

  radio.begin();
  radio.setRetries(8, 15);
  radio.openWritingPipe(pipes[0]);
  radio.stopListening();
  radio.setPALevel(RF24_PA_LOW);


  initialize_MPU6050();

  pinMode(4, INPUT_PULLUP);
  

}



void initialize_MPU6050() {
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission
  // Configure Accelerometer
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);
}



void calculate_IMU_error() {
  // We can call this funtion in the setup section to calculate the accelerometer and gury data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    AccY = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    AccZ = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;
  // Read gyro values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 4, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 32.8);
    GyroErrorY = GyroErrorY + (GyroY / 32.8);
    c++;
  }
  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: ");
  Serial.println(AccErrorX);
  Serial.print("AccErrorY: ");
  Serial.println(AccErrorY);
  Serial.print("GyroErrorX: ");
  Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: ");
  Serial.println(GyroErrorY);
}


void read_IMU() {
  // === Read acceleromter data === //
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
  //For a range of +-8g, we need to divide the raw values by 4096, according to the datasheet
  AccX = (Wire.read() << 8 | Wire.read()) / 4096.0; // X-axis value
  AccY = (Wire.read() << 8 | Wire.read()) / 4096.0; // Y-axis value
  AccZ = (Wire.read() << 8 | Wire.read()) / 4096.0; // Z-axis value
  // Calculating angle values using
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) + 1.15; // AccErrorX ~(-1.15) See the calculate_IMU_error()custom function for more details
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) - 0.52; // AccErrorX ~(0.5)
  // === Read gyro data === //
  previousTime = currentTime;        // Previous time is stored before the actual time read
  currentTime = millis();            // Current time actual time read
  elapsedTime = (currentTime - previousTime) / 1000;   // Divide by 1000 to get seconds
  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Gyro data first register address 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 4, true); // Read 4 registers total, each axis value is stored in 2 registers
  GyroX = (Wire.read() << 8 | Wire.read()) / 32.8; // For a 1000dps range we have to divide first the raw value by 32.8, according to the datasheet
  GyroY = (Wire.read() << 8 | Wire.read()) / 32.8;
  GyroX = GyroX + 1.85; //// GyroErrorX ~(-1.85)
  GyroY = GyroY - 0.15; // GyroErrorY ~(0.15)
  // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
  gyroAngleX = GyroX * elapsedTime;
  gyroAngleY = GyroY * elapsedTime;
  // Complementary filter - combine acceleromter and gyro angle values
  angleX = 0.98 * (angleX + gyroAngleX) + 0.02 * accAngleX;
  angleY = 0.98 * (angleY + gyroAngleY) + 0.02 * accAngleY;
  // Map the angle values from -90deg to +90 deg into values from 0 to 255, like the values we are getting from the Joystick
  data.X = map(angleX, -90, +90, 255, 0);
  data.Y = map(angleY, -90, +90, 0, 255);
}


void loop() {
  data.S = digitalRead(4);
  Serial.println(data.S);

  read_IMU();
  if (radio.write(&data, sizeof(mydata))) {

    Serial.print("\n");
    Serial.print("data sent");
    //delay(20);
  }
  else {
    Serial.print("\n");
    Serial.print("data was not sent");
    
  }
}

Receiver code is 135 lines

//CODE FOR Receiver//
#include<nRF24L01.h>
#include<SPI.h>
#include<RF24.h>
#include<Servo.h>


//servo and their pins
Servo servo1;
Servo servo2;
int pos = 0;

//data structure in which data will be received
struct mydata
{
  uint8_t X;
  uint8_t Y;
  uint8_t S;
};
mydata data;




//radio channel setup
RF24 radio(49, 53);
const uint64_t pipes[1] = {0xf0f0f0f0E1LL}; //defining the pipes



void setup() {
  servo1.attach(13);
  servo2.attach(12);
  Serial.begin(115200);



  radio.begin();
  radio.setRetries(5, 15);
  radio.openReadingPipe(1, pipes[0]);
  radio.startListening();
  radio.setPALevel(RF24_PA_LOW);

  //motor control driver pins



  //setting all pwm to high because no speed control is intended.

  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);

  //always high on PWM pin
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);


}

void loop() {

  if (radio.available()) {
    radio.read(&data, sizeof(mydata));
    Serial.print("\n");
    Serial.print(data.X);
    Serial.print("\n");
    Serial.print(data.Y);
    Serial.print("\n");
    Serial.print(data.S);
    Serial.print("\n");
  }
  else {
    Serial.print("\n \n");
    Serial.print("no data available");
  }
  if (data.S == 1)
    //drive the servo motors(arm)
  {
    if (data.Y > 140)
    {
      servo2.write(90);
    }
    else if (data.Y < 120)
    {
      servo2.write(0);
    }
  }
  else if (data.S == 0)
    //drive DC motors(car)
  {
    if (data.X >> 140)
    {
      //move right side so left side is HIGH and right side is LOW
      digitalWrite(4, HIGH);
      digitalWrite(5, HIGH);

      digitalWrite(6, HIGH);
      digitalWrite(7, HIGH);
      digitalWrite(8, HIGH);
      digitalWrite(9, HIGH);

      delay(4000);
    }
    else //if (data.X << 120)
    {
      //move left side so left side is low and right side is high
      //digitalWrite(8, LOW);
      //digitalWrite(9, LOW);

      digitalWrite(5, LOW );
      digitalWrite(4, LOW);
      digitalWrite(6, LOW);
      digitalWrite(7, LOW);

      delay(4000);

    }
  }

  delay(100);
}

Do your Serial prints show that you are receiving the data that you expect?

Does the servo work as expected? (What happened to the other 4 servos?)

Have you written a simple program just to run the motors? That will at least check if your wiring and drivers are working and give you some idea if whatever you are powering everything with is adequate.

If you provide more details it would be easier to help e.g. what DC motors? what "cheap driver circuits"? are you sure the "cheap driver" can supply enough current for the DC motors? how is everything connected (circuit diagram please, hand drawn is fine)? Then what power are you using to run all these servos and DC motors?

Many problems with motors are less with the code and more about bad wiring or insufficient power.

Steve