Jaluro sw sandbox
From TeamFrednetWiki
Contents |
Jaluro Test Software
I will try to publish here little software codes I use to control Jaluro. Very basic C :-), some stuff taken from I-net (not developed, just adjusted to fit). Improvements welcome.
Okay, here comes the first load, pls be aware that all code is just for my personal use on Jaluro and to see if some things work as I expect / wish it. Moreover, I will update the code within the next few days a bit - more funtions,nice looking, comments, mindmaps...
What the hell...?!
A brief intro into my idea, and what I want to do: Jaluro uses to control the two motors a little motor controller. There are a lot of circuits out there in the web - the one I have installed is allready "preprogrammed" - and understands some simple commands. I can pass the commands either via RS232 or I2C to the controller, it doesn't matter very much, just the command structure changes a bit. Currently I use the RS232 interface. A standard command looks like this:
- Character 1: # (or hex 0x23)
- Character 2: # (or hex 0x23)
- Character 3: number of following bytes in hex (max 255, FF)
- Character 4: command (in hex, e.g start motors is 0x02)
- Character 5: parameter (e.g speed,also in hex)
Then I use a low power PC104+ board as an onboard computer. It has an ARM Processor with 200Mhz, 32 MByte NAND Flash, a lot of Interfaces (USB 2.0, Ethernet, PC104,...), and needs approximatly 1.2 sec. to boot into Linux. Not to forget - I use a USB Wifi dongle for the wireless connection.
Batteries and Motors are obligatory. Now I've written (and taken from the web) some C Code. This code does following:
jearth.c is a simple client waiting for an user input. Push a key, and the requested command will be transfered to jluna.c, whereas jluna works as server. As soon it recieves a command from jearth, it returns the given command to the client (as kind of feedback) and passes it through jser.c to the serial port. That's it.
The code just works under Linux!!!
How to test
If you want to test the code, and you have Linux installed, it should not be a problem. Copy and paste each file into a file names as the title is (jser.h, jluna.c,...) . Rename the seriall port in jluna.c (Hava a look into /dev) Create a subdirectory called jheader. Put jser.h and jser.c into this directory. Do a
./make
And everything should be compiled. Bridge on your serial RS232 output Pin 2 (RX) with Pin 3 (TX). Start on one console
./jearth
and on another console
./jluna 1234
That's it. Have fun.
jser.h
int writeport(int fd, char *chars); int readport(int fd, char *result); int getbaud(int fd); int convertcmd(char *earthCmd); int datatoport(char *earthCmd);
jearth.c
I've done it very simple - after starting ./jearth you can hit a key (see see switch/case at main) to invoke a command, which will be then send to jluna. Hardcore coding, nothing dynamic, nothing flexible - due to a lack of time! But it should be sufficient for testing.
/*
* jearth.c
* jdrift
*
*
* Created by Tobias Krieger (tobiokanobi) on 05.02.09.
* Thanks to captain (www.captain.at), elphel (www.elphel.com)
* and all others providing usefull code
*
* This is still a very early draft!!!
*
*
**************************************************************************
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h> /* Standard input/output definitions */
#include <sys/socket.h> /* TCP socket definition */
#include <arpa/inet.h> /* Internet defintions */
#include <stdlib.h> /* Standard library */
#include <string.h> /* String function definition */
#include <unistd.h> /* UNIX standard function definitions */
#include <netinet/in.h> /* Network definitions */
#define BUFFSIZE 32
void Die(char *mess) { perror(mess); exit(1); }
int conntoluna(char *jCmd){
int sock;
struct sockaddr_in echoserver;
char buffer[BUFFSIZE];
unsigned int echolen;
int received = 0;
char jIp[]="192.168.1.1";
char jPort[]="1234";
/* Create the TCP socket */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
Die("Failed to create socket");
}
/* Construct the server sockaddr_in structure */
memset(&echoserver, 0, sizeof(echoserver)); /* Clear struct */
echoserver.sin_family = AF_INET; /* Internet/IP */
echoserver.sin_addr.s_addr = inet_addr(jIp); /* IP address */
echoserver.sin_port = htons(atoi(jPort)); /* server port */
/* Establish connection */
if (connect(sock, (struct sockaddr *) &echoserver, sizeof(echoserver)) < 0) {
Die("Failed to connect with server");
}
/* Send the word to the server */
echolen = strlen(jCmd);
if (send(sock, jCmd, echolen, 0) != echolen) {
Die("Mismatch in number of sent bytes");
}
/* Receive the word back from the server */
fprintf(stdout, "Received: ");
while (received < echolen) {
int bytes = 0;
if ((bytes = recv(sock, buffer, BUFFSIZE-1, 0)) < 1) {
Die("Failed to receive bytes from server");
}
received += bytes;
buffer[bytes] = '\0'; /* Assure null terminated string */
fprintf(stdout, buffer);
}
fprintf(stdout, "\n");
close (sock);
return sock;
}
void stopcommand(){
char stopCmd[6];
printf("Stop Motors\n");
stopCmd[0]=0x23; //marks a new command
stopCmd[1]=0x23; //marks a new command
stopCmd[2]=0x03; //number of the following bytes
stopCmd[3]=0x02; //Set new speed */
stopCmd[4]=0x03; // Motor #1 and Motor #2 */
stopCmd[5]=0x00; // Speed = 0 */
conntoluna(stopCmd);
}
void motorcurrent() {
char getcurrentCmd[5];
printf("Get Motor current\n");
getcurrentCmd[0]=0x23;
getcurrentCmd[1]=0x23;
getcurrentCmd[2]=0x03;
getcurrentCmd[3]=0x28; //Motor current*/
getcurrentCmd[4]=0x03; //both motors*/
conntoluna(getcurrentCmd);
}
void dirbothfwd() {
char setfwd[6];
printf("Set direction fwd\n");
setfwd[0]=0x23;
setfwd[1]=0x23;
setfwd[2]=0x03;
setfwd[3]=0x05; //command direction
setfwd[4]=0x03; //both motors
setfwd[5]=0x00; //direction fwd
conntoluna(setfwd);
}
void dirbothrev() {
char setrev[6];
printf("Set direction rev\n");
setrev[0]=0x23;
setrev[1]=0x23;
setrev[2]=0x03;
setrev[3]=0x05; //command direction
setrev[4]=0x03; //both motors
setrev[5]=0x01; //direction rev
conntoluna(setrev);
}
void dirleftfwd() {
char setfwd[6];
printf("Set left wheel direction fwd\n");
setfwd[0]=0x23;
setfwd[1]=0x23;
setfwd[2]=0x03;
setfwd[3]=0x05; //command direction
setfwd[4]=0x01; //left motors
setfwd[5]=0x00; //direction fwd
conntoluna(setfwd);
}
void dirleftrev() {
char setrev[6];
printf("Set left wheel direction rev\n");
setrev[0]=0x23;
setrev[1]=0x23;
setrev[2]=0x03;
setrev[3]=0x05; //command direction
setrev[4]=0x01; //left motors
setrev[5]=0x01; //direction rev
conntoluna(setrev);
}
void dirrightfwd() {
char setfwd[6];
printf("Set right wheel direction fwd\n");
setfwd[0]=0x23;
setfwd[1]=0x23;
setfwd[2]=0x03;
setfwd[3]=0x05; //command direction
setfwd[4]=0x02; //right motors
setfwd[5]=0x00; //direction fwd
conntoluna(setfwd);
}
void dirrightrev() {
char setrev[6];
printf("Set right wheel direction rev\n");
setrev[0]=0x23;
setrev[1]=0x23;
setrev[2]=0x03;
setrev[3]=0x05; //command direction
setrev[4]=0x02; //right motors
setrev[5]=0x01; //direction rev
conntoluna(setrev);
}
void drivebothslowp() {
char driveslow[6];
printf("Set speed slow\n");
driveslow[0]=0x23;
driveslow[1]=0x23;
driveslow[2]=0x03;
driveslow[3]=0x02; // motorstart
driveslow[4]=0x03; // both motors
driveslow[5]=0x84; //pulse 130
conntoluna(driveslow);
}
void drivebothmediump() {
char drivemedium[6];
printf("Set speed medium\n");
drivemedium[0]=0x23;
drivemedium[1]=0x23;
drivemedium[2]=0x03;
drivemedium[3]=0x02; // motorstart
drivemedium[4]=0x03; // both motors
drivemedium[5]=0xAA; //pulse 170
conntoluna(drivemedium);
}
void drivebothfastp() {
char drivefast[6];
printf("Set speed fast\n");
drivefast[0]=0x23;
drivefast[1]=0x23;
drivefast[2]=0x03;
drivefast[3]=0x02; // motorstart
drivefast[4]=0x03; // both motors
drivefast[5]=0xE6; //pulse 230
conntoluna(drivefast);
}
void drivebothmaxp() {
char drivefast[6];
printf("Set speed max\n");
drivefast[0]=0x23;
drivefast[1]=0x23;
drivefast[2]=0x03;
drivefast[3]=0x02; // motorstart
drivefast[4]=0x03; // both motors
drivefast[5]=0xFF; //pulse 230
conntoluna(drivefast);
}
void motorleftmedium(){
char leftmed[6];
printf("Set left wheel speed medium\n");
leftmed[0]=0x23;
leftmed[1]=0x23;
leftmed[2]=0x03;
leftmed[3]=0x02; // motorstart
leftmed[4]=0x01; // left motor
leftmed[5]=0xAA; //pulse 170
conntoluna(leftmed);
}
void motorrightmedium(){
char rightmed[6];
printf("Set right wheel speed medium\n");
rightmed[0]=0x23;
rightmed[1]=0x23;
rightmed[2]=0x03;
rightmed[3]=0x02; // motorstart
rightmed[4]=0x02; // right motors
rightmed[5]=0xAA; //pulse 170
conntoluna(rightmed);
}
void motorleftfast(){
char leftfast[6];
printf("Set left wheel speed fast\n");
leftfast[0]=0x23;
leftfast[1]=0x23;
leftfast[2]=0x03;
leftfast[3]=0x02; // motorstart
leftfast[4]=0x01; // left motor
leftfast[5]=0xD8; //pulse 200
conntoluna(leftfast);
}
void motorrightfast(){
char rightfast [6];
printf("Set right wheel speed fast\n");
rightfast[0]=0x23;
rightfast[1]=0x23;
rightfast[2]=0x03;
rightfast[3]=0x02; // motorstart
rightfast[4]=0x02; // right motors
rightfast[5]=0xD8; //pulse 200
conntoluna(rightfast);
}
void spintest1() {
printf("***SPINTEST 1 \n");
dirleftfwd();
dirrightrev();
motorleftmedium();
motorrightmedium();
}
void spintest2() {
printf("***SPINTEST 2 \n");
dirleftrev();
dirrightfwd();
motorleftmedium();
motorrightmedium();
}
void turnleftfwd (){
printf("***Turn left forward \n");
dirbothfwd();
motorleftmedium();
motorrightfast();
}
void turnrightfwd (){
printf("***Turn right forward \n");
dirbothfwd();
motorrightmedium();
motorleftfast();
}
void turnleftrev (){
printf("***Turn left reverse \n");
dirbothrev();
motorleftmedium();
motorrightfast();
}
void turnrightrev (){
printf("***Turn right reverse \n");
dirbothrev();
motorrightmedium();
motorleftfast();
}
int main(int argc, char *argv[]) {
char command;
int running = 0;
printf("Welcome to Jaluro Driving Control\n");
printf("Enter 'h' for command list\n");
printf("Enter 'e' to leave\n");
while (running == 0) {
printf("Command: ");
scanf(" %c",&command);
switch (command) {
// Left Hand
case 'q': drivebothslowp(); break;
case 'w': drivebothmediump(); break;
case 'r': drivebothfastp(); break;
case 't': drivebothmaxp(); break;
case 's': motorleftmedium(); break;
case 'd': motorrightmedium(); break;
case 'a': motorleftfast(); break;
case 'f': motorrightfast(); break;
case 'e': dirbothfwd(); break;
case 'x': dirbothrev(); break;
//Right Hand
case 'u': stopcommand(); break;
case 'p': motorcurrent(); break;
case 'i': turnleftfwd(); break;
case 'o': turnrightfwd(); break;
case 'k': turnleftrev(); break;
case 'l': turnrightrev(); break;
case 'b': spintest1(); break;
case 'n': spintest2(); break;
case 'v': printf("\n Bye Bye\n"); running= 1; break;
default: printf("Try Again \n");break;
}
}
exit(0);
}
jluna.c
My first attemped was to send the "command line" input to the server and to analyse it there, but I figured out that it makes much more sense to implement the command "translation" into jearth. I left most pieces of code anyway there, maybe I need it for something else :-) .
/*
* jluna.c
* jdrift
*
* Created by Tobias Krieger (tobiokanobi) on 23.01.09.
* Thanks to captain (www.captain.at), elphel (www.elphel.com)
* and all others providing usefull code
*
* This is still a very early draft!!!
*
*
**************************************************************************
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <ctype.h>
#include "jheader/jser.h"
#define MAXPENDING 5 /* Max connection requests */
#define BUFFSIZE 32
int fd;
void Die(char *mess) { perror(mess); exit(1); }
void HandleClient(int sock) {
char buffer[BUFFSIZE];
char earthCmd[254]="0";
int received = -1;
int rb = 0;
/* Receive message */
if ((received = recv(sock, buffer, BUFFSIZE, 0)) < 0) {
Die("Failed to receive initial bytes from client");
}
/* Send bytes and check for more incoming data in loop */
while (received > 0) {
for (rb=0; rb<(received); rb++){
earthCmd[rb]=buffer[rb];
}
datatoport(earthCmd);
/* Send back received data */
if (send(sock, buffer, received, 0) != received) {
Die("Failed to send bytes to client");
}
/* Check for more data */
if ((received = recv(sock, buffer, BUFFSIZE, 0)) < 0) {
Die("Failed to receive additional bytes from client");
}
}
close(sock);
}
/ *Serial Port */
int initport(int fd) {
struct termios options;
// Get the current options for the port...
tcgetattr(fd, &options);
// Set the baud rates to 19200...
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
// Enable the receiver and set local mode...
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// Set the new options for the port...
tcsetattr(fd, TCSANOW, &options);
return 1;
}
int datatoport(char* sCmd){
fd = open("/dev/tty.PL2303-00002006", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyS0 - ");
return 1;
} else {
fcntl(fd, F_SETFL, 0);
}
printf("baud=%d\n", getbaud(fd));
initport(fd);
printf("baud=%d\n", getbaud(fd));
if (!writeport(fd, sCmd)) {
printf("write failed\n");
close(fd);
return 1;
}
printf("written:%s\n", sCmd);
usleep(500000);
char sResult[254];
fcntl(fd, F_SETFL, FNDELAY); // don't block serial read
if (!readport(fd,sResult)) {
printf("read failed\n");
close(fd);
return 1;
}
printf("readport=%s\n", sResult);
close(fd);
return 0;
}
/*
int motorcurrent() {
char m12_pwr[5];
printf("\nMotorcurrent\n");
m12_pwr[0]=0x23;
m12_pwr[1]=0x23;
m12_pwr[2]=0x03;
m12_pwr[3]=0x28; //Motor current
m12_pwr[4]=0x03; //both motors
datatoport(m12_pwr);
return 0;
}
int convertcmd(char *earthCmd){
int cmdlength=0;
int cmdcounter=0;
int cmdcounter2=0;
int cmdsplit=0;
char separator1[]="-";
char separator2[]=" ";
char *token;
char listofCmd[10][10];
char listPara[10][10];
printf("%s\n\nToken:\n",earthCmd);
token=strtok(earthCmd, separator1);
while ( token != NULL ) {
// printf("%s\n", token);
for (cmdlength=0; cmdlength<=(strlen(token)); cmdlength++) {
listofCmd[cmdcounter][cmdlength]=token[cmdlength];
}
token = strtok(NULL,separator1);
cmdcounter++;
}
cmdlength = 0;
for (cmdsplit=0; cmdsplit<cmdcounter; cmdsplit++){
token=strtok(&listofCmd[cmdsplit][0], separator2);
while ( token != NULL ) {
for (cmdlength=0; cmdlength<=(strlen(token)); cmdlength++) {
listPara[cmdcounter2][cmdlength]=token[cmdlength];
}
token = strtok(NULL,separator2);
}
cmdcounter2++;
}
for (cmdlength=0; cmdlength<cmdcounter2;cmdlength++){
switch (listofCmd[cmdlength][0]) {
case 'a': printf("Set Acceleration: %s\n", &listPara[cmdlength][0]); break;
case 'b': printf("Get rpm \n"); break;
case 'c': printf("Get Current\n"); break;
case 'd': printf("Set Direction: %s\n", &listPara[cmdlength][0]); break;
case 'e': printf("Set Encoder: %s\n", &listPara[cmdlength][0]); break;
case 'f': printf("Get Driven Way\n"); break;
case 'g': printf("Set Gear: %s", &listPara[cmdlength][0]);break;
case 'h': printf("Set distance per turn: %s\n", &listPara[cmdlength][0]);break;
case 'i': printf("Set Motorcurrent metering: %s\n", &listPara[cmdlength][0]);break;
case 'j': printf("Set max I watchdog: %s\n",&listPara[cmdlength][0]);break;
case 'k': printf("Set max Temp: %s\n", &listPara[cmdlength][0]);break;
case 'l': printf("Set time max I: %s\n", &listPara[cmdlength][0]);break;
case 'm': printf("Set Motor: %s\n", &listPara[cmdlength][0]); break;
case 'p': printf("Set Pulses: %s\n", &listPara[cmdlength][0]); break;
case 'r': printf("Roll!\n"); break;
case 's': printf("Set Speed rpm: %s\n", &listPara[cmdlength][0]); break;
case 't': printf("Get Temperature \n"); break;
case 'u': printf("Reset Way \n"); break;
case 'w': printf("Get Way: %s\n", &listPara[cmdlength][0]); break;
case 'x': printf("Set max rpm: %s", &listPara[cmdlength][0]);break;
case 'y': printf("Test parameter: %s", &listPara[cmdlength][0]);break;
case '?': printf("Reason Motorstop");
default: printf("Nothing \n");
}
}
return 1;
} */
int main(int argc, char *argv[]) {
int serversock, clientsock;
struct sockaddr_in echoserver, echoclient;
if (argc != 2) {
fprintf(stderr, "USAGE: echoserver <port>\n");
exit(1);
}
/* Create the TCP socket */
if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
Die("Failed to create socket");
}
/* Construct the server sockaddr_in structure */
memset(&echoserver, 0, sizeof(echoserver)); /* Clear struct */
echoserver.sin_family = AF_INET; /* Internet/IP */
echoserver.sin_addr.s_addr = htonl(INADDR_ANY); /* Incoming addr */
echoserver.sin_port = htons(atoi(argv[1])); /* server port */
/* Bind the server socket */
if (bind(serversock, (struct sockaddr *) &echoserver, sizeof(echoserver)) < 0) {
Die("Failed to bind the server socket");
}
/* Listen on the server socket */
if (listen(serversock, MAXPENDING) < 0) {
Die("Failed to listen on server socket");
}
/* Run until cancelled */
while (1) {
unsigned int clientlen = sizeof(echoclient);
/* Wait for client connection */
if ((clientsock = accept(serversock, (struct sockaddr *) &echoclient, &clientlen)) < 0)
{
Die("Failed to accept client connection");
}
fprintf(stdout, "\nClient connected: %s\n", inet_ntoa(echoclient.sin_addr));
HandleClient(clientsock);
}
}
jser.c
/* jser.c
* adpated 23.01.2009 by Tobias Krieger (tobiokanobi) for use on Jaluro / TeamFrednet.
*
* jser.c provides functions to read,write and to check the baudrate of the serial port (RS232);
*
*
* Thanks to captain (www.captain.at), elphel (www.elphel.com)
* and all others providing usefull code
*
* This is still a very early draft!!!
*
*
**************************************************************************
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
int writeport(int fd, char *chars) {
int len = strlen(chars);
chars[len] = 0x0d; // stick a <CR> after the command
chars[len+1] = 0x00; // terminate the string properly
int n = write(fd, chars, strlen(chars));
if (n < 0) {
fputs("write failed!\n", stderr);
return 0;
}
return 1;
}
int readport(int fd, char *result) {
int iIn = read(fd, result, 254);
result[iIn-1] = 0x00;
if (iIn < 0) {
if (errno == EAGAIN) {
printf("SERIAL EAGAIN ERROR\n");
return 0;
} else {
printf("SERIAL read error %d %s\n", errno, strerror(errno));
return 0;
}
}
return 1;
}
int getbaud(int fd) {
struct termios termAttr;
int inputSpeed = -1;
speed_t baudRate;
tcgetattr(fd, &termAttr);
/* Get the input speed. */
baudRate = cfgetispeed(&termAttr);
switch (baudRate) {
case B0: inputSpeed = 0; break;
case B50: inputSpeed = 50; break;
case B110: inputSpeed = 110; break;
case B134: inputSpeed = 134; break;
case B150: inputSpeed = 150; break;
case B200: inputSpeed = 200; break;
case B300: inputSpeed = 300; break;
case B600: inputSpeed = 600; break;
case B1200: inputSpeed = 1200; break;
case B1800: inputSpeed = 1800; break;
case B2400: inputSpeed = 2400; break;
case B4800: inputSpeed = 4800; break;
case B9600: inputSpeed = 9600; break;
case B19200: inputSpeed = 19200; break;
case B38400: inputSpeed = 38400; break;
}
return inputSpeed;
}
Makefile
CFLAGS=-g -Wall ser: jheader/jser.c jluna.c gcc -g -c -Wall jheader/jser.c -o jser.o gcc -g -c -Wall jluna.c -o jluna.o gcc -g -c -Wall jearth.c -o jearth.o gcc jluna.o jser.o -o jluna gcc jearth.o -o jearth
