
Нам понадобится:
Arduino: http://ali.pub/1x1jri
Драйвер двигателей L298N: http://ali.pub/1wptjz
2 моторредуктора: http://ali.pub/1x1kic
Гироскоп: http://ali.pub/1x1lem
Аккумуляторы 18650: http://ali.pub/1x1llm
Отличная зарядка 18650: http://ali.ski/vHvuN
box под 18650: http://ali.pub/1x1mse
Макетная плата: http://ali.ski/mvDWz2
Контактные провода: http://ali.pub/1th4xf
Прежде чем приступить к материалу, я Вас попрошу, если нравится то, что я делаю и хотите следить за моей деятельностью, то рекомендую подписаться на мой телеграмм канал: https://t.me/ypavla
Там я публикую новости о вышедших видео, статьях и разные устройства для умного дома и не только показываю.
Спасибо за внимание, теперь продолжим.
Для изготовления корпуса для балансира я взял картон. Картон был довольно тонкий и я склеивал несколько листов, для увеличения прочности конструкции.

Размер боковин балансира указан на фото:

Таких деталей должно быть две, но с учетом того что картон тонкий, я их сделал 4 и склеил между собой термопистолетом.
С вертикальными частями разобрались, теперь нужно сделать 3 горизонтальных. Я их склеивал тоже между собой, поэтому сделал вот таких частей 6 шт.:

После склейки должна получиться лесенка. Все детали я склеивал между собой термоклеем, картон он очень хорошо склеивает.
Моторредукторы я крепил на стяжки к боковинам получившейся “лесенки”

Драйвер двигателей, я разместил на самую нижнюю полку получившейся конструкции.

При подключении самих моторов к драйверу, важно подобрать правильную полярность, чтоб моторы крутились именно в ту сторону, в которую нужно чтоб они крутились для удерживания ровновесия.
Наши “мозги” Ардуино и гироском Mpu 6050 я установил на среднюю полку, чтоб было не сложно дотянуться и до драйвера двигателей и до аккумуляторов.
ВАЖНО: Гироскоп нужно расположить ровно в плоскости, иначе роботу будет тяжело держать равновесие.

Ну и сами аккумуляторы прикрепил на стяжки в самом верху конструкции.

После размещения всех элементов и подключения их друг с другом проводами, Робот выглядит вот таким вот образом.

После того как мы разобрались с конструкцией робота, давайте перейдем к электронной части, а именно к схеме подключения элементов.

Ну и собственно сам скетч:
#include <Wire.h>
#include "Kalman.h"
#include "PID_v1.h"
Kalman kalmanY;
uint8_t IMUAddress = 0x68;
/* IMU Data */
int16_t accX;
int16_t accY;
int16_t accZ;
int16_t gyroY;
double accYangle;
double gyroYangle = 180;
double compAngleY = 180;
double kalAngleY;
double in, out, setpoint;
PID pid(&in, &out, &setpoint, 30, 410 , 0.8, DIRECT);
uint32_t timer;
void setup() {  
  Serial.begin(115200);
  Wire.begin();  
  i2cWrite(0x6B,0x00); // Disable sleep mode  
  if(i2cRead(0x75,1)[0] != 0x68) { // Read "WHO_AM_I" register
    Serial.print(F("MPU-6050 with address 0x"));
    Serial.print(IMUAddress,HEX);
    Serial.println(F(" is not connected"));
    while(1);
  }      
  kalmanY.setAngle(180);
  pid.SetMode(AUTOMATIC);
  pid.SetOutputLimits(-255,255);
  pid.SetSampleTime(10);
  setpoint = 181.8;
  
  timer = micros();
}
double ang;
int pwm;
void loop() {
  /* Update all the values */
  uint8_t* data = i2cRead(0x3B,14);  
  accX = ((data[0] << 8) | data[1]);
  accY = ((data[2] << 8) | data[3]);
  accZ = ((data[4] << 8) | data[5]);  
  gyroY = ((data[10] << 8) | data[11]);
  
  /* Calculate the angls based on the different sensors and algorithm */
  accYangle = (atan2(accX,accZ)+PI)*RAD_TO_DEG;
  
  double gyroYrate = -((double)gyroY/131.0);
  gyroYangle += gyroYrate*((double)(micros()-timer)/1000000);
  kalAngleY = kalmanY.getAngle(accYangle, gyroYrate, (double)(micros()-timer)/1000000);
  timer = micros();
  
  in = kalAngleY;
  pid.Compute();
  if (out < 0) {
    pwm = -1 * out;
    analogWrite(11, 0);
    analogWrite(10, pwm);
  } else {
    pwm = out;
    analogWrite(10, 0);
    analogWrite(11, pwm);
  }
  
  delay(1); // The accelerometer's maximum samples rate is 1kHz
}
void i2cWrite(uint8_t registerAddress, uint8_t data){
  Wire.beginTransmission(IMUAddress);
  Wire.write(registerAddress);
  Wire.write(data);
  Wire.endTransmission(); // Send stop
}
uint8_t* i2cRead(uint8_t registerAddress, uint8_t nbytes) {
  uint8_t data[nbytes];  
  Wire.beginTransmission(IMUAddress);
  Wire.write(registerAddress);
  Wire.endTransmission(false); // Don't release the bus
  Wire.requestFrom(IMUAddress, nbytes); // Send a repeated start and then release the bus after reading
  for(uint8_t i = 0; i < nbytes; i++)
    data[i] = Wire.read();
  return data;
} 
Для корректной работы скетча нам еще понадобятся две библиотеки kalman и PID_v1
Все это можно скачать здесь: https://yadi.sk/d/_IPFIZLX3NkEqg
Ну и собственно демонстрация работы: