A more manageable listing (as well as the project files) for the device code are available here.
// UINT
type definition
#ifndef
_UINT_DEF_
#define
_UINT_DEF_
typedef
unsigned int UINT;
#endif /* _UINT_DEF_ */
// BYTE
type definition
#ifndef
_BYTE_DEF_
#define
_BYTE_DEF_
typedef
unsigned char BYTE;
#endif /* _BYTE_DEF_ */
//
Global Definitions
#define
NUM_CHANNELS 6
#define
DATA_PACKET_LENGTH 10
//RXC
ISR variables
unsigned
char r_index; //current string index
unsigned
char r_buffer[16]; //input string
unsigned
char r_ready; //flag for receive done
unsigned
char r_char; //current character
//TX
empty ISR variables for getting input
unsigned
char t_index; //current string index
unsigned
char t_buffer[DATA_PACKET_LENGTH]; //output
string
unsigned
char t_ready; //flag for transmit done
unsigned
char t_char; //current character
// Data
channel vector
UINT
data[NUM_CHANNELS];
BYTE
time0; // sampling time counter
BYTE
time1; // transmission time
counter
//
ADMUX values for each channel selected
flash
BYTE muxvals[ NUM_CHANNELS ] = { 0b01100000,
0b01100001, 0b01100010,
0b01100011,
0b01100101, 0b01100110 };
//
Function protoytes
void Port_Init(void);
void
Timer0_Init(void);
void
ACD0_Init(void);
void
UART_Init(void);
void
send_data(void);
void
puts_int(void);
void
gets_int(void);
#include
<Mega32.h>
#include
<stdio.h> // sprintf amungst
other definitions
#include
"project.h"
/*********************************************************/
//UART
character-ready ISR
interrupt
[USART_RXC] void uart_rec(void){
r_char=UDR; //get a char
//UDR=r_char; //then print it
//build the input string
if (r_char != '\r')
r_buffer[r_index++]=r_char;
else{
putchar('\n'); //use
putchar to avoid overwrite
r_buffer[r_index]=0x00; //zero
terminate
r_ready=1; //signal cmd processor
UCSRB.7=0; //stop
rec ISR
}
}
/**********************************************************/
//UART
xmit-empty ISR
interrupt
[USART_DRE] void uart_send(void){
t_char = t_buffer[++t_index];
if(t_char == 0){
UCSRB.5=0; //kill isr
t_ready=1; //transmit done
}
else
UDR = t_char ; //send the char
}
/**********************************************************/
//
Timer 0 compare ISR
interrupt
[TIM0_COMP] void timer0_compare(void){
// increment .5ms time variables
time0++;
time1++;
}
/**********************************************************/
//Entry
point and task scheduler loop
void
main(void){
// temp vars
BYTE i, prev_time;
UINT temp;
// set timing variables to zero
time0 = 0;
time1 = 0;
Port_Init(); // set up port for
proper i/o
Timer0_Init(); // set up timer 0
ACD0_Init(); // set up ADC and start first conversion
UART_Init(); // set up UART
PORTD.7 = 0; // turn LED on
// enable interrupts
#asm
sei
#endasm
//
spin forever
while(1){
// 2.5 ms count tick
if( time0 == 5 ){
time0 = 0;
// sample each channel
continuously
for( i=0; i<NUM_CHANNELS;
i++ ){
// change channel
ADMUX = muxvals[i];
// start new conversion
ADCSRA.6=1;
// poll for completion
while( ADCSRA.6 == 1 );
// grab data
//data[i] += ADCH;
temp = (ADCL>>6);
temp |= ( (UINT)ADCH )
<< 2;
data[i] += temp;
}
}
// 10 ms count tick, send the data
if( time1 == 20 ){
time1 = 0;
send_data();
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[3] = 0;
data[4]
= 0;
data[5] = 0;
}
}//
end while(1)
}
//--------------------------------------------------------
// SEND_DATA
//--------------------------------------------------------
// send
x,y,z data out to UART
void
send_data(){
// temp variables
BYTE i, temp;
// divide the data by 4 (>>2)
for( i=0; i<NUM_CHANNELS; i++ )
data[i] = data[i]>>2;
// build the data packet
t_buffer[0] = 0x01;
t_buffer[1] = (BYTE)(data[0]&0x00FF); // data[0] lb -- x1
t_buffer[2] = (BYTE)(data[1]&0x00FF); // data[1] lb -- y1
t_buffer[3] = (BYTE)(data[2]&0x00FF); // data[2] lb -- z1
t_buffer[4]
= (BYTE)(data[3]&0x00FF); //
data[0] lb -- x2
t_buffer[5] = (BYTE)(data[4]&0x00FF); // data[1] lb -- y2
t_buffer[6] = (BYTE)(data[5]&0x00FF); // data[2] lb -- z2
temp =
(data[0]>>2)&0b11000000;
temp |= (data[1]>>4)&0b00110000;
temp |= (data[2]>>6)&0b00001100;
temp |= (data[3]>>8)&0b00000011;
t_buffer[7] = temp;
temp =
(data[4]>>2)&0b11000000;
temp |= (data[5]>>4)&0b00110000;
t_buffer[8] = temp;
t_buffer[9] = 0x00;
// send the data
puts_int();
}
//---------------------------------------------------------
// ADC0_Init
//---------------------------------------------------------
// Set
up ADC with right adjusted values
//
Start first conversion
void
ACD0_Init(void){
ADMUX =
0b01100000; // using AVCC
as reference
// /w left adjusted values
// looking @ ADC0
ADCSRA = 0b10000111; // enable ADC with interrupt on
// auto trigger off, interrupt enable
// start first conversion
ADCSRA.6
= 1;
}
//---------------------------------------------------------
// Port_Init
//---------------------------------------------------------
// Set
up I/O PORTS:
//
PORTA: input for Analog Signals
void
Port_Init(void){
DDRA = 0x00; // port A as an input
PORTA = 0xff; // turn pull-ups on
// port C,D as digital output
DDRC = 0xff;
DDRD = 0xff;
}
//---------------------------------------------------------
// Timer0_Init
//---------------------------------------------------------
// Set
up timer 0 with interrupt ticks @ .5ms
void
Timer0_Init(void){
TCCR0 = 0b00001011; // clock source @ /64 internal clock
OCR0 = 125; // compare value of 125
TIMSK = 0x02; // enable compare
match
}
//---------------------------------------------------------
// UART0_Init
//---------------------------------------------------------
// Set
up Uart @ 9600 baud
void
UART_Init(void){
UCSRB
= 0x18 ;
UBRRL
= 103 ;
//init
the task timers
r_ready=0;
t_ready=1;
}
//**********************************************************
// -- non-blocking keyboard check initializes
ISR-driven
// receive.
This routine merely sets up the ISR, which then
//does
all the work of getting a command.
void
gets_int(void){
r_ready=0;
r_index=0;
UCSRB.7=1; // enables UART_RXC interrupt
}
//**********************************************************
// -- nonblocking print: initializes ISR-driven
//
transmit. This routine merely sets up the ISR, then
//send
one character, The ISR does all the work.
void
puts_int(void){
t_ready=0;
t_index=0;
if
(t_buffer[0]>0){
putchar(t_buffer[0]);
UCSRB.5=1; // enables UART_DRE interrupt
}
}
A more manageable listing of the code (including the visual studio project files) are available here.
#define
GAMEX_MAIN
#include
<windows.h>
#include
<process.h>
#include
<stdio.h>
#include
"gamex.hpp"
#include
"LogFile.hpp"
#include
"Console.hpp"
#include
"Graph.hpp"
#include
"Button.hpp"
#include
"SerialPort.hpp"
#include
"Point.hpp"
#include
"Elbow.hpp"
#include
"Wrist.hpp"
#include
"Body.hpp"
#define
PI 3.14159f
int
width = 512;
int height = 768;
char
buffer[128];
//
Camera for 3D projections
CameraX
cam;
Vector3DF
view;
Vector3DF
axisView;
char
txt_x[] = "x";
char
txt_y[] = "y";
char
txt_z[] = "z";
// GUI
HWND
hWnd;
Console
*console;
Graph
*accGraph[3], *velGraph[3], *posGraph[3], *angGraph[3];
bool
showAllGraphs = false, graphsDisabled = true;
Button
*startLogButton, *saveLogButton, *runLogButton, *resetButton;
//
Motion Capture
Wrist
*wrist;
Elbow
*elbow;
Point
*shoulder;
Body
*body;
//
Serial Port Stuff
SerialPort
serialPort;
BYTE
ReadBuffer[255];
DWORD
BytesRead;
HANDLE
hDataMutex;
bool
dataChanged = true, dataChanged_c = true;
Vector3DF
accOne;
Vector3DF
accTwo;
UINT
b[9] = {0,0,0,0,0,0,0,0,0};
int
b_ptr = 0;
// File
Logging
LogFile
logFile;
bool
logSerialToFile = false, readFromLogFile = false;
bool
doneReadingLog = false;
OPENFILENAME
ofn;
char
szFileName[128];
BYTE
readBuf[128];
void
GameInit (void)
{
// ------------- GAMEX BEGIN
---------------
GameX.Initialize ("Motion
Capture", RUN_NOCONFIRMQUIT | VIDEO_16BIT
| VIDEO_WINDOWED | RUN_BACKGROUND |
RUN_AUTOSHOWINFO, 1280, 768);
view.x = 0; view.y = 0.5f; view.z = 250;
axisView.x = 0; axisView.y = 0; axisView.z
= 60;
cam.SetWindow (0, 0, 512, 768); // Initialize Camera
cam.SetToPosition( Vector3DF(0,0,0) ); // Set camera to look at the origin
cam.SetFromAngles( view );
GameX.SetDrawCam(&cam); // Tell GameX to draw
using the camera
// ------------- GAMEX END ---------------
// ------------- GUI BEGIN ---------------
startLogButton = new Button("Start
Log", 10, 718, 100, 758);
saveLogButton = new Button("Save
Log", 110, 718, 200, 758);
runLogButton = new Button("Run
Log", 210, 718, 300, 758);
resetButton = new
Button("Reset", 310, 718, 400, 758);
saveLogButton->Disable();
hWnd = GameX.GetWindow();
console = new
Console("consoleLog.txt", 10,10,width-10,height-10);
console->Printfn("Motion Capture
Modelling System");
console->Printfn("Debug
Interface");
accGraph[0] = new
Graph("avg_acc1.x", -40, 40, width+0, 0, width+240, 190);
accGraph[1] = new
Graph("acc1.y", -40, 40, width+256, 0, width+496, 190);
accGraph[2] = new
Graph("acc1.z", -40, 40, width+512, 0, width+752, 190);
velGraph[0] = new
Graph("vel1.x", -4, 4, width+0,
192, width+240, 382);
velGraph[1] = new
Graph("vel1.y", -0.6, 0.6, width+256, 192, width+496, 382);
velGraph[2] = new
Graph("vel1.z", -0.6, 0.6, width+512, 192, width+752, 382);
posGraph[0] = new
Graph("pos1.x", -50, 50, width+0,
384, width+240, 574);
posGraph[1] = new
Graph("pos1.y", -50, 50, width+256, 384, width+496, 574);
posGraph[2] = new
Graph("pos1.z", -50, 50, width+512, 384, width+752, 574);
angGraph[0] = new
Graph("psi1", -PI, PI, width+0,
576, width+240, 766);
angGraph[1] = new
Graph("phi1", -PI, PI,
width+256, 576, width+496, 766);
angGraph[2] = new
Graph("theta1", -PI, PI, width+512, 576, width+752, 766);
// ------------- GUI END ---------------
// ------------- MOTION CAPTURE BEGIN
---------------
shoulder = new Point( Vector3DF(0,0,0), 0,
NULL, &cam);
elbow = new Elbow( Vector3DF(0,0,-30), 30,
shoulder, &cam);
wrist = new Wrist( Vector3DF(0,-60,-30),
30, elbow, &cam);
body = new Body();
// ------------- MOTION CAPTURE END
---------------
// ------------- SERIAL PORT BEGIN
---------------
if (serialPort.Init("COM1") ==
S_OK)
{
console->Printfn("COM1
Configured Correctly.");
}
else
{
// get error and display it
char lpMsgBuf[100];
serialPort.LastError(lpMsgBuf);
console->Printfn("COM1
Configuration Error: %s", lpMsgBuf );
}
// ------------- SERIAL PORT END
---------------
// ------------- LOG FILE START
---------------
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = NULL;
ofn.lpstrFile= szFileName;
ofn.nMaxFile = sizeof(szFileName)/
sizeof(*szFileName);
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = (LPSTR)NULL;
ofn.Flags = OFN_SHOWHELP |
OFN_OVERWRITEPROMPT | OFN_CREATEPROMPT;
ofn.lpstrTitle = NULL;
// ------------- LOG FILE END
---------------
wrist->Reset();
}
float
wristPsi = 0;
float
elbowPhi = 0;
void
GameRun (void)
{
DWORD dwWaitResult;
if (readFromLogFile)
{
BytesRead =
logFile.ReadLine(ReadBuffer);
if (logFile.IsLogFinished())
{
logFile.Close();
doneReadingLog = true;
readFromLogFile = false;
startLogButton->Enable();
runLogButton->Enable();
}
}
else if( serialPort.Read(ReadBuffer,
&BytesRead) == E_FAIL )
{
// get error and display it
char lpMsgBuf[100];
serialPort.LastError(lpMsgBuf);
console->Printfn("Serial
Data Read Error: %s", lpMsgBuf );
}
for(int i=0; i<BytesRead; i++)
{
// if buffer is 0x01
if( ReadBuffer[i] == 0x01 )
b_ptr = 0;
else
b[b_ptr++] = ReadBuffer[i];
// if you have a full data packet
if( b_ptr == 8 )
{
b_ptr = 0;
b[7] = ReadBuffer[i];
// unpack the packet into
values
accOne.x = (float)b[0] +
(float)( (b[6]&0xC0)<<2 );
accOne.y = (float)b[1] +
(float)( (b[6]&0x30)<<4 );
accOne.z = (float)b[2] +
(float)( (b[6]&0x0C)<<6 );
accTwo.x = (float)b[3] + (float)(
(b[6]&0x03)<<8 );
accTwo.y = (float)b[4] +
(float)( (b[7]&0xC0)<<2 );
accTwo.z = (float)b[5] +
(float)( (b[7]&0x30)<<4 );
// display the data
console->Printfn( "%f,
%f, %f, %f, %f, %f", accOne.x, accOne.y, accOne.z, accTwo.x, accTwo.y,
accTwo.z );
elbow->Run(accTwo);
wrist->Run(accOne);
body->RotateElbow(
elbow->phi, elbow->theta );
body->RotateWrist(
wrist->phi, wrist->psi);
//body->RotateElbow(
elbowPhi, 0 );
//body->RotateWrist(
wristPsi, PI/4);
//elbowPhi += (PI/1920);
//wristPsi += (PI/480);
if (!graphsDisabled)
{
accGraph[0]->AddPoint(wrist->x_avg);//acc.x);
accGraph[1]->AddPoint(wrist->acc.y);
accGraph[2]->AddPoint(wrist->acc.z);
velGraph[0]->AddPoint(wrist->vel.x);
velGraph[1]->AddPoint(wrist->vel.y);
velGraph[2]->AddPoint(wrist->vel.z);
posGraph[0]->AddPoint(wrist->pos.x);
posGraph[1]->AddPoint(wrist->pos.y);
posGraph[2]->AddPoint(wrist->pos.z);
angGraph[0]->AddPoint(wrist->psi);
angGraph[1]->AddPoint(wrist->phi);
angGraph[2]->AddPoint(wrist->theta);
}
}
}
if (logSerialToFile)
{
for (int i = 0; i < BytesRead;
i++)
logFile.Printf("%d
", ReadBuffer[i]);
if (BytesRead > 0)
logFile.Printf("\n");
}
if (startLogButton->Run())
{
logFile.OpenForWriting("accLogFile_do_not_touch.txt");
logSerialToFile = true;
doneReadingLog = false;
saveLogButton->Enable();
}
if (saveLogButton->Run())
{
BOOL saveOK =
GetSaveFileName(&ofn);
if (saveOK)
{
logFile.Close();
logSerialToFile = false;
doneReadingLog = false;
saveLogButton->Disable();
CopyFile("accLogFile_do_not_touch.txt",
ofn.lpstrFile, FALSE);
}
}
if (runLogButton->Run() &&
!logSerialToFile)
{
BOOL openOK =
GetOpenFileName(&ofn);
if (openOK)
{
logFile.OpenForReading(ofn.lpstrFile);
readFromLogFile = true;
doneReadingLog = false;
startLogButton->Disable();
saveLogButton->Disable();
runLogButton->Disable();
}
}
if (resetButton->Run())
{
wrist->Reset();
elbow->Reset();
body->Reset();
}
// move camera view about the origin on
right button down
if( GameX.IsMouseDown(MOUSE_RIGHT) ){
view.x += GameX.GetMouseDX();
view.y += GameX.GetMouseDY();
view.z += GameX.GetMouseDZ()/20;
if( view.y < -89.9f ) view.y =
-89.9f;
if( view.y > 89.9f ) view.y = 89.9f;
if( view.z < 2.0f ) view.z = 2.0f;
cam.SetToPosition( Vector3DF(0,0,0)
);
cam.SetFromAngles( view );
axisView.x = view.x;
axisView.y = view.y;
}
// Toggle Console on '`' key press
if ( GameX.GetKeyPress(KEY_TILDE) )
console->Toggle();
if ( GameX.GetKeyPress(KEY_0) )
graphsDisabled = !graphsDisabled;
if (!graphsDisabled)
{
if ( GameX.GetKeyPress(KEY_1) )
accGraph[0]->Toggle();
if ( GameX.GetKeyPress(KEY_2) )
accGraph[1]->Toggle();
if ( GameX.GetKeyPress(KEY_3) )
accGraph[2]->Toggle();
if ( GameX.GetKeyPress(KEY_Q) )
velGraph[0]->Toggle();
if ( GameX.GetKeyPress(KEY_W) )
velGraph[1]->Toggle();
if ( GameX.GetKeyPress(KEY_E) )
velGraph[2]->Toggle();
if ( GameX.GetKeyPress(KEY_A) )
posGraph[0]->Toggle();
if ( GameX.GetKeyPress(KEY_S) )
posGraph[1]->Toggle();
if ( GameX.GetKeyPress(KEY_D) )
posGraph[2]->Toggle();
if ( GameX.GetKeyPress(KEY_Z) )
angGraph[0]->Toggle();
if ( GameX.GetKeyPress(KEY_X) )
angGraph[1]->Toggle();
if ( GameX.GetKeyPress(KEY_C) )
angGraph[2]->Toggle();
if ( GameX.GetKeyPress(KEY_9) )
{
showAllGraphs =
!showAllGraphs;
accGraph[0]->SetShowGraph(showAllGraphs);
accGraph[1]->SetShowGraph(showAllGraphs);
accGraph[2]->SetShowGraph(showAllGraphs);
velGraph[0]->SetShowGraph(showAllGraphs);
velGraph[1]->SetShowGraph(showAllGraphs);
velGraph[2]->SetShowGraph(showAllGraphs);
posGraph[0]->SetShowGraph(showAllGraphs);
posGraph[1]->SetShowGraph(showAllGraphs);
posGraph[2]->SetShowGraph(showAllGraphs);
angGraph[0]->SetShowGraph(showAllGraphs);
angGraph[1]->SetShowGraph(showAllGraphs);
angGraph[2]->SetShowGraph(showAllGraphs);
}
}
}
void
drawAxis ()
{
GameX.DrawLine(ColorX(150,150,150), 0,
height, width, height);
GameX.DrawLine(ColorX(150,150,150), width,
0, width, height);
cam.SetWindow ( width-100, 0, width, 100
);
cam.SetFromAngles( axisView );
GameX.DrawLine3D (ColorX(255,0,0),
Vector3DF(0,0,0), Vector3DF(24,0,0));
GameX.DrawLine3D (ColorX(0,255,0),
Vector3DF(0,0,0), Vector3DF(0,24,0));
GameX.DrawLine3D (ColorX(0,0,255), Vector3DF(0,0,0),
Vector3DF(0,0,24));
float x, y, z;
cam.Project( Vector3DF(24,0,0), x, y, z);
GameX.DrawText(x-5, y-5, txt_x);
cam.Project( Vector3DF(0,24,0), x, y, z);
GameX.DrawText(x-5, y-5, txt_y);
cam.Project( Vector3DF(0,0,24), x, y, z);
GameX.DrawText(x-5, y-5, txt_z);
cam.SetWindow (0, 0, width, height);
cam.SetFromAngles( view );
sprintf(buffer, "x:%5.3f, y:%5.3f,
z:%5.3f", wrist->pos.x, wrist->pos.y, wrist->pos.z);
GameX.DrawText(5,5,buffer);
sprintf(buffer, "vx:%5.3f, vy:%5.3f,
vz:%5.3f", wrist->vel.x, wrist->vel.y, wrist->vel.z);
GameX.DrawText(5,20,buffer);
sprintf(buffer, "ax:%5.3f, ay:%5.3f,
az:%5.3f", wrist->x_avg, wrist->acc.y, wrist->acc.z);
GameX.DrawText(5,35,buffer);
sprintf(buffer, "phi:%5.3f, psi:%5.3f
, theta:%5.3f", wrist->phi, wrist->psi, wrist->theta);
GameX.DrawText(5,50,buffer);
}
void
GameDraw (void)
{
GameX.ClearScreen();
// Draw Gray Background
GameX.SetView(0,0,width,height);
GameX.FillScreen (ColorX(100,100,100));
GameX.ResetView();
GameX.Begin3DScene ();
body->Draw();
//wrist->Draw();
//elbow->Draw();
shoulder->Draw();
if (!graphsDisabled)
{
accGraph[0]->Draw();
accGraph[1]->Draw();
accGraph[2]->Draw();
velGraph[0]->Draw();
velGraph[1]->Draw();
velGraph[2]->Draw();
posGraph[0]->Draw();
posGraph[1]->Draw();
posGraph[2]->Draw();
angGraph[0]->Draw();
angGraph[1]->Draw();
angGraph[2]->Draw();
}
startLogButton->Draw();
saveLogButton->Draw();
runLogButton->Draw();
resetButton->Draw();
if (logSerialToFile)
GameX.DrawText(10, 700,
"Logging...");
if (readFromLogFile)
GameX.DrawText(10, 700,
"Reading from log file...");
if (doneReadingLog)
GameX.DrawText(10, 700, "Done
Reading from log file!");
drawAxis ();
GameX.End3DScene ();
console->Draw();
}
#include
"GameX.hpp"
#define
PI 3.14159f
#define
PI_2 1.570795f
class
Body
{
private:
ImageX boxImg;
ImageX redImg;
ImageX blueImg;
ImageX bigRedImg;
ImageX faceImg1;
ImageX faceImg2;