Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • danc/MicroCART
  • snawerdt/MicroCART_17-18
  • bbartels/MicroCART_17-18
  • jonahu/MicroCART
4 results
Show changes
Showing
with 2666 additions and 101 deletions
# groundStation
## Make Process
First, if submodules were not recursevly added through git. Run this command if you have made any attempt to make vrpn manually.
run
'git submodule update --init --recursive'
Now that you have all of the files necissary.
cd into the groundstation folder.
cd groundStation
make vrpn
make
run the program with sudo privledges
sudo -E ./BackEnd
If you wish to change the way the backend communicates to the quad and vice versa, look at src/config.h.
This provides a list of environment variables which you can set and use for your computer or time of use.
Because the backend must be ran with sudo privledges, you will need to preserve the env. vars. with sudo rights.
Hence the "-E" flag.
## Modifying
See MODIFYING for the software architecture/organization and how to add new functionality.
## Using
First, the backend daemon must be running. Run the backend with ./BackEnd. Note
the environment variables in config.h, especially the backend socket path. The backend
requires root for bluetooth, but can run as a normal user with TCP, as long as the
socket path is writable by the user.
Once the backend is running, various CLI tools can be used to view the state of the
quad and send commands. Each of these tools is given as the first argument
to the CLI program, for example, to monitor the quad, use `cli monitor`. Note that
the backend socket environment variable must be set to the same value as it
was for the backend. The CLI program also supports busybox-style symbolic links.
For example, if there is a symlink named `monitor` that points to the `cli` binary,
running the `monitor` program will effectively run `cli monitor`.
The names of the binaries is subject to change.
### Example
In one terminal or screen, run the backend:
`UCART_SOCKET=./ucart.socket ./BackEnd`
This will activate the quad and the backend, and the backend will be available for
connections from the frontend tools. One useful tool is the monitor. In another
terminal window, run the monitor forever:
`UCART_SOCKET=./ucart.socket ./cli monitor -f`
This will begin a periodic monitoring that updates 10 times per second.
Finally, in a third window, export the socket path:
`export UCART_SOCKET=./ucart.socket`
and then run any other tools to modify the quad, for example modifying PID constants:
`./cli setpid --pitch -p 1.000`
This diff is collapsed.
This diff is collapsed.
#ifndef _COMMANDS_H
#define _COMMANDS_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "type_def.h"
// ----------------------
// Helper stuff
#define MAX_TYPE 6
#define MAX_SUBTYPE 100
enum Message{
BEGIN_CHAR = 0xBE,
END_CHAR = 0xED
};
// This should also have double to avoid confusion with float values.
enum DataType
{
floatType,
intType,
stringType
};
// MESSAGE SUBTYPES
struct MessageSubtype{
char ID;
char cmdText[100];
char cmdDataType;
int (*functionPtr)(unsigned char *command, int dataLen, modular_structs_t *structs);
};
// MESSAGE TYPES
struct MessageType{
char ID;
struct MessageSubtype subtypes[MAX_SUBTYPE];
};
int debug(unsigned char *c, int dataLen, modular_structs_t *structs);
int update(unsigned char *c, int dataLen, modular_structs_t *structs);
int logdata(unsigned char *c, int dataLen, modular_structs_t *structs);
int response(unsigned char *packet, int dataLen, modular_structs_t *structs);
int setyaw(unsigned char *c, int dataLen, modular_structs_t *structs);
int setyawp(unsigned char *c, int dataLen, modular_structs_t *structs);
int setyawd(unsigned char *c, int dataLen, modular_structs_t *structs);
int setroll(unsigned char *c, int dataLen, modular_structs_t *structs);
int setrollp(unsigned char *c, int dataLen, modular_structs_t *structs);
int setrolld(unsigned char *c, int dataLen, modular_structs_t *structs);
int setpitch(unsigned char *c, int dataLen, modular_structs_t *structs);
int setpitchp(unsigned char *c, int dataLen, modular_structs_t *structs);
int setpitchd(unsigned char *c, int dataLen, modular_structs_t *structs);
int setthrottle(unsigned char *c, int dataLen, modular_structs_t *structs);
int setthrottlep(unsigned char *c, int dataLen, modular_structs_t *structs);
int setthrottlei(unsigned char *c, int dataLen, modular_structs_t *structs);
int setthrottled(unsigned char *c, int dataLen, modular_structs_t *structs);
int getyaw(unsigned char *c, int dataLen, modular_structs_t *structs);
int getyawp(unsigned char *c, int dataLen, modular_structs_t *structs);
int getyawd(unsigned char *c, int dataLen, modular_structs_t *structs);
int getroll(unsigned char *c, int dataLen, modular_structs_t *structs);
int getrollp(unsigned char *c, int dataLen, modular_structs_t *structs);
int getrolld(unsigned char *c, int dataLen, modular_structs_t *structs);
int getpitch(unsigned char *c, int dataLen, modular_structs_t *structs);
int getpitchp(unsigned char *c, int dataLen, modular_structs_t *structs);
int getpitchd(unsigned char *c, int dataLen, modular_structs_t *structs);
int getthrottle(unsigned char *c, int dataLen, modular_structs_t *structs);
int getthrottlep(unsigned char *c, int dataLen, modular_structs_t *structs);
int getthrottlei(unsigned char *c, int dataLen, modular_structs_t *structs);
int getthrottled(unsigned char *c, int dataLen, modular_structs_t *structs);
int getaccel(unsigned char *c, int dataLen, modular_structs_t *structs);
int getgyro(unsigned char *c, int dataLen, modular_structs_t *structs);
int getpitchangle(unsigned char *c, int dataLen, modular_structs_t *structs);
int getrollangle(unsigned char *c, int dataLen, modular_structs_t *structs);
int respaccel(unsigned char *c, int dataLen, modular_structs_t *structs);
int respgyro(unsigned char *c, int dataLen, modular_structs_t *structs);
int resppitchangle(unsigned char *c, int dataLen, modular_structs_t *structs);
int resprollangle(unsigned char *c, int dataLen, modular_structs_t *structs);
int respyaw(unsigned char *c, int dataLen, modular_structs_t *structs);
int respyawp(unsigned char *c, int dataLen, modular_structs_t *structs);
int respyawd(unsigned char *c, int dataLen, modular_structs_t *structs);
int resproll(unsigned char *c, int dataLen, modular_structs_t *structs);
int resprollp(unsigned char *c, int dataLen, modular_structs_t *structs);
int resprolld(unsigned char *c, int dataLen, modular_structs_t *structs);
int resppitch(unsigned char *c, int dataLen, modular_structs_t *structs);
int resppitchp(unsigned char *c, int dataLen, modular_structs_t *structs);
int resppitchd(unsigned char *c, int dataLen, modular_structs_t *structs);
int respthrottle(unsigned char *c, int dataLen, modular_structs_t *structs);
int respthrottlep(unsigned char *c, int dataLen, modular_structs_t *structs);
int respthrottlei(unsigned char *c, int dataLen, modular_structs_t *structs);
int respthrottled(unsigned char *c, int dataLen, modular_structs_t *structs);
int respaccel(unsigned char *c, int dataLen, modular_structs_t *structs);
int respgyro(unsigned char *c, int dataLen, modular_structs_t *structs);
int resppitchangle(unsigned char *c, int dataLen, modular_structs_t *structs);
int resprollangle(unsigned char *c, int dataLen, modular_structs_t *structs);
float getFloat(unsigned char* str, int pos);
int getInt(unsigned char* str, int pos);
// TODO add in string to be read from the command line when sending a subtype of message
extern struct MessageType MessageTypes[MAX_TYPE];
#endif
\ No newline at end of file
......@@ -52,84 +52,95 @@ int checkInt(char *intString, int *value) {
//--------------------------------
// Formatting commands from ground station CLI
int formatCommand(unsigned char *command, unsigned char **formattedCommand) {
//command[strlen((char *)command) - 1] = 0;
tokenList_t tokens = tokenize((char *)command);
int formatCommand(char *command, unsigned char **formattedCommand) {
//fprintf(stderr, "length = %li , received '%s'\n", strlen(command), command);
char cmd[strlen(command)];
strncpy(cmd, command, strlen(command));
cmd[strlen(command)] = '\0';
tokenList_t tokens = tokenize(cmd);
float floatValue = 0.0;
int intValue = 0;
int valid;
metadata_t metadata = {};
metadata_t metadata;
// ----------------------------------------------
if(tokens.numTokens > 1) {
for(int cmdIndex = 0; cmdIndex < NUM_COMMANDS; ++cmdIndex)
if(tokens.numTokens > 0) {
for(int type = 0; type < MAX_TYPE; type++)
{
if(strcmp(tokens.tokens[0], registeredCommands[cmdIndex].commandText) == 0)
for(int subtype = 0; subtype < MAX_SUBTYPE; subtype++)
{
switch (registeredCommands[cmdIndex].dataType)
if(strcmp(tokens.tokens[0], MessageTypes[type].subtypes[subtype].cmdText) == 0)
{
// Validate the float input
case floatType:
valid = checkFloat(tokens.tokens[1], &floatValue);
if(!valid) {
return -1;
}
printf("%f, %s\n", floatValue, tokens.tokens[1]);
metadata.begin_char = BEGIN_CHAR;
metadata.msg_type = registeredCommands[cmdIndex].ID;
metadata.msg_subtype = registeredCommands[cmdIndex].subID;
metadata.msg_id = msgNum++;
metadata.data_len = sizeof(floatValue);
formatPacket(&metadata, &floatValue, formattedCommand);
break;
// Validate the integer input
case intType:
valid = checkInt(tokens.tokens[1], &intValue);
if(!valid) {
return -1;
}
metadata.begin_char = BEGIN_CHAR;
metadata.msg_type = registeredCommands[cmdIndex].ID;
metadata.msg_subtype = registeredCommands[cmdIndex].subID;
metadata.msg_id = msgNum++;
metadata.data_len = sizeof(intValue);
formatPacket(&metadata, &intValue, formattedCommand);
break;
printf("Sending\n\ttype: %d, \n\tsubtype: %d\n\tcommand: %s\n", type, subtype, MessageTypes[type].subtypes[subtype].cmdText);
// Validate the string input (doesn't need to happen)
case stringType:
metadata.begin_char = BEGIN_CHAR;
metadata.msg_type = registeredCommands[cmdIndex].ID;
metadata.msg_subtype = registeredCommands[cmdIndex].subID;
metadata.msg_id = msgNum++;
metadata.data_len = strlen(tokens.tokens[1]);
// Make sure the second token is the right type
switch (MessageTypes[type].subtypes[subtype].cmdDataType)
{
// Validate the float input
case floatType:
metadata.begin_char = (char) BEGIN_CHAR;
metadata.msg_type = MessageTypes[type].ID;
metadata.msg_subtype = MessageTypes[type].subtypes[subtype].ID;
if(MessageTypes[type].ID == 0x01) {
valid = checkFloat(tokens.tokens[1], &floatValue);
if(!valid) {
return -1;
}
metadata.data_len = sizeof(floatValue);
} else {
metadata.data_len = 0;
}
metadata.msg_id = msgNum++;
formatPacket(&metadata, &floatValue, formattedCommand);
break;
formatPacket(&metadata, &tokens.tokens[1], formattedCommand);
// Validate the integer input
case intType:
metadata.begin_char = (char) BEGIN_CHAR;
metadata.msg_type = MessageTypes[type].ID;
metadata.msg_subtype = MessageTypes[type].subtypes[subtype].ID;
if(MessageTypes[type].ID == 0x01) {
valid = checkInt(tokens.tokens[1], &intValue);
if(!valid) {
return -1;
}
metadata.data_len = sizeof(intValue);
} else {
metadata.data_len = 0;
}
metadata.msg_id = msgNum++;
formatPacket(&metadata, &intValue, formattedCommand);
break;
break;
default:
return -1;
// Validate the string input (doesn't need to happen)
case stringType:
metadata.begin_char = (char) BEGIN_CHAR;
metadata.msg_type = MessageTypes[type].ID;
metadata.msg_subtype = MessageTypes[type].subtypes[subtype].ID;
metadata.msg_id = msgNum++;
metadata.data_len = strlen(tokens.tokens[1]);
formatPacket(&metadata, &tokens.tokens[1], formattedCommand);
break;
default:
return -1;
}
return 0;
}
return 0;
}
}
}
// Only gets here if the command does not exist
return -1;
return -1;
}
// QUAD & Ground Station
// Format the log data from log_message
//int formatData(unsigned char *log_msg, unsigned char *formattedCommand)
......@@ -154,7 +165,8 @@ int formatPacket(metadata_t *metadata, void *data, unsigned char **formattedComm
(*formattedCommand)[2] = metadata->msg_subtype;
//Msg id (msgNum is 2 bytes)
(*formattedCommand)[3] = metadata->msg_id;
(*formattedCommand)[3] = (metadata->msg_id & 0x000000ff);
(*formattedCommand)[4] = ((metadata->msg_id >> 8) & 0x000000ff);
// Data length and data - bytes 5&6 for len, 7+ for data
(*formattedCommand)[5] = metadata->data_len & 0x000000ff;
......@@ -232,7 +244,7 @@ int parse_packet(unsigned char * packet, unsigned char ** data, metadata_t * met
// QUAD & Ground Station
// Process the command received
int processCommand(unsigned char *packet, unsigned int cmdIndex) {
int processCommand(unsigned char *packet, modular_structs_t *structs) {
int validPacket;
unsigned char *data;
metadata_t metadata;
......@@ -244,9 +256,13 @@ int processCommand(unsigned char *packet, unsigned int cmdIndex) {
}
if(metadata.data_len >= 0) {
// Call the appropriate subtype function
(* (registeredCommands[cmdIndex].functionPtr))(data, metadata.data_len);
/* Null check*/
if (MessageTypes[(unsigned char)metadata.msg_type].subtypes[
(unsigned char) metadata.msg_subtype].functionPtr) {
// Call the appropriate subtype function
(* (MessageTypes[(unsigned char)metadata.msg_type].subtypes[(unsigned char)metadata.msg_subtype].functionPtr))(data, metadata.data_len, structs);
}
return 0;
}
......
......@@ -10,12 +10,10 @@
tokenList_t tokenize(char* cmd);
int checkFloat(char *floatString, float *value);
int checkInt(char *intString, int *value);
int formatCommand(unsigned char *command, unsigned char **formattedCommand);
int formatCommand(char *command, unsigned char **formattedCommand);
int formatPacket(metadata_t *metadata, void *data, unsigned char **formattedCommand);
int parse_packet(unsigned char * packet, unsigned char ** data, metadata_t * meta_data);
int processCommand(unsigned char *command, unsigned int cmdIndex);
int processCommand(unsigned char *command, modular_structs_t *structs);
int logData(unsigned char *log_msg, unsigned char *formattedCommand);
float getFloat(unsigned char* str, int pos);
int getInt(unsigned char* str, int pos);
#endif
#endif
\ No newline at end of file
#ifndef __CONFIG_H
#define __CONFIG_H
#define DEFAULT_SOCKET "/var/run/ucart.socket"
#define SOCKET_ENV "UCART_SOCKET"
#define NOQUAD_ENV "UCART_NO_QUAD"
#define NOVRPN_ENV "UCART_NO_VRPN"
// If you are planning on using any of these env vars and you have
// exported them with normal user rights. You will need to run the
// backend with sudo elevation and with the --preserve-env flag or -E
#define QUAD_WIFI_ENV "UCART_USE_WIFI"
#define QUAD_IP_ENV "UCART_QUAD_IP"
#define QUAD_IP_DEFAULT "192.168.4.1"
#define QUAD_PORT_ENV "UCART_QUAD_PORT"
#define QUAD_PORT_DEFAULT 8080
#endif
......@@ -4,21 +4,30 @@
*/
#include "logger.h"
#include <stdio.h>
#include <err.h>
#include <pthread.h>
int quadlog_file;
static FILE * quadlog_file = NULL;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int createLogFile(int argc, char* argv)
{
char log_file[300] = {'l', 'o', 'g','s', '/'};
if (quadlog_file != NULL) {
return -1;
}
if (pthread_mutex_lock(&mutex)) {
err(-2, "pthrtead_mutex_lock (%s:%d):", __FILE__, __LINE__);
}
char log_file[300];
strcpy(log_file, "logs/");
if(argc >= 2)
{
strcat(log_file, argv);
strncat(log_file, argv, 294);
printf("Creating log file '%s'...\n",log_file);
quadlog_file = open(log_file, O_WRONLY | O_CREAT, 0666);
return quadlog_file;
}
else
{
quadlog_file = fopen(log_file, "a");
} else {
time_t rawtime;
char timestr [30];
time(&rawtime);
......@@ -26,7 +35,7 @@ int createLogFile(int argc, char* argv)
// Lets convert space to _ in
char *p = timestr;
int i = 0;
size_t i = 0;
while(i < strlen(timestr))
{
if (*p == ' ')
......@@ -40,18 +49,60 @@ int createLogFile(int argc, char* argv)
strncat(log_file, timestr, strlen(timestr) -1 );
strcat(log_file, ".txt");
printf("Creating log file '%s'...\n",log_file);
quadlog_file = open(log_file, O_WRONLY | O_CREAT, 0666);
return quadlog_file;
quadlog_file = fopen(log_file, "a");
}
if (pthread_mutex_unlock(&mutex)) {
err(-2, "pthrtead_mutex_unlock (%s:%d):", __FILE__, __LINE__);
}
return 0;
}
int updateLogFile(const struct ucart_vrpn_TrackerData * td)
{
return dprintf(quadlog_file, "FPS: %lf Pos (xyz): (%lf %lf %lf) Att (pry): (%lf %lf %lf)\n",
int retval;
if (pthread_mutex_lock(&mutex)) {
err(-2, "pthrtead_mutex_lock (%s:%d):", __FILE__, __LINE__);
}
retval = fprintf(quadlog_file,
"FPS: %lf Pos (xyz): (%lf %lf %lf) Att (pry): (%lf %lf %lf)\n",
td->fps, td->x, td->y, td->z, td->pitch, td->roll, td->yaw);
if (pthread_mutex_unlock(&mutex)) {
err(-2, "pthrtead_mutex_unlock (%s:%d):", __FILE__, __LINE__);
}
return retval;
}
int writeStringToLog(const char * string)
{
return dprintf(quadlog_file, "%s", string);
int retval;
if (pthread_mutex_lock(&mutex)) {
err(-2, "pthrtead_mutex_lock (%s:%d):", __FILE__, __LINE__);
}
retval = fprintf(quadlog_file, "%s", string);
if (pthread_mutex_unlock(&mutex)) {
err(-2, "pthrtead_mutex_unlock (%s:%d):", __FILE__, __LINE__);
}
return retval;
}
void closeLogFile(void)
{
if (pthread_mutex_lock(&mutex)) {
err(-2, "pthrtead_mutex_lock (%s:%d):", __FILE__, __LINE__);
}
fclose(quadlog_file);
if (pthread_mutex_unlock(&mutex)) {
err(-2, "pthrtead_mutex_unlock (%s:%d):", __FILE__, __LINE__);
}
}
......@@ -15,6 +15,7 @@
int createLogFile(int, char*);
int writeStringToLog(const char*);
int updateLogFile(const struct ucart_vrpn_TrackerData* );
void closeLogFile();
#endif
\ No newline at end of file
#endif
File moved
#include <iostream>
#include <algorithm>
#include <functional>
#include "vrpn_Tracker.h"
#include "quat.h"
......@@ -9,28 +10,25 @@
namespace microcart
{
static void VRPN_CALLBACK vrpn_cb(void * param, const vrpn_TRACKERCB t);
TrackerData::TrackerData() :
x(0.0), y(0.0), z(0.0),
pitch(0.0), roll(0.0), yaw(0.0),
fps(0.0), timestamp()
{
}
Tracker::Tracker(std::string server) : Tracker(server.c_str())
Tracker::Tracker(std::string server) :
remote(server.c_str()),
stop_flag(0),
trackerData()
{
}
Tracker::Tracker(const char * server) :
remote(server),
stop_flag(0),
trackerData({
.x = 0.0,
.y = 0.0,
.z = 0.0,
.pitch = 0.0,
.roll = 0.0,
.yaw = 0.0,
.fps = 0.0,
.timestamp = {
.tv_sec = 0,
.tv_usec = 0
}
})
trackerData()
{
remote.register_change_handler(this, vrpn_cb);
......@@ -92,10 +90,9 @@ namespace microcart
trackerData.fps = 1.0 / elapsed_time_usec;
auto td = trackerData;
std::for_each(cb_vector.begin(), cb_vector.end(),
[td](std::function<void(const TrackerData &)> &fn){
fn(td);
});
for(auto i = cb_vector.begin(); i != cb_vector.end(); ++i) {
(*i)(td);
}
}
void Tracker::addCallback(std::function<void(const TrackerData&)> cb)
......@@ -115,6 +112,20 @@ struct ucart_vrpn_tracker {
microcart::Tracker * t;
};
void cb_wrapper(void (*cb)(struct ucart_vrpn_TrackerData *),
const microcart::TrackerData &td)
{
struct ucart_vrpn_TrackerData data;
data.x = td.x;
data.y = td.y;
data.z = td.z;
data.pitch = td.pitch;
data.roll = td.roll;
data.yaw = td.yaw;
data.fps = td.fps;
(*cb)(&data);
}
extern "C"
{
struct ucart_vrpn_tracker * ucart_vrpn_tracker_createInstance(
......@@ -123,6 +134,7 @@ extern "C"
try {
auto inst = new struct ucart_vrpn_tracker;
inst->t = new microcart::Tracker(server);
return inst;
} catch(...) {
return NULL;
}
......@@ -138,16 +150,8 @@ extern "C"
void (*cb)(struct ucart_vrpn_TrackerData *))
{
try {
inst->t->addCallback([cb](const microcart::TrackerData & td) {
struct ucart_vrpn_TrackerData data;
data.x = td.x;
data.y = td.y;
data.z = td.z;
data.pitch = td.pitch;
data.roll = td.roll;
data.yaw = td.yaw;
(*cb)(&data);
});
auto new_cb = bind(cb_wrapper, cb, std::placeholders::_1);
inst->t->addCallback(new_cb);
} catch(...) {
return -1;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.