inka
19.12.2017, 16:48
hallo allerseits,
ich habe wieder mal etwas herumgebastelt, das hier ist das ergebnis:
33129 33130 33131
das verhalten unter dem weiter unten aufgelisteten code kann man in diesem video (https://youtu.be/Dvi44rkz8MY) sehen. Der robby wird oben festgehalten, man kann aber sehen, dass die regelung versucht dem "fallen" entgegen zu wirken...
das thema kompass (hier MPU6050) ist neu für mich, der code ist auch garnicht von mir, ich habe ihn nur im rahmen meiner möglichkeiten angepasst.
fragen/bemerkungen:
- die anpassung an die adafruit motorlib (was die initialisierung und ansteuerung betrifft) war kein problem
- das mit dem setMotors und motorPower (ab zeile 80 und 130) habe ich nur soweit angepasst, wie es mir für die adafruit lib notwendig schien
- die US entfernungs-messung ist für spätere verwendung auskommentiert
- die ISR routine haben ich so gelassen wie sie war. in dieser zeile:
accAngle = atan2(accX, accY) * RAD_TO_DEG;
wird z.b. ein winkel "in der fläche" (x und y bilden bei mir die waagerechte fläche) berechnet, warum reicht nicht die senkrechte richtung zu der drehachse der räder?
- die PID regelung wollte ich mit meinen bescheidenen kenntnissen der steuerungstechnik lieber nich anfassen...
und dann kommen schon die altbekannten funktionen der adafruit motoren lib...
was das verhalten beim balancieren betrifft, habe ich versucht es mit änderungen der motorengeschwindigkeit (motor_A->setSpeed(200)) und der dauer des motor-einsatzes (dauer_fahrt = 50) zu regeln, wahrscheinlich an der PID regelung völlig vorbei...
wo muss ich anfangen mit der anpassung? Was ist sinnvoll? Könnte sich jemand die zeit nehmen und versuchen mit mir step by step die zusammenhänge durchzugehen?
// http://www.instructables.com/id/Arduino-Self-Balancing-Robot-1/
// stammt vom "midhun_s"
// http://www.instructables.com/member/midhun_s/
#include "Arduino.h"
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include "math.h"
#include <NewPing.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *motor_A = AFMS.getMotor(3);
Adafruit_DCMotor *motor_B = AFMS.getMotor(4);
#define TRIGGER_PIN 6 //9
#define ECHO_PIN 7 //8
#define MAX_DISTANCE 175
#define Kp 40
#define Kd 0.05
#define Ki 40
#define sampleTime 0.005
#define targetAngle -2.5
MPU6050 mpu;
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
int16_t accX, accY, accZ, gyroX, gyroY, gyroZ;
volatile int motorPower, gyroRate;
volatile float accAngle, gyroAngle, currentAngle, prevAngle = 0, error, prevError = 0, errorSum = 0;
volatile byte count = 0;
int distanceCm;
unsigned long dauer_fahrt, currentMillis, previousMillis;
void setup()
{
// set the motor control and PWM pins to output mode
AFMS.begin();
// set the status LED to output mode
pinMode(13, OUTPUT);
// initialize the MPU6050 and set offset values
mpu.initialize();
mpu.setXAccelOffset(-1151);
mpu.setYAccelOffset(-823);
mpu.setZAccelOffset(888);
mpu.setXGyroOffset(118);
mpu.setYGyroOffset(28);
mpu.setZGyroOffset(183);
// initialize serial.print
Serial.begin(115200);
Serial1.begin(115200);
// initialize PID sampling loop
init_PID();
}
void loop()
{
// read acceleration and gyroscope values
accX = mpu.getAccelerationX();
accY = mpu.getAccelerationY();
accZ = mpu.getAccelerationZ();
gyroX = mpu.getRotationX();
gyroY = mpu.getRotationY();
gyroZ = mpu.getRotationZ();
accAngle = atan2(accX, accY) * RAD_TO_DEG; //accY, accZ
// set motor power after constraining it
motorPower = constrain(motorPower, -255, 255);
setMotors(motorPower, motorPower);
/*
// measure distance every 100 milliseconds
if ((count % 20) == 0)
{
distanceCm = sonar.ping_cm();
}
if ((distanceCm < 20) && (distanceCm != 0))
{
setMotors(-motorPower, motorPower);
}
*/
}
// The ISR will be called every 5 milliseconds
ISR(TIMER1_COMPA_vect)
{
// calculate the angle of inclination
accAngle = atan2(accX, accY) * RAD_TO_DEG; //accY, accZ
gyroRate = map(gyroX, -32768, 32767, -250, 250);
gyroAngle = (float)gyroRate * sampleTime;
currentAngle = 0.9934 * (prevAngle + gyroAngle) + 0.0066 * (accAngle);
error = currentAngle - targetAngle;
errorSum = errorSum + error;
errorSum = constrain(errorSum, -300, 300);
//calculate output from P, I and D values
motorPower = Kp * (error) + Ki * (errorSum) * sampleTime - Kd * (currentAngle - prevAngle) / sampleTime;
prevAngle = currentAngle;
// toggle the led on pin13 every second
count++;
if (count == 100)
{
count = 0;
digitalWrite(13, !digitalRead(13));
/*
Serial.print(gyroX);
Serial.print(" ");
Serial.println(accAngle);
Serial1.print(gyroX);
Serial1.print(" ");
Serial1.println(accAngle);
*/
}
}
void setMotors(int leftMotorSpeed, int rightMotorSpeed)
{
if (leftMotorSpeed >= 0)
{
//rueckwaerts();
vorwaerts();
}
else
{
//vorwaerts();
rueckwaerts();
}
if (rightMotorSpeed >= 0)
{
//vorwaerts();
rueckwaerts();
}
else
{
//rueckwaerts();
vorwaerts();
}
}
void init_PID()
{
// initialize Timer1
cli(); // disable global interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
// set compare match register to set sample time 5ms
OCR1A = 9999;
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for prescaling by 8
TCCR1B |= (1 << CS11);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // enable global interrupts
}
void vorwaerts (void)
{
currentMillis = millis();
if (currentMillis - previousMillis > dauer_fahrt)
{
motor_A->setSpeed(200);
motor_B->setSpeed(200);
Serial.println("vorwaerts");
Serial1.println("vorwaerts");
motor_A->run(FORWARD);
motor_B->run(FORWARD);
dauer_fahrt = 50;
}
//delay(1000);
}
void rueckwaerts (void)
{
currentMillis = millis();
if (currentMillis - previousMillis > dauer_fahrt)
{
motor_A->setSpeed(200);
motor_B->setSpeed(200);
Serial.println("rueckwaerts");
Serial1.println("rueckwaerts");
motor_A->run(BACKWARD);
motor_B->run(BACKWARD);
dauer_fahrt = 50;
}
//delay(1000);
}
void motoren_stop(void)
{
motor_A->setSpeed(0);
motor_B->setSpeed(0);
Serial.println("motoren stop");
Serial1.println("motoren stop");
motor_A->run(RELEASE);
motor_B->run(RELEASE);
//delay(1000);
}
ich habe wieder mal etwas herumgebastelt, das hier ist das ergebnis:
33129 33130 33131
das verhalten unter dem weiter unten aufgelisteten code kann man in diesem video (https://youtu.be/Dvi44rkz8MY) sehen. Der robby wird oben festgehalten, man kann aber sehen, dass die regelung versucht dem "fallen" entgegen zu wirken...
das thema kompass (hier MPU6050) ist neu für mich, der code ist auch garnicht von mir, ich habe ihn nur im rahmen meiner möglichkeiten angepasst.
fragen/bemerkungen:
- die anpassung an die adafruit motorlib (was die initialisierung und ansteuerung betrifft) war kein problem
- das mit dem setMotors und motorPower (ab zeile 80 und 130) habe ich nur soweit angepasst, wie es mir für die adafruit lib notwendig schien
- die US entfernungs-messung ist für spätere verwendung auskommentiert
- die ISR routine haben ich so gelassen wie sie war. in dieser zeile:
accAngle = atan2(accX, accY) * RAD_TO_DEG;
wird z.b. ein winkel "in der fläche" (x und y bilden bei mir die waagerechte fläche) berechnet, warum reicht nicht die senkrechte richtung zu der drehachse der räder?
- die PID regelung wollte ich mit meinen bescheidenen kenntnissen der steuerungstechnik lieber nich anfassen...
und dann kommen schon die altbekannten funktionen der adafruit motoren lib...
was das verhalten beim balancieren betrifft, habe ich versucht es mit änderungen der motorengeschwindigkeit (motor_A->setSpeed(200)) und der dauer des motor-einsatzes (dauer_fahrt = 50) zu regeln, wahrscheinlich an der PID regelung völlig vorbei...
wo muss ich anfangen mit der anpassung? Was ist sinnvoll? Könnte sich jemand die zeit nehmen und versuchen mit mir step by step die zusammenhänge durchzugehen?
// http://www.instructables.com/id/Arduino-Self-Balancing-Robot-1/
// stammt vom "midhun_s"
// http://www.instructables.com/member/midhun_s/
#include "Arduino.h"
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include "math.h"
#include <NewPing.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *motor_A = AFMS.getMotor(3);
Adafruit_DCMotor *motor_B = AFMS.getMotor(4);
#define TRIGGER_PIN 6 //9
#define ECHO_PIN 7 //8
#define MAX_DISTANCE 175
#define Kp 40
#define Kd 0.05
#define Ki 40
#define sampleTime 0.005
#define targetAngle -2.5
MPU6050 mpu;
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
int16_t accX, accY, accZ, gyroX, gyroY, gyroZ;
volatile int motorPower, gyroRate;
volatile float accAngle, gyroAngle, currentAngle, prevAngle = 0, error, prevError = 0, errorSum = 0;
volatile byte count = 0;
int distanceCm;
unsigned long dauer_fahrt, currentMillis, previousMillis;
void setup()
{
// set the motor control and PWM pins to output mode
AFMS.begin();
// set the status LED to output mode
pinMode(13, OUTPUT);
// initialize the MPU6050 and set offset values
mpu.initialize();
mpu.setXAccelOffset(-1151);
mpu.setYAccelOffset(-823);
mpu.setZAccelOffset(888);
mpu.setXGyroOffset(118);
mpu.setYGyroOffset(28);
mpu.setZGyroOffset(183);
// initialize serial.print
Serial.begin(115200);
Serial1.begin(115200);
// initialize PID sampling loop
init_PID();
}
void loop()
{
// read acceleration and gyroscope values
accX = mpu.getAccelerationX();
accY = mpu.getAccelerationY();
accZ = mpu.getAccelerationZ();
gyroX = mpu.getRotationX();
gyroY = mpu.getRotationY();
gyroZ = mpu.getRotationZ();
accAngle = atan2(accX, accY) * RAD_TO_DEG; //accY, accZ
// set motor power after constraining it
motorPower = constrain(motorPower, -255, 255);
setMotors(motorPower, motorPower);
/*
// measure distance every 100 milliseconds
if ((count % 20) == 0)
{
distanceCm = sonar.ping_cm();
}
if ((distanceCm < 20) && (distanceCm != 0))
{
setMotors(-motorPower, motorPower);
}
*/
}
// The ISR will be called every 5 milliseconds
ISR(TIMER1_COMPA_vect)
{
// calculate the angle of inclination
accAngle = atan2(accX, accY) * RAD_TO_DEG; //accY, accZ
gyroRate = map(gyroX, -32768, 32767, -250, 250);
gyroAngle = (float)gyroRate * sampleTime;
currentAngle = 0.9934 * (prevAngle + gyroAngle) + 0.0066 * (accAngle);
error = currentAngle - targetAngle;
errorSum = errorSum + error;
errorSum = constrain(errorSum, -300, 300);
//calculate output from P, I and D values
motorPower = Kp * (error) + Ki * (errorSum) * sampleTime - Kd * (currentAngle - prevAngle) / sampleTime;
prevAngle = currentAngle;
// toggle the led on pin13 every second
count++;
if (count == 100)
{
count = 0;
digitalWrite(13, !digitalRead(13));
/*
Serial.print(gyroX);
Serial.print(" ");
Serial.println(accAngle);
Serial1.print(gyroX);
Serial1.print(" ");
Serial1.println(accAngle);
*/
}
}
void setMotors(int leftMotorSpeed, int rightMotorSpeed)
{
if (leftMotorSpeed >= 0)
{
//rueckwaerts();
vorwaerts();
}
else
{
//vorwaerts();
rueckwaerts();
}
if (rightMotorSpeed >= 0)
{
//vorwaerts();
rueckwaerts();
}
else
{
//rueckwaerts();
vorwaerts();
}
}
void init_PID()
{
// initialize Timer1
cli(); // disable global interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
// set compare match register to set sample time 5ms
OCR1A = 9999;
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for prescaling by 8
TCCR1B |= (1 << CS11);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // enable global interrupts
}
void vorwaerts (void)
{
currentMillis = millis();
if (currentMillis - previousMillis > dauer_fahrt)
{
motor_A->setSpeed(200);
motor_B->setSpeed(200);
Serial.println("vorwaerts");
Serial1.println("vorwaerts");
motor_A->run(FORWARD);
motor_B->run(FORWARD);
dauer_fahrt = 50;
}
//delay(1000);
}
void rueckwaerts (void)
{
currentMillis = millis();
if (currentMillis - previousMillis > dauer_fahrt)
{
motor_A->setSpeed(200);
motor_B->setSpeed(200);
Serial.println("rueckwaerts");
Serial1.println("rueckwaerts");
motor_A->run(BACKWARD);
motor_B->run(BACKWARD);
dauer_fahrt = 50;
}
//delay(1000);
}
void motoren_stop(void)
{
motor_A->setSpeed(0);
motor_B->setSpeed(0);
Serial.println("motoren stop");
Serial1.println("motoren stop");
motor_A->run(RELEASE);
motor_B->run(RELEASE);
//delay(1000);
}