Hallo,
ich bin gerade etwas am verzweifeln, weil ich das verhalten von einer Klassenvariablen, die ich nur im Konstruktor setze und ansonsten nur lesend darauf zugreife, nicht nachvollziehen kann. Hintergrund ist ein Programm um drei DC Motoren möglichst synchron zu steuern (für einen selbstgebauten höhenverstellbaren Eckschreibtisch). Und gleich vorweg, der Schreibtisch ist so konstruiert, das z.B. bei einer Blockade die elektronische Abschaltung versagen sollte, durch einen zweiten Sicherheitsmechanismus der Strom komplett unterbrochen wird.
Aber nun zum eigentlichen Problem. Es gibt eine Motor Klasse, von der für jeden Motor eine Instanz erzeugt wird (aktuell teste ich erstmal mit zwei Motoren). Und eine MotorController Klasse, die die unterschiede zwischen den Motoren überwacht. Der langsamste Motor ist immer der Master Motor, und die schnelleren Motoren müssen sich mittels PWM an den langsamsten Motor angleichen.
Da ich aber als Interrupt Rutine (für die Codier Scheibe jedes Motors) nur Statische Routinen verwenden kann, löse ich das setzen der Werte aus den Codier Scheiben per Statischen Arrays. Und jeder Motor hat eine Klassenvariable "id", die den Index enthält und im Konstruktor gesetzt wird. Das funktioniert auch zuerst doch dann plötzlich hat "id" auf einmal einen anderen Wert und ich verstehe nicht warum.
Auch wenn es jetzt etwas viel wird, habe ich der Vollständigkeit halber mal alle Sourcen gepostet, einfach zum besseren Verständnis. Und ich hoffe das einer eine Idee hat woran es liegen könnte.
Hier die Klasse Motor
Motor.h
#ifndef Motor_H
#define Motor_H
#include "Arduino.h"
#include <EEPROM.h>
#define UP 1
#define DOWN -1
#define OFF 0
#define EEPROM_OFF_ABS_MIN 0x00
#define EEPROM_OFF_ABS_MAX 0x04
#define EEPROM_OFF_MIN 0x08
#define EEPROM_OFF_MAX 0x0C
#define EEPROM_OFF_MASTER 0x10
#define EEPROM_OFF_POS 0x11
class Motor
{
public:
// Constructor
Motor(uint8_t _outA, uint8_t _outB, uint8_t _sensorIn);
uint32_t GetPosition();
uint8_t GetId();
uint8_t GetCurrentPwm();
bool IsMaster();
void Init();
void Calculate(uint32_t posOfSlowestMotor);
void SetMinMaxPosition(uint32_t _min, uint32_t _max);
void SetMaster(bool _master);
void SetReverseDirection(bool _reverse);
void Break();
void Stop();
void MoveUp();
void MoveDown();
private:
uint8_t id;
bool reverseDirection; // Flag if the direction reverse
volatile bool master; // Flagh if motor is Master
uint8_t lastPwm; // Last Pwm value;
bool breakisOn; // Flag if motor break is on
uint32_t breakOnMillis; // Millis on break start
uint8_t a; // Motor Control A Pin
uint8_t b; // Motor Control B Pin
uint8_t s; // Sensor Pin
uint32_t minPos; // Saved minimal down position
uint32_t maxPos; // Saved maximal up position
uint32_t absolutMinPos; // Absolute minimal down position
uint32_t absolutMaxPos; // Absolute maximal up position
uint32_t centerPos; // Center position between absolut min and max
static volatile uint32_t positions[4];
static volatile int8_t direction[4]; // Direction Up or Down
static uint8_t idCount;
static void OnSensor1Changed();
static void OnSensor2Changed();
static void OnSensor3Changed();
static void OnSensor4Changed();
void MoveMaxPower();
void MovePID(uint8_t pwm);
bool CheckMinMaxLimits();
void ReadFromEEProm();
void WriteToEEProm();
};
#endif
Motor.cpp
#include "Arduino.h"
#include "Motor.h"
uint8_t Motor::idCount = 0;
volatile uint32_t Motor::positions[4];
volatile int8_t Motor::direction[4];
Motor::Motor(uint8_t _outA, uint8_t _outB, uint8_t _sensorIn)
{
id = idCount;
idCount++;
positions[id] = 0;
direction[id] = OFF;
master = ((id == 0) ? true : false);
breakisOn = false;
a = _outA;
b = _outB;
s = _sensorIn;
lastPwm = 255;
}
uint32_t Motor::GetPosition()
{
return positions[id];
}
uint8_t Motor::GetId()
{
return id;
}
uint8_t Motor::GetCurrentPwm()
{
return ((master) ? 255 : lastPwm);
}
bool Motor::IsMaster()
{
return master;
}
void Motor::Init()
{
Serial.print("Init motor with id ");
Serial.println(id);
ReadFromEEProm();
pinMode(s, INPUT_PULLUP);
pinMode(a, OUTPUT);
pinMode(b, OUTPUT);
digitalWrite(a, LOW);
digitalWrite(b, LOW);
switch(id)
{
case 0:
{
attachInterrupt(digitalPinToInterrupt(s), OnSensor1Changed, CHANGE);
break;
}
case 1:
{
attachInterrupt(digitalPinToInterrupt(s), OnSensor2Changed, CHANGE);
break;
}
case 2:
{
attachInterrupt(digitalPinToInterrupt(s), OnSensor3Changed, CHANGE);
break;
}
case 3:
{
attachInterrupt(digitalPinToInterrupt(s), OnSensor4Changed, CHANGE);
break;
}
}
}
void Motor::Calculate(uint32_t posOfSlowestMotor)
{
if(direction[id] != OFF)
{
Serial.print("Calculate motor ");
Serial.println(id);
if(CheckMinMaxLimits())
{
return;
}
if(master)
{
MoveMaxPower();
}
else
{
uint8_t pwm = lastPwm;
int32_t diff = ((direction[id] == UP) ? (positions[id] - posOfSlowestMotor) : (posOfSlowestMotor - positions[id]));
if(diff > 0)
{
pwm = pwm - 1;
}
else if(diff < 0)
{
pwm = pwm + 1;
}
MovePID(pwm);
lastPwm = pwm;
}
}
else
{
if(breakisOn)
{
int32_t timeDiff = (millis() - breakOnMillis);
if(timeDiff > 500)
{
Stop();
}
}
}
}
void Motor::SetMinMaxPosition(uint32_t _min, uint32_t _max)
{
minPos = _min;
maxPos = _max;
WriteToEEProm();
}
void Motor::SetMaster(bool _master)
{
master = _master;
if(master)
{
lastPwm = 255;
}
WriteToEEProm();
}
void Motor::SetReverseDirection(bool _reverse)
{
reverseDirection = _reverse;
}
void Motor::Break()
{
digitalWrite(a, HIGH);
digitalWrite(b, HIGH);
direction[id] = OFF;
breakOnMillis = millis();
breakisOn = true;
}
void Motor::Stop()
{
digitalWrite(a, LOW);
digitalWrite(b, LOW);
direction[id] = OFF;
breakisOn = false;
}
void Motor::MoveUp()
{
direction[id] = UP;
}
void Motor::MoveDown()
{
direction[id] = DOWN;
}
void Motor::MoveMaxPower()
{
if(direction[id] == UP)
{
digitalWrite(a, ((reverseDirection) ? LOW : HIGH));
digitalWrite(b, ((reverseDirection) ? HIGH : LOW));
}
else
{
digitalWrite(a, ((reverseDirection) ? HIGH : LOW));
digitalWrite(b, ((reverseDirection) ? LOW : HIGH));
}
}
void Motor::MovePID(uint8_t pwm)
{
if(direction[id] == UP)
{
analogWrite(a, ((reverseDirection) ? 0 : pwm));
analogWrite(b, ((reverseDirection) ? pwm : 0));
}
else
{
analogWrite(a, ((reverseDirection) ? pwm : 0));
analogWrite(b, ((reverseDirection) ? 0 : pwm));
}
}
bool Motor::CheckMinMaxLimits()
{
if(direction[id] == UP)
{
if(positions[id] > max(maxPos, absolutMaxPos))
{
Break();
return true;
}
}
else
{
if(positions[id] < min(minPos, absolutMinPos))
{
Break();
return true;
}
}
return false;
}
void Motor::OnSensor1Changed()
{
Serial.print("Sensor 0 changed ");
Serial.println(positions[0]);
if(direction[0] == UP)
{
positions[0] = positions[0] + 1;
}
else if(direction[0] == DOWN)
{
positions[0] = positions[0] - 1;
}
}
void Motor::OnSensor2Changed()
{
Serial.print("Sensor 1 changed ");
Serial.println(positions[1]);
if(direction[1] == UP)
{
positions[1] = positions[1] + 1;
}
else if(direction[1] == DOWN)
{
positions[1] = positions[1] - 1;
}
}
void Motor::OnSensor3Changed()
{
if(direction[2] == UP)
{
positions[2] = positions[2] + 1;
}
else if(direction[2] == DOWN)
{
positions[2] = positions[2] - 1;
}
}
void Motor::OnSensor4Changed()
{
if(direction[3] == UP)
{
positions[3] = positions[3] + 1;
}
else if(direction[3] == DOWN)
{
positions[3] = positions[3] - 1;
}
}
void Motor::ReadFromEEProm()
{
EEPROM.get(EEPROM_OFF_ABS_MIN, absolutMinPos);
EEPROM.get(EEPROM_OFF_ABS_MAX, absolutMaxPos);
EEPROM.get(EEPROM_OFF_MIN, minPos);
EEPROM.get(EEPROM_OFF_MAX, maxPos);
uint8_t masterId = 0;
EEPROM.get(EEPROM_OFF_MASTER, masterId);
master = (masterId == id);
centerPos = ((absolutMaxPos - absolutMinPos) / 2);
uint32_t pos = 0;
EEPROM.get(EEPROM_OFF_POS + (id * 0x04), pos);
positions[id] = pos;
}
void Motor::WriteToEEProm()
{
EEPROM.put(EEPROM_OFF_ABS_MIN, absolutMinPos);
EEPROM.put(EEPROM_OFF_ABS_MAX, absolutMaxPos);
EEPROM.put(EEPROM_OFF_MIN, minPos);
EEPROM.put(EEPROM_OFF_MAX, maxPos);
if(master)
{
EEPROM.get(EEPROM_OFF_MASTER, id);
}
uint32_t pos = positions[id];
EEPROM.put(EEPROM_OFF_POS + (id * 0x04), pos);
}
MotorController.h
#ifndef MotorController_H
#define MotorController_H
#include "Arduino.h"
#include "Motor.h"
class MotorController
{
public:
MotorController();
void Init();
void AddMotor(Motor* m, int stopSensorPin);
void MoveUp();
void MoveDown();
void MoveTo(uint32_t pos);
void Stop();
void Calculate();
private:
Motor* motors[4];
uint8_t count;
uint8_t direction;
uint8_t stopSensorPins[4];
uint32_t stopPos;
bool doStop;
int GetMinMotorPos();
int GetMaxMotorPos();
void SetMasterMotor(int id);
};
#endif
MotorController.cpp
#include "Arduino.h"
#include "MotorController.h"
MotorController::MotorController()
{
count = 0;
direction = OFF;
stopPos = 0;
doStop = false;
}
void MotorController::AddMotor(Motor* m, int stopSensorPin)
{
motors[count] = m;
stopSensorPins[count] = stopSensorPin;
count++;
}
void MotorController::Init()
{
for(int i=0; i<count; i++)
{
pinMode(stopSensorPins[i], INPUT_PULLUP);
motors[i]->Init();
}
}
void MotorController::MoveUp()
{
direction = UP;
for(int i=0; i<count; i++)
{
motors[i]->MoveUp();
}
doStop = false;
}
void MotorController::MoveDown()
{
direction = DOWN;
for(int i=0; i<count; i++)
{
motors[i]->MoveDown();
}
doStop = false;
}
void MotorController::MoveTo(uint32_t pos)
{
}
void MotorController::Stop()
{
if(direction != OFF)
{
int idOfFastestMotor = ((direction == UP) ? GetMaxMotorPos() : GetMinMotorPos());
stopPos = motors[idOfFastestMotor]->GetPosition();
doStop = true;
}
}
void MotorController::Calculate()
{
uint32_t maxPos = 0;
int isStop = LOW;
for(int i=0; i<count; i++)
{
isStop = (isStop | digitalRead(stopSensorPins[i]));
}
// Stop all motors if sensor detect colision
if(isStop == HIGH)
{
for(int i=0; i<count; i++)
{
motors[i]->Break();
}
}
if(direction != OFF)
{
int idOfSlowestMotor = ((direction == UP) ? GetMinMotorPos() : GetMaxMotorPos());
int idOfFastestMotor = ((direction == UP) ? GetMaxMotorPos() : GetMinMotorPos());
maxPos = motors[idOfFastestMotor]->GetPosition();
if((!motors[idOfSlowestMotor]->IsMaster()) && motors[idOfSlowestMotor]->GetCurrentPwm() == 255)
{
SetMasterMotor(idOfSlowestMotor);
}
if(doStop)
{
for(int i=0; i<count; i++)
{
if(direction == UP)
{
if(motors[i]->GetPosition() >= stopPos)
{
motors[i]->Stop();
}
}
else
{
if(motors[i]->GetPosition() <= stopPos)
{
motors[i]->Stop();
}
}
}
}
}
for(int i=0; i<count; i++)
{
motors[i]->Calculate(maxPos);
}
}
int MotorController::GetMinMotorPos()
{
uint32_t min = 0xFFFFFFFF;
int motorId = 0;
for(int i=0; i<count; i++)
{
if(motors[i]->GetPosition() < min)
{
min = motors[i]->GetPosition();
motorId = i;
}
}
return motorId;
}
int MotorController::GetMaxMotorPos()
{
uint32_t max = 0x00;
int motorId = 0;
for(int i=0; i<count; i++)
{
if(motors[i]->GetPosition() > max)
{
max = motors[i]->GetPosition();
motorId = i;
}
}
return motorId;
}
void MotorController::SetMasterMotor(int id)
{
for(int i=0; i<count; i++)
{
motors[i]->SetMaster((id == i));
}
}
Schreibtisch.ino
#include "MotorController.h"
#include "Motor.h"
const int motorForwardR = 10;
const int motorBackwardR = 9;
const int motorForwardL = 5;
const int motorBackwardL = 6;
const int motorSensorR = 3;
const int motorSensorL = 2;
const int btnDown = 0;
const int btnUp = 1;
const int speedCtrl = A0;
MotorController motorController;
Motor m1(motorForwardR, motorBackwardR, motorSensorR);
Motor m2(motorForwardL, motorBackwardL, motorSensorL);
bool motorUp = false;
bool motorDown = false;
void setup()
{
Serial.begin(9600);
while(!Serial);
pinMode(speedCtrl, INPUT);
pinMode(btnDown, INPUT_PULLUP);
pinMode(btnUp, INPUT_PULLUP);
m1.SetReverseDirection(false);
m2.SetReverseDirection(true);
motorController.AddMotor(&m1, 7);
motorController.AddMotor(&m2, 8);
motorController.Init();
}
void loop()
{
int speedCtrlVal = analogRead(speedCtrl);
int _up = digitalRead(btnUp);
int _down = digitalRead(btnDown);
if(_up == LOW)
{
motorController.MoveUp();
}
else if(_down == LOW)
{
motorController.MoveDown();
}
else
{
motorController.Stop();
}
motorController.Calculate();
delay(5);
}
Hier die Ausgaben etwas gekürzt, wo aber zu sehen ist, das die Variable "id" plötzlich einen komplett anderen Wert hat. Und ich weiß nicht warum?
Init motor with id 0
Init motor with id 1
Sensor 1 changed 0
Sensor 0 changed 0
Sensor 1 changed 1
Sensor 0 changed 1
Sensor 0 changed 2
Sensor 1 changed 2
Sensor 0 changed 3
Sensor 1 changed 3
Sensor 0 changed 4
Sensor 1 changed 4
Sensor 0 changed 5
Sensor 1 changed 5
Sensor 0 changed 6
Sensor 1 changed 6
Sensor 0 changed 7
Sensor 1 changed 7
Sensor 0 changed 8
Sensor 1 changed 8
Sensor 0 changed 9
Sensor 0 changed 10
Sensor 1 changed 9
Sensor 0 changed 11
Sensor 1 changed 10
Calculate motor 69
Calculate motor 69
Calculate motor 69
Calculate motor 69
Calculate motor 69