Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

projekte2014:beerbot:dokumentation:software

Dies ist eine alte Version des Dokuments!




Softwaredokumentation

Libraries

BeerBotLib

BeerBotLib.h

BeerBotLib.h
#ifndef BeerBotLib_h
#define BeerBotLib_h
 
#include "Arduino.h"
#include "Servo.h"
#include "NewPing.h"
 
/**
* class to add some additional features for the servo.
*/
 
class NewServo {
	public:
		void setup(int servoPin, int pos, boolean newServo);
		int getPos();
		void setPos(int pos);
 		void sweep(int servoSpeed, int servoRange, int servoDelay);
	private:
		Servo myServo;
		int position;
		int direction;
};
 
/**
* class for working with an ultrasonic distance sensor.
* is not used for the roboter in its current state. 
*/
 
class DistanceSensor {
	public:
		void setup(int inputPin, int outputPin, int servoPin);
		int getPos();
		int getDistance();
 
	private:
		NewPing sensor;
		NewServo myServo;	 
};
 
/**
* class to control the stepper motors.
*/
 
class StepperMotor {
	public:
		void setup(int stepPin, int directionPin);
		void makeStep(boolean direction);
	private:
		int stepPin;
		int directionPin;
};
 
/**
* class to control the whole gear of the servo.
*/
 
class Gear {
	public:
		void setup(float wheelDiameter, float axisDistance, int leftMotorStepPin, int leftMotorDirPin, int rightMotorStepPin, int rightMotorDirPin);
		void turnToServoPos(int servPos, int stepSpeed, int tolerance, int partAngle);
		void turnAngle (int angle, boolean turnDirection, int stepSpeed); 
		void drive(float distance, int stepSpeed, boolean driveDirection);
	private:
		float wheelDiameter;
		float axisDistance;
		StepperMotor rightMotor;
		StepperMotor leftMotor;
};
 
/**
* class to trigger the pusher(s).
*/
 
class Pusher {
	public:
		void setup(int pusherPin);
		void push(int duration);
	private:
		int pusherPin;
};
 
/**
* class to control the barriers.
*/
 
class Barrier {
	public:
		void setup(int servoPin, int closedPos, int openPos);
		void openBarrier();
		void closeBarrier();
	private:
		NewServo myServo;
		boolean closed;
		int closedPos;
		int openPos;	
};
 
/**
* class to control the push button contact sensors.
*/
 
class ContactSensor {
	public:
		void setup(int rightButtonPin, int leftButtonPin, int conductorPin);
		boolean rightButtonPushed();
		boolean leftButtonPushed();
		boolean isConducting();
	private:
		int rightButtonPin;
		int leftButtonPin;
		int conductorPin;
};
 
 
#endif

BeerBotLib.cpp

BeerBotLib.cpp
#include "BeerBotLib.h"
 
////////////////////////////////////////
// NewServo class
////////////////////////////////////////
 
/**
* setup method for servo class.
* the setup mehod has to be called, before the implicit constructed objects can be used.
* 
* @param servoPin: pin the servo is attached to,
*		 pos: initial position of the servo,
*		 newServo: specifies if the servo is one of the new models.
*/
 
void NewServo::setup(int servoPin, int pos, boolean newServo) {
	if (newServo) {
		myServo.attach(servoPin, 800, 2100);
	}
	else {
		myServo.attach(servoPin);
	}
	setPos(pos);
	direction = 0;
}
 
/**
* getter method for servo position.
* 
* @return the last position to which the servo was set. 
*/
 
int NewServo::getPos() {
	return position;
}
 
/**
* setter method for the servo method.
* servo position is set to new position and servo is moved to new position.
* 
* @param pos: new servo position. 
*/
 
void NewServo::setPos(int pos) {
	myServo.write(pos);
	this-> position = pos;
}
 
/**
* method to let the servo sweep.
* sweeps only one step on each method call
* 
* @param servoSpeed: specifies the lenght of each step,
*	  	 servoRange: specifies the range in wich the servo should sweep
*		 (e.g. servoRange = 50 --> servo sweeps from 65 to 115),
*		 servoDelay: delay after each step.
*/
 
void NewServo::sweep(int servoSpeed, int servoRange, int servoDelay) {
	if (direction == 0) {
		direction = 1;
	}
	if (direction == 1) {
		moveRight(servoSpeed, servoDelay);
		if (position >= 90 + servoRange/2) {
			direction = -1;
		}
	}
	if (direction == -1) {
		moveLeft(servoSpeed, servoDelay);
		if (position <= 90 - servoRange/2) {
			direction = 1;
		}
	}
}
 
////////////////////////////////////////
// DistanceSensor class
////////////////////////////////////////
 
/**
* setup method for the distance sensor.
* initializes the distance sensor using third-party library NewPing.
* has to be called before the object can be used.
*
* @param inputPin: the echo pin of the sensor,
	 	 outputPin: the trigger pin of the sensor,
		 servoPin: the pin of the servo on which the sensor is mounted (if that is the case).
*/
 
void DistanceSensor::setup(int inputPin, int outputPin, int servoPin) {
	sensor.setup(outputPin, inputPin);
	myServo.setup(servoPin, 90, false);
}
 
/**
* getter method for the servo on which the sensor is mounted.
*
* @return the getPos method of the servo.
*/
 
int DistanceSensor::getPos() {
	return myServo.getPos();
}
 
/**
* method to measure the distance with the sensor.
* uses the third-party library NewPing.
* 
* @return the currently measured distance in cm.
*/
 
int DistanceSensor::getDistance() {
	return sensor.ping_cm();
}
 
////////////////////////////////////////
// Pusher class
////////////////////////////////////////
 
/**
* setup method for the pusher.
* sets the pin to which the relay controller of the pusher is connected
* and sets the pin to HIGH as default because that is needed for the relay.
*
* @param pusherPin: the pin to which the relay controller is connected.
*/
 
void Pusher::setup(int pusherPin) {
	this-> pusherPin = pusherPin;
	pinMode(pusherPin, OUTPUT);
	digitalWrite(pusherPin, HIGH);
}
 
/**
* method to trigger the pusher.
* pusher should not be triggerd for longer than 500ms continously.
*
* @param duration: the duration for which the pusher should be triggerd in ms.
*/
 
void Pusher::push(int duration) {
	digitalWrite(pusherPin, LOW);
	delay(duration);
	digitalWrite(pusherPin, HIGH);
}
 
////////////////////////////////////////
// Barrier class
////////////////////////////////////////
 
/**
* setup method for the barrier class. 
* the setup mehod has to be called, before the implicit constructed objects can be used.
*
* @param servoPin: the pin to which the servo of the barrier is connected,
*		 closedPos: the servo position in which the barrier is closed,
*		 openPos: the servo position in which the barrier is opened.
*/
 
void Barrier::setup(int servoPin, int closedPos, int openPos) {
	this-> closedPos = closedPos;
	this-> openPos = openPos;
	myServo.setup(servoPin, openPos, false);
	closed = false;
}
 
/**
* method that open the barrier.
* sets the servo to the specified open position.
*/
 
void Barrier::openBarrier() {
	if (closed) {
		myServo.setPos(openPos);
		closed = false;
		delay(1000);
	}
}
 
/**
* method that closes the barrier.
* sets the servo to the specified closed position.
*/
 
void Barrier::closeBarrier() {
	if (!closed) {
		myServo.setPos(closedPos);
		closed = true;
		delay(1000);
	}
}
 
 
////////////////////////////////////////
// ContactSensor class
////////////////////////////////////////
 
/**
* setup method for the contact sensor class.
* the setup mehod has to be called, before the implicit constructed objects can be used.
*
* @param leftButtonPin: pin to which the left button is connected,
*		 rightButtonPin: pin to which the right button is connected,
*		 conductorPin: pin to which the conduction signal is connected.
*/
 
void ContactSensor::setup(int leftButtonPin, int rightButtonPin, int conductorPin) {
	this-> leftButtonPin = leftButtonPin;
	this-> rightButtonPin = rightButtonPin;
	this-> conductorPin = conductorPin;
 
	pinMode(leftButtonPin, INPUT);
	pinMode(rightButtonPin, INPUT);
	pinMode(conductorPin, INPUT);
}
 
/**
* method to check if the left button is pushed.
*
* @return true if button is pushed, false if not.
*/
 
boolean ContactSensor::leftButtonPushed() {
	return (digitalRead(leftButtonPin) == HIGH);
}
 
/**
* method to check if the right button is pushed.
*
* @return true if button is pushed, false if not.
*/
 
boolean ContactSensor::rightButtonPushed() {
	return (digitalRead(leftButtonPin) == HIGH);
}
 
/**
* method to check if an electric current is flowing.
*
* @return true if button is pushed, false if not.
*/
 
boolean ContactSensor::isConducting() {
	if (conductorPin > 0) {
		return (digitalRead(leftButtonPin) == HIGH);
	}
	return false;
}
 
////////////////////////////////////////
// StepperMotor class
////////////////////////////////////////
 
/**
* setup method for the stepper motor class.
* the setup mehod has to be called, before the implicit constructed objects can be used.
*
* @param stepPin: the pin which is connected to the stepper pin of the motor driver,
		 directionPin: the pin which is connected to the direction pin of the motor driver.
*/
 
void StepperMotor::setup(int stepPin, int directionPin) {
	this-> stepPin = stepPin;
	this-> directionPin = directionPin;
 
	pinMode(stepPin, OUTPUT);
	pinMode(directionPin, OUTPUT);
 
	Serial.println("motor");
}
 
/**
* method to make one step.
* one step is an 1.8 degree turn of the axis.
*
* @param stepDirection: defines the direction in which the step is made.
*/
 
void StepperMotor::makeStep(boolean stepDirection){    
  if (stepDirection){
    digitalWrite(directionPin, HIGH);
  }
  else {
    digitalWrite(directionPin,LOW);
  }
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(1);
  digitalWrite(stepPin, LOW);  
}
 
////////////////////////////////////////
// Gear class
////////////////////////////////////////
 
/**
* setup method for the gear class.
* the setup mehod has to be called, before the implicit constructed objects can be used.
*
* @param wheelDiameter: diameter of the wheel,
* 		 axisDistance: length of the axis (distance between the weels),
*		 leftMotorStepPin: stepper pin of the left stepper motor,
*		 leftMotorDirPin: direction pin of the left stepper motor,
		 rightMotorStepPin: stepper pin of the right stepper motor,
		 rightMotorDirPin: stepper pin of the right stepper motor.
*/
 
void Gear::setup(float wheelDiameter, float axisDistance, int leftMotorStepPin, int leftMotorDirPin, int rightMotorStepPin, int rightMotorDirPin) {
	this-> wheelDiameter = wheelDiameter;
	this-> axisDistance = axisDistance;	
	leftMotor.setup(leftMotorStepPin, leftMotorDirPin);
	rightMotor.setup(rightMotorStepPin, rightMotorDirPin);
}
 
/**
* method to drive in a straight line.
* 
* @param distance: the distance to drive in cm,
*		 stepSpeed: delay between to steps in ms,
*		 driveDirection: true to drive forward, false to drive backwards.
*/
 
void Gear::drive(float distance, int stepSpeed, boolean driveDirection) {
	//stepsValue ist die Anzahl der Schritte die jeder Motor machen muss
	float stepsValue = round(distance/((wheelDiameter*PI)/200));
	//Beide Motoren fahren in die gleiche Richtung. Da der eine aber umgedreht ist, bekommen sie unterschiedliche direction Anweisungen.
	for (int countSteps = 0; countSteps < stepsValue; countSteps++) {
		rightMotor.makeStep(driveDirection);                                                      
		leftMotor.makeStep(!driveDirection);
		delay(stepSpeed);                                                    
	}	
}
 
/**
* method to turn the robot to a servo position.
* if the servo is not in the tolarance range (90 - tolerance/2 < servoPos > 90 + tolerance/2),
* the robot is turned in the direction which the servo, respectivly the mounted sensor, is facing.
*
* @param servoPos: the position of the servo,
*		 stepSpeed: the delay between the stepper motor steps,
*		 tolerance: the tolerance range (90 - tolerance/2 < servoPos > 90 + tolerance/2);
*		 partAngle: the angle for the turning of the robot.
*/
 
void Gear::turnToServoPos(int servoPos, int stepSpeed, int tolerance, int partAngle) {
	boolean turnDirection = true;
 
	if (servoPos > 90 + tolerance/2 || servoPos < 90 - tolerance/2) {
		if (servoPos > 90) {
			turnAngle(partAngle, !turnDirection, stepSpeed);
		}
		else {
			turnAngle(partAngle, turnDirection, stepSpeed);
		}	
	}
}
 
/**
* method to turn the robot by an specific angle.
*
* @param angle: amount of degrees (0 - 360) by which the robot should turn,
*		 turnDirection: true --> anti-clockwise turning, false --> clockwise turning,
*		 stepSpeed: the delay between two steps oft the stepper motors.
*/
 
void Gear::turnAngle (int angle, boolean turnDirection, int stepSpeed) {
	float stepsValue = round(angle/(360.0/((axisDistance*PI)/((wheelDiameter*PI)/200.0))));
 
	for (int countSteps = 0; countSteps < stepsValue; countSteps++) {
		if (turnDirection) {
			rightMotor.makeStep(false);
			leftMotor.makeStep(false);
			delay(stepSpeed);
		}
		else {
			rightMotor.makeStep(true);
			leftMotor.makeStep(true);
			delay(stepSpeed);
		}
	}
}

ThermalCam

ThermalCam.h

ThermalCam.h
#ifndef ThermalCam_h
#define ThermalCam_h
 
 
#include "Arduino.h"
#include "i2c_t3.h"
#include "teensy3_Melexis90620.h"
#include "BeerBotLib.h"
 
class ThermalCam {
	private:
		Melexis90620 sensor;
		NewServo myServo;
 
		int sweepSpeed;
		int servoSpeed;
		float tolerance;
 
		double* pixelTemps;
		double pixelCompressedTo16[16];
		double midPixels;
		double leftSide;
		double rightSide;
		double pixelSum;
		double coldestPixel;
		double temperatureBorder;
		double pixelCompressedTo8[8];
		int dire;
		int servoRange;
		float searchTolerance;
 
		boolean foundColdPixel();
		void getThermalData();
		void summarizeVerticalPixels();
		void summarizeMidPixels();
		boolean checkMidPixelsForCold();
		void summarizeSides();
		void moveToColderSide();
		void moveToCold();
		void searchColdestPixel();
		void compressPixelTo8();
	public:
		void setup(int servoPin, int temperatureBorder);
		boolean searchColdSpot();
		void followColdSpot();
		int getPos();
};
 
#endif

ThermalCam.cpp

ThermalCam.cpp
#include <ThermalCam.h>
 
void ThermalCam::setup(int servoPin, int temperatureBorder){
	myServo.setup(servoPin, 90, true);
	sensor.init(16);
 
	this-> sweepSpeed = 2;
	this-> servoSpeed = 1;
	this-> tolerance = 1.5;
	this-> midPixels = 0.0;
	this-> leftSide = 0.0;
	this-> rightSide = 0.0;
	this-> pixelSum = 0.0;
	this-> coldestPixel = 0.0;
	this-> temperatureBorder = temperatureBorder;
	this-> dire = 0.0;
	this-> servoRange = 90;
	this-> searchTolerance = 1.5;
}
 
void ThermalCam::getThermalData() {
  sensor.readTemperatures();
  pixelTemps = sensor.getPixelTemperatures();
}
 
void ThermalCam::summarizeVerticalPixels() {
  for( int x = 0; x < 16; x++ ) {
    for( int y = 0; y < 4; y++ ) {
      pixelSum += pixelTemps[ y + x * 4 ];
    }
    pixelCompressedTo16[x] = pixelSum / 4.0;
    pixelSum = 0.0;
  }
}
 
void ThermalCam::summarizeMidPixels() {
  midPixels = ( pixelCompressedTo16[8] + pixelCompressedTo16[9] ) / 2;
}
 
boolean ThermalCam::checkMidPixelsForCold() {
	return (midPixels < temperatureBorder);
}
 
void ThermalCam::summarizeSides() {
    for( int x = 3; x < 8; x++ ) {
    rightSide += pixelCompressedTo16[x];
  }
  rightSide /= 7;
    for( int x = 8; x < 13; x++ ) {
    leftSide += pixelCompressedTo16[x];
  }
  leftSide /= 7;
}
 
void ThermalCam::moveToColderSide() {
  if( leftSide < rightSide && ( rightSide - leftSide ) > tolerance ) myServo.moveLeft((int)servoSpeed, 15);
  else if( rightSide < leftSide && ( leftSide - rightSide ) > tolerance ) myServo.moveRight((int)servoSpeed, 15);
  else;
}
 
boolean ThermalCam::searchColdSpot() {
	myServo.setPos(90);
	delay(100);
	for (int i = 0; i < servoRange; i++) {
		myServo.sweep((int)sweepSpeed, servoRange, 15);
		getThermalData();
		for (int i = 28; i < 36; i++) {
			Serial.println(pixelTemps[i]);
		}
		// summarizeVerticalPixels();
		// summarizeMidPixels();
		if (foundColdPixel()) {
			return true;
		}
	}
	return false;
}
 
void ThermalCam::followColdSpot() {
	getThermalData();
	//summarizeVerticalPixels();
    //compressPixelTo8();
    searchColdestPixel();
    moveToCold();
}
 
int ThermalCam::getPos() {
  return myServo.getPos();
}
 
void ThermalCam::moveToCold() {
  if(dire < 28 && coldestPixel < temperatureBorder && getPos() < 90 + servoRange/2) {
	  myServo.setPos(getPos() + (int)servoSpeed);
	  delay(10);
  }
  else if(dire > 27 && coldestPixel < temperatureBorder && getPos() > 90 - servoRange/2) {
	  myServo.setPos(getPos() - (int)servoSpeed);
	  delay(10);
  }
}
 
boolean ThermalCam::foundColdPixel() {
  for( int i = 28; i < 35; i++ )
  {
    if( pixelTemps[i] < temperatureBorder )
    {
		return true;
    }
  }
  return false;
}
 
void ThermalCam::searchColdestPixel() {
  coldestPixel = pixelTemps[4];
  for( int i = 5; i < 60; i++ )
  {
    if( pixelTemps[i] < coldestPixel && ( coldestPixel - pixelTemps[i] ) > searchTolerance )
    {
    coldestPixel = pixelTemps[i];
    dire = i;
    }
  }
}
 
void ThermalCam::compressPixelTo8() {
  summarizeVerticalPixels();
  int j = 0;
  for( int i = 0; i < 8; i++, j += 2 )
  {
    pixelCompressedTo8[i] = pixelCompressedTo16[j] + pixelCompressedTo16[j + 1];
    pixelCompressedTo8[i] /= 2;
  }
}

3rd party libraries

i2c_t3

teensy3_Melexis90620

Library to control the Melexis90620 thermal camera

https://github.com/Zapalot/teensy3_Melexis90620

NewPing

Library for improved usage of an ultrasonic distance sensor.

https://github.com/PaulStoffregen/NewPing

projekte2014/beerbot/dokumentation/software.1406634061.txt.gz · Zuletzt geändert: 2016/01/21 12:45 (Externe Bearbeitung)