Skip to content

Commit

Permalink
2014 Competitive Release
Browse files Browse the repository at this point in the history
Captain no longer relies on the transparent mode of the XBee along with
a rickety custom sentence-based data pattern. Thanks to the Bee
library, Captain uses the escaped API mode of the DigiMesh XBee
platform. Because of this, the handleRx methods have been very simple.
All they do is receive the callback data frame from Bee and directly
put it to use. Bee also verifies the checksum of incoming data,
preventing Captain from being led astray by malformed frames. Sending
data has also been drastically improved.

Another major improvement is the lack of Arduino String objects,
especially in time-critical code.  Better yet, absolutely no string
concatenation which can be incredibly expensive. This is thanks to
using the XBee’s API mode.

Since the 2014 release does not include a GPS I’ve removed the code
that would normally be used to send that data. It’s unfortunate but a
good GPS is not cheap.

The actual pin-outs remain entirely intact from last year.
  • Loading branch information
kmark committed Apr 6, 2014
1 parent 8e47a07 commit 88b74ed
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 204 deletions.
127 changes: 29 additions & 98 deletions CaptainBase/Base.cpp
Expand Up @@ -30,14 +30,18 @@ USB Usb;
//CaptainLCD lcd(62, 63, 64, 65, 66, 67);
Base *baseInstance = NULL;

Base::Base() : XBee(Bee(&XBEE_SERIAL, config::xbeeBaud)) {
//
}

void Base::setup() {
lcd = new CaptainLCD(config::lcdPins[0], config::lcdPins[1],
config::lcdPins[2], config::lcdPins[3],
config::lcdPins[4], config::lcdPins[5],
config::lcdPins[6], config::lcdPins[7],
config::lcdPins[8], &config::gps);
lcd->begin();

controllerConnected = false;
thrustDirection = true;
currentThrust = 0;
Expand All @@ -46,15 +50,13 @@ void Base::setup() {
oldDirection = 1;
oldThrustDirection = false;
thrustLock = false;

rxTermNum = 0;
rxSentenceType = CAPTAIN_SENTENCE_UNKNOWN;

rxSpeed = "";
rxLatitude = "";
rxLongitude = "";
rxActive = false;
rxLastTerm = 5000;

Serial.begin(115200);

if(Usb.Init() == -1) {
Expand All @@ -63,20 +65,21 @@ void Base::setup() {
}

interruptCount = 0;
XBee = &XBEE_SERIAL;
XBee->begin(config::xbeeBaud);
baseInstance = this;
TCCR2A = 0; // Wave gen mode normal
TCCR2B = 0; // Disable
TCNT2 = 130; // set timer count to 130 of 255
TIFR2 = 0; // Clear overflow flag
TIMSK2 = 1; // Enable timer compare interrupt
TCCR2B = 5; // Timer prescaler to 128

XBee.setCallback(xbeeCallback);
XBee.begin();
}

void Base::loop() {
handleController();
handleRx();
XBee.tick();
}

void Base::handleController() {
Expand Down Expand Up @@ -131,94 +134,17 @@ void Base::updateControllerBattery() {
}
}

void Base::handleRx() {
while(Serial3.available()) {
char lolz = Serial3.read();
Serial.write(lolz);
if(rxEncode(lolz)) {
if(lcd->setGPSActive(rxActive) && controllerConnected) {
PS3.setRumbleOn(25, 255, 0, 0);
};
}
}
}

// The below will probably be put into some kind
// of "CaptainCommunication" library...
// Based on NMEA and TinyGPS

bool Base::rxEncode(char c) {
bool valid = false;
switch(c) {
case ',': // term terminators
case '\r':
case '\n':
// Ignores the LF or \n in CR+LF or \r\n terminators
if(rxBufferOffset == 0) {
return valid;
}
valid = rxTermComplete();
rxBufferOffset = 0;
memset(rxBuffer, 0, sizeof(rxBuffer));
rxTermNum++;
return valid;
case '$': // sentence begin
rxSentenceType = CAPTAIN_SENTENCE_UNKNOWN;
rxTermNum = rxBufferOffset = 0;
memset(rxBuffer, 0, sizeof(rxBuffer));
return valid;
}
// Data. Not a $ or terminator. Add it to the buffer.
rxBuffer[rxBufferOffset++] = c;
return valid;
}

bool Base::rxTermComplete() {
void Base::handleRx(BeePointerFrame *frame) {
rxLastTerm = millis();
if(rxTermNum == 0) {
if(!strcmp(rxBuffer, "GPS")) {
rxSentenceType = CAPTAIN_SENTENCE_GPS;
}
}
switch (rxSentenceType) {
case CAPTAIN_SENTENCE_GPS:
switch(rxTermNum) {
case 1:
rxActive = rxBuffer[0] == 'A';
break;
case 2:
rxLatitude = String(rxBuffer);
break;
case 3:
rxLongitude = String(rxBuffer);
break;
case 4:
rxSpeed = String(rxBuffer);
break;
}
break;
default:
return false;
}
return true;
}

// dsize = sizeof(data)
void Base::rxSendTerm(int termType, char data[][15], int dsize) {
String term = "$";
switch(termType) {
case CAPTAIN_SENTENCE_CDT:
term += "CDT";
switch(frame->data[0]) {
case CaptainFrames::GPS:
rxActive = frame->data[1] == 'A';
// rxLatitude, rxLongitude, and rxSpeed are currently unused
break;
default:
return;
}
for(int i = 0; i < dsize; i++) {
term += ",";
term += data[i];
if(lcd->setGPSActive(rxActive) && controllerConnected) {
PS3.setRumbleOn(25, 255, 0, 0);
}
term += "\r\n";
XBee->println(term);
}

// Convenience function
Expand Down Expand Up @@ -246,18 +172,19 @@ void Base::handleInterrupt() {
oldThrust = currentThrust;
oldDirection = currentDirection;
oldThrustDirection = thrustDirection;
XBee->print("$CDT,");

char cdt[] = { CaptainFrames::CDT, thrustDirection ? 'F': 'R',
currentDirection, currentThrust};

XBee.sendData(cdt, sizeof cdt);

Serial.print("$CDT,");
XBee->print(thrustDirection ? 'F' : 'R');
Serial.print(thrustDirection ? 'F' : 'R');
XBee->print(',');
Serial.print(',');
XBee->print(currentDirection);
Serial.print(currentDirection);
XBee->print(',');
Serial.print(',');
XBee->println(currentThrust);
Serial.println(currentThrust);

}
}
// For things that only need to be run every once in awhile
Expand All @@ -269,3 +196,7 @@ void Base::handleInterrupt() {
ISR(TIMER2_OVF_vect) {
baseInstance->handleInterrupt();
}

void xbeeCallback(BeePointerFrame *frame) {
baseInstance->handleRx(frame);
}
24 changes: 12 additions & 12 deletions CaptainBase/Base.h
Expand Up @@ -23,14 +23,24 @@
#include "PS3USB.h"
#include "CaptainBase.h"
#include "CaptainLCD.h"
#include "Bee.h"
#include "avr/io.h"
#include "avr/interrupt.h"

void xbeeCallback(BeePointerFrame *frame);

namespace CaptainFrames {
static const uint8_t GPS = 0x47;
static const uint8_t CDT = 0x44;
}

class Base {
public:
Base();
void setup();
void loop();
void handleInterrupt();
void handleRx(BeePointerFrame *); // Handles received data from the XBee
private:
bool controllerConnected; // true if controller is connected, false otherwise
unsigned int currentThrust; // Current thrust
Expand All @@ -44,25 +54,15 @@ class Base {

void handleController(); // Handles all DS3 inputs
void updateControllerBattery();

void handleRx(); // Handles received data from the XBee
bool rxEncode(char);
bool rxTermComplete();
bool rxInTerm;
unsigned short rxTermNum;
byte rxSentenceType;
char rxBuffer[15];
unsigned int rxBufferOffset;
enum { CAPTAIN_SENTENCE_GPS, CAPTAIN_SENTENCE_CDT, CAPTAIN_SENTENCE_UNKNOWN };

String rxLatitude;
String rxLongitude;
bool rxActive;
unsigned long rxLastTerm;
String rxSpeed;
void rxSendTerm(int, char[][15], int);
bool rxStale();
unsigned int interruptCount;
HardwareSerial *XBee;
Bee XBee;
CaptainLCD *lcd;
};

Expand Down
2 changes: 1 addition & 1 deletion CaptainBase/CaptainBase.h
Expand Up @@ -27,7 +27,7 @@
//

namespace config {
const bool gps = true; // If the Ship module has a GPS onboard
const bool gps = false; // If the Ship module has a GPS onboard
const unsigned int stickSensitivity = 3; // Prevents servo convulsions
const ButtonEnum thrustLockButton = CIRCLE; // Button to use for thrust locking
const ButtonEnum thrustButton = R2; // Analog button to use for thrust control
Expand Down
3 changes: 2 additions & 1 deletion CaptainBase/CaptainBase.ino
Expand Up @@ -18,4 +18,5 @@
#include "LiquidCrystal.h"
#include "PS3BT.h"
#include "PS3USB.h"
#include "CaptainLCD.h"
#include "CaptainLCD.h"
#include "Bee.h"
3 changes: 2 additions & 1 deletion CaptainShip/CaptainShip.ino
Expand Up @@ -17,4 +17,5 @@

#include "TinyGPS.h"
#include "SoftwareSerial.h"
#include "Servo.h"
#include "Servo.h"
#include "Bee.h"

0 comments on commit 88b74ed

Please sign in to comment.