1. Do not share user accounts! Any account that is shared by another person will be blocked and closed. This means: we will close not only the account that is shared, but also the main account of the user who uses another person's account. We have the ability to detect account sharing, so please do not try to cheat the system. This action will take place on 04/18/2023. Read all forum rules.
    Dismiss Notice
  2. For downloading SimTools plugins you need a Download Package. Get it with virtual coins that you receive for forum activity or Buy Download Package - We have a zero Spam tolerance so read our forum rules first.

    Buy Now a Download Plan!
  3. Do not try to cheat our system and do not post an unnecessary amount of useless posts only to earn credits here. We have a zero spam tolerance policy and this will cause a ban of your user account. Otherwise we wish you a pleasant stay here! Read the forum rules
  4. We have a few rules which you need to read and accept before posting anything here! Following these rules will keep the forum clean and your stay pleasant. Do not follow these rules can lead to permanent exclusion from this website: Read the forum rules.
    Are you a company? Read our company rules

Dan's 3dofDuino Ver. 0.02 - Arduino interface for X-Sim2

Discussion in 'SimTools compatible interfaces' started by DanielDk, Feb 27, 2012.

  1. DanielDk

    DanielDk Member

    Joined:
    Feb 27, 2012
    Messages:
    38
    Balance:
    386Coins
    Ratings:
    +12 / 1 / -0
    Hi Guys,

    13-03-2012 - Ver. 0.02 is done.
    Lots of new stuff, PWM, PID, HEX - check it out :)


    Feature Log:
    Code:
    
    //-----3dofDuino - 0.02 -  13-03-2012----------
    -   up to 12x servos and 9 pwms simultaneously  
    -   Output with a frequency range of 100hz to 31KHZ
         user adjustable in 2hz increments. (tested @ 20khz)
         with a resolution from 255 steps to 65535 steps 
         (changes automagically with frequency)
     - Pid control with adjustable P-I-D parameters for each pwm output.
     - Simple to configure - dynamically configures outputs. 
     - Hex input
     - 115200 baud communication with x-sim2
     - up to 21 axis
     - 16bit input accuracy (0-65535)
     - No error checking for now
     - around 200 pk/s@115200baud,  3 axis
     - based on arduino IDE so beginners can easily modify the code. (including me :)
     - tested on Ardunio mega 2560 r3  - 
         others may still work allthough less timers = less pwm outputs
    
    //-----3dofDuino - 0.02 -  13-03-2012----------
    
    
    
    
    //-----3dofDuino - 0.01 -  26-02-2012----------
     - 115200 baud communication with x-sim2
     - 3 axis
     - 16bit input accuracy (0-65535)
     - error checking of each value of each  multi-axis-package recieved.
     - around 400 pk/s@115200baud,  3 axis, with  full package verification
     - indicator leds for sucessfull recieve/package  and failed package check.
     - servo output
     - based on arduino IDE so beginners can easily modify the code. (including me :)
     -  tested on Ardunio mega 2560 r3  - but change the output pins and se no reason i shouldn't work on uno, due etc tec.
    //-----3dofDuino - 0.01 -  26-02-2012----------
    


    I will keep updating this post as the work progresses.

    Stuff to come:

    - XOR based error checking instead of sending every value twice. ( propably need help on this one)
    - act on limit switches
    - auto calibrate using encoder/limitswitches
    - use fastwrite insted of digitalwrite - should result in a 50x increase of performance
    - as5040 magnetic 1024 PPR resolution encoder support



    Best Regards
    Daniel

    Attached Files:

  2. eaorobbie

    eaorobbie Well-Known Member SimTools Developer Gold Contributor

    Joined:
    May 26, 2009
    Messages:
    2,574
    Occupation:
    CAD Detailer
    Location:
    Ellenbrook, Western Australia
    Balance:
    20,452Coins
    Ratings:
    +1,686 / 23 / -2
    My Motion Simulator:
    2DOF, DC motor, JRK, SimforceGT, 6DOF
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    yes this looks like it will work with servos but not a h bridge gets alot more complicated with pid
    But gunna keeps tabs on this.
  3. DanielDk

    DanielDk Member

    Joined:
    Feb 27, 2012
    Messages:
    38
    Balance:
    386Coins
    Ratings:
    +12 / 1 / -0
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Hi Earobbie,

    Yeah i know i'm in a world of hurt on that one :)

    i
  4. eaorobbie

    eaorobbie Well-Known Member SimTools Developer Gold Contributor

    Joined:
    May 26, 2009
    Messages:
    2,574
    Occupation:
    CAD Detailer
    Location:
    Ellenbrook, Western Australia
    Balance:
    20,452Coins
    Ratings:
    +1,686 / 23 / -2
    My Motion Simulator:
    2DOF, DC motor, JRK, SimforceGT, 6DOF
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    there is a few ard guys here they just dont say much. Normally just pick others programs.
    Keep the effort up. I have a simple servo program that works through xsim, for 2dof but utilizes only 8 bit due to a servo only works between 0-255 anyway not point in taking it further unless ya want to use h bridges and pid control.
    If i can find it on my old drive i will post it for ya to see.
    I use a pololu servo controller to run my test model but ventured onto changing it to a ard for a local ard hobbist so he could have a desktop model move while he played the game, doesnt want a motion chair, just a toy.
    But looks like ya have a better grip on the ard than i so if i can help i will.
  5. stowaway

    stowaway New Member

    Joined:
    Mar 16, 2009
    Messages:
    213
    Location:
    Gold Coast - Australia
    Balance:
    1Coins
    Ratings:
    +0 / 0 / -0
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Have you considered ditching the Arudino libraries completely and coding directly to the chip?

    Thats what Im doing, I'll happily share my code if you want. (im a n00b too, so my code may be tremendously inefficent)

    I communicate with the USO directly in binary so there is no conversation at all.
    I dont error check, besides to make sure that I have received the correct amount of values *might need to fix this in the future?
    I have already created some functions that turn on and use PWM. *its pretty easy to do, i tested with a H-Bridge, not sure why you need a ocilloscope.
    Atmel have their own PID.C file so thats what I use. I'm assuming it should be pretty efficient seeing it is made by Atmel.

    Right now im really just waiting for all my parts to come from china and my workshop to finish them off before I can start testing everything in real world situation.

    But it was suggested to me by other members here that its more efficient to not use the arduino librarys... perhapes worth looking at?

    Anyway let me know if you want it, I can post my code. It is all designed for a ATMEGA328P.
  6. DanielDk

    DanielDk Member

    Joined:
    Feb 27, 2012
    Messages:
    38
    Balance:
    386Coins
    Ratings:
    +12 / 1 / -0
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Yeah - i thought about it - but given my limited exposure to C i thought it best to stay with the arduino libs so i would be able to blatantly steal code from other arduino projects out there. :)
    How ever, i have no doubt in my mind that coding directly to the chip is far more efficient - (Just took a peak at your code - looks impressive - and abit over my head ! )
    The error checking feature came about because of an error on my part (ran different serial baud rates) since i corrected that the error led seldomly lights up. So i'm not shure if it is even required anymore...

    I would very much like to pick your brain regarding pwm,registers,prescalers and theory when the time comes cause' programming to hardware is a first for me. :)

    Btw. thanks - i'm looking forward to seeing your setup!

    Daniel
  7. stowaway

    stowaway New Member

    Joined:
    Mar 16, 2009
    Messages:
    213
    Location:
    Gold Coast - Australia
    Balance:
    1Coins
    Ratings:
    +0 / 0 / -0
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Well first of all, I have pretty much jsut got all my code from tutorials and such, so i am a complete n00b also.. but here goes what I have. I beleive it may help as some of the functions are pretty simply (ie setup PWM, use PID ect)

    Its still very much in testing so there is alot of commented out code and alot of code only in there for debugging and seeing what it does..

    here is description of the PID library i use :

    http://www.atmel.com/Images/doc2558.pdf

    I also use a standard LCD library.

    to control motors just change OCR2B, OCR0B, OCR0A. They can only be between 0-255.. But there will also be other pins that control the direction.
    So Ill need to create some conversations here which isnt done yet..

    here goes:

    atmega328_tip.c // I am hopefully desiging the function in this file so i can easily upgrade the chip, and i just have the change the methods to suit the chip and not the main.c file. (as initalising pwm, adc, serial may require different bytes with different chips)
    Code:
    #include atmega328_tip.h
    
    /* SETUP UART */
    void USART_Init( unsigned int ubrr)
    {
       /*Set baud rate */
       UBRR0H = (unsigned char)(ubrr>>8);
       UBRR0L = (unsigned char)ubrr;
       
      /*Enable receiver and transmitter */
       UCSR0B = (1<<RXEN0)|(1<<TXEN0);
       
       /* Set frame format: 8data, 1stop bit */
       UCSR0C = (3<<UCSZ00);
       
          /*Turn on Receive Complete Interrupt*/
       UCSR0B |= (1 << RXCIE0);
       
    }
    
    
    void USART_Interrupt_On()
    {
       /*Turn on Receive Complete Interrupt*/
       UCSR0B |= (1 << RXCIE0);
    }
    
    /* Simple methods to make UART read and transmit more readble - Extremely unnecessary*/
    void USART_Transmit( unsigned char data )
    {
    	while(!(UCSR0A & (1<<UDRE0)));
    	UDR0 = data;
    }
    
    
    unsigned char USART_Receive( void )
    {
       return UDR0;
    }
    
    
    /* ADC METHODS */
    
    // Initate ADC. 
    // Input prescaler amount, and 10bit or 8bit results
    void ADC_Init(int preScaler, int tenBit)
    {
    	ADCSRA |= (1 << ADEN);  //Enable ADC
    	
    	//To Do. Set Different prescalers.
    	if (preScaler == 128)
    		ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);  //set prescaler to 128
    		
    		
    	if (!tenBit)
    		ADMUX |= (1 << ADLAR);  //Left adjust ADC result to allow easy 8 bit reading	
    		
    	ADMUX |= (1 << REFS0);  //USE AVCC as refernece;
    	ADCSRA |= (1 << ADSC);  //start first conversion
    }
    
    
    /* PWM Methods */
    
    void PWM_init(void)
    {
    
    	/* Init Timer 0A PORT D6 or PORT 6 on Arduino */
        DDRD |= (1 << DDD6);
        // PD6 is now an output
    
        OCR0A = 100;
        // set PWM for 50% duty cycle
    
    
        TCCR0A |= (1 << COM0A1);	
        // set none-inverting mode
    
        TCCR0A |= (1 << WGM00);  //PWM Phase Corrected 
    
        TCCR0B |= (1 << CS00);
        // set prescaler to 8 and starts PWM
    	
    	
    		
    	/* Init Timer 0B PORT D5 or PORT 5 on Arduino */
    	DDRD |= (1 << DDD5);
    	OCR0B = 128; // set PWM for 50% duty cycle
    
    	TCCR0A |= (1 << COM0B1) | (1 << COM2A1);;
        // set none-inverting mode
    
    	OCR0B = 128;
    	
    
    	/* INIT Timer 2B Port D3 or 3 oon Arduino*/	
    	DDRD |= (1 << DDD3);
    	
    	DDRB |= (1 << DDB3);
        // PD6 is now an output
    	
        OCR2B = 250;
        // set PWM for 50% duty cycle
    	OCR2A = 250;
    	
    
        TCCR2A |= (1 << COM2B1) | (1 << WGM20);
        // set none-inverting mode & set PWM Phase correct Mode
    	        
        	
    	
        TCCR2B |= (1 << CS20);
        // set prescaler to 8 and starts PWM
    
    
    	//Set Directoinal Pins
    	DDRB |= (1 << DDB4);
    	PORTB &= ~(1 << PINB4);
    } 
    
    
    //Send String To Serial
    void SendString(char *StringPtr)
    {
    	
    	while(*StringPtr != 0x00)
    	{  
    	USART_Transmit(*StringPtr);    
    	StringPtr++;
    	}        
    
    }
    main.c //thee is alot of stuff in here that is useless or testing purposes. thigns that might be handy are how i setup PID. how im using interrupts etc.. but please remember this is a LONG way from finished and alot of code is commented out.

    Code:
    /*** TMC - Tippett Motion Control
    **** Timer 0B - PMW Motor 1
    **** Timer 1 - PID Timer Run PID Calculations every PIDDELAY (Currently 2500 for every 10ms)
    **** 
    ****
    **** TO control Motors change OCR2B, OCR0B, OCR0A
    ****
    ****/
    
    #include <avr/io.h> 
    #include <stdio.h>
    #include <stdlib.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include pid.h
    #include lcd.h
    #include <string.h>
    #include atmega328_tip.h
    #include SetupMode.h
    
    #define NO_OF_POTS 3
    #define NO_OF_AXIS 3
    #define NO_OF_INPUTS (NO_OF_AXIS * 2)
    #define potSensitivity 10
    
    /* UART SERIAL DEFINES */
    #define F_CPU 16000000UL
    #define BAUD 9600
    #define MYUBRR F_CPU/16/BAUD-1
    #define PIDDELAY 2500
    
    
    
    /* Setup Mode Variables */
    uint8_t SetupMode;
    char input[20];
    uint8_t menuNumber;
    int counter;
    
    //To Do. make these values editable via lcd and buttons
    
    double K_P = 3;
    double K_I = 35;
    double K_D = 10;
    
    
    /* PUT IN HEADER */
    void InitPIDTimer(void);
    
    
    volatile int pot1;
    volatile int pot2;
    volatile int pot3;
    
    //TO DO. DELETE THESE VARIABLES
    volatile int desiredPosition;
    volatile int actualPosition;
    volatile uint8_t inputBuffer[NO_OF_INPUTS];
    volatile int change;
    
    volatile uint8_t position;
    
    
    struct Motors
    {
    	uint16_t CurrentPosition;
    	uint16_t DesiredPosition;
    	struct PID_DATA PidData;
    	uint16_t PWMspeed;
    	
    } Motor1, Motor2, Motor3;
    
    
    /******************/
    
    void InitPIDTimer()
    {
    	TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode 
    	TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt 
    	TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64
    	OCR1A   = PIDDELAY;
    
    }
    
    
    //Common Setup Routines
    void standardSetup(void)
    {
    	//Setup Serial
    	USART_Init(MYUBRR);
    	USART_Interrupt_On();
    	sei();
    	
    	/* Init LCD */
    	lcd_init(LCD_DISP_ON);
    	
    		//Setup input direction to PINC4
    	DDRC &= ~(1 << PINC4); 
    	PORTC |= 1 << PINC4; 
    	_delay_ms(1000);
    
    }
    
    void setupInit(void)
    {
    	menuNumber = 0;
    	
    	lcd_clrscr();
    	lcd_puts(Setup Mode);	
    	SetupMode = 1;
    }
    
    
    void Init(void)
    {
    	//Setup PID structs
    	pid_Init(K_P, K_I, K_D, &Motor1.PidData);
    	pid_Init(K_P, K_I, K_D, &Motor2.PidData);
    	pid_Init(K_P, K_I, K_D, &Motor3.PidData);
    	PWM_init();
      	
    	/* Setup  ADC */
    	//ADC_Init(128, 1);
    	
         /*Turn on Receive Complete Interrupt*/
    	UCSR0B |= (1 << RXCIE0);
    
    	/*Turn on ADC Interrupt */
    	ADCSRA |= (1 << ADIE); 
       
       
    	//Turn on PORTB 12 to input
    	DDRB &= ~(1 << PINB4);   //set input direction
    	
    	/* Setup Pot Values */
    	pot1 = 0;
    	
    	pot2 = 0;
    	
    	pot3 = 0;	
    	
    	change = 0;
    	
    	
    	lcd_clrscr();
    	lcd_puts(Init Okay);
    	
    	position = -1;
    	
    	
       
    }
    
    int main(void)
    {
    	standardSetup();
    
    	if (bit_is_clear(PINC, 4)) 
    	{
    		setupInit();
    	}
    	else
    	{
    		Init();		
    		
    	}
    
    	
    	//Init();
    	//desiredPosition = 500;
    	//actualPosition = 200;
    	//InitPIDTimer();
    	//turn on interrupts	
    		/* INITALISE SERIAL */
    	//USART_Init(MYUBRR);
    	
    	//sei();
    	
    	//int LCDCount =0;
    	//lcd_clrscr();
    	//lcd_puts(Init Okay);
    	
    	int testcount = 0;
    	int prescaler = 0;
    	
    	while (1)
    	{
    		
    		if (testcount < 5000)
    		{
    			PORTB &= ~(1 << PINB4);
    		}
    		else if (testcount < 10000)
    		{
    			PORTB |= (1 << PINB4);
    		}
    		else 
    		{
    			testcount=0;
    		}
    		
    		prescaler++;
    		
    		if (prescaler > 1000)
    		{
    			testcount++;
    			prescaler = 0;
    		}
    	}
       /*
    	while (1)
    	{
    		if (LCDCount > 10000)
    		{
    		
    			
    			LCDCount = 0;	
    			
    			char Motor1String[7];
    			char Motor2String[7];
    			char Motor3String[7];
    			char pid3String[7];
    			
    			sprintf(Motor1String,%u , Motor1.DesiredPosition);			
    			sprintf(Motor3String,%u , Motor3.DesiredPosition);			
    			itoa(Motor1.PWMspeed, Motor2String, 10);
    			itoa(Motor3.PWMspeed, pid3String, 10);
    			
    			
    			lcd_clrscr();     /* clear the screen*/  /*
    			lcd_puts(1:);
    			lcd_puts(Motor1String); 
    			lcd_puts( P:);
    			lcd_puts(Motor2String);					
    			lcd_gotoxy(0,1);
    			lcd_puts(3:);
    			lcd_puts(Motor3String);
    			lcd_puts(P:);
    			lcd_puts(pid3String);
    			
    			Motor1.CurrentPosition += Motor1.PWMspeed;
    			Motor3.CurrentPosition += Motor3.PWMspeed;
    			
    		}
    		
    		LCDCount++;
    		
    	}
    	*/
    	
    	
    }
    
    
    
    /* INTERRUPTS */
    
    //Timer 1A Interrupt
    
    /*Every 10ms Calcualte the PWM value via DoPid - unsure if this is the best way to do it?*/
    ISR(TIMER1_COMPA_vect)
    {			   		
    			Motor1.PWMspeed = pid_Controller(Motor1.DesiredPosition, Motor1.CurrentPosition, &Motor1.PidData);										
    			Motor2.PWMspeed = pid_Controller(Motor2.DesiredPosition, Motor2.CurrentPosition, &Motor2.PidData);										
    			Motor3.PWMspeed = pid_Controller(Motor3.DesiredPosition, Motor3.CurrentPosition, &Motor3.PidData);						
    } 
    
    
    
    
    //SERIAL INTERRUPT -- If not in setup mode then read binary serial.. currently only reading buadrate of 9600.. but i could speed this up??
    ISR (USART_RX_vect)
    {	
    	
    	if (!SetupMode)
    	{
    		int input = UDR0;
    	
    		if (input == 'R')
    		{	
    			position = 0;				
    		}
    		else if ((input != 'E') && (position > -1))
    		{
    	
    			if (position < NO_OF_INPUTS)
    			{
    				inputBuffer[position] = input;
    				position++;
    			}
    			else
    			{
    				//error; ignore and restart
    				position = -1;
    			}
    		
    		}
    		else if (input == 'E')
    		{		
    		
    			/* Packet Recevied. Commit Values */
    			Motor1.DesiredPosition = (inputBuffer[0] << 8) | inputBuffer[1];
    			Motor2.DesiredPosition = (inputBuffer[2] << 8) | inputBuffer[3];
    			Motor3.DesiredPosition = (inputBuffer[4] << 8) | inputBuffer[5];	
    		
    			position = -1;
    		}
    	}
    	else
    	{
    		char ReceivedByte; 
    
    		ReceivedByte = UDR0; // Fetch the received byte value into the variable ByteReceived	
    	
    		if ((int)ReceivedByte == 13)
    		{
    		
    			if (menuNumber == 0)
    			{
    				if (strcmp(input, go) == 0)
    				{
    					start_Setup(&menuNumber);
    				}
    				else
    				{				
    					SendString(To Start Setup Write \go\ \r\n);		
    				}
    			}
    			else if (menuNumber == 1)
    			{
    				int menu_choice;
    				menu_choice = input[0] - '0';
    			
    				switch (menu_choice)
    				{
    					case 1: 
    						setup_pid(&menuNumber);
    						break;
    					case 2:
    						SendString(You Chose 2\r\n);					
    						break;
    					default:
    						SendString(Invalid Choice, Try again\r\n);					
    						break;
    				}						
    		}
    		else if (menuNumber == 2)		
    		{
    		
    			if (saveAnswer(0, input))
    			{
    				setup_Ki(&menuNumber);
    			}		
    		}
    		else if (menuNumber == 3)
    		{
    			if (saveAnswer(1, input))
    			{
    				setup_Kd(&menuNumber);
    			}
    		}
    		else if (menuNumber == 4)
    		{
    			if (saveAnswer(2, input))
    			{
    				menuNumber=1;
    				start_Setup(&menuNumber);
    			}
    		}
    		
    		
    		//Clear Input Character
    		memset(&input[0], 0, sizeof(input)); 
    		counter=0;
    
    	}
    	else
    	{
    		input[counter] = ReceivedByte;
    		
    		if (counter < 20)
    			counter++;
    		else 
    			counter = 0;
    	}
    	}
    	
    }
    
    
    
    //ADC INTERRUPT -- Read 3 differnt Pots
    ISR(ADC_vect) 
    { 
    	
    
    	switch (ADMUX)
    	{
    		case 0x40:		
    		
    		if ((pot1 > ADC + potSensitivity) || (pot1 < ADC - potSensitivity))
    		{
    			change = 1;
    			pot1 = ADC;
    		}		
    			
    		if (NO_OF_POTS > 1)
    			ADMUX = 0x41;
    		break;
    		
    		case 0x41:
    		if ((pot2 > ADC + potSensitivity) || (pot2 < ADC - potSensitivity))
    		{
    			change = 1;
    			pot2 = ADC;
    		}
    		
    		
    		if (NO_OF_POTS > 2)
    			ADMUX = 0x42;
    		else
    			ADMUX = 0x40;
    		break;
    		
    		
    		case 0x42:
    		if ((pot3 > ADC + potSensitivity) || (pot3 < ADC - potSensitivity))
    		{
    			change = 1;
    			pot3 = ADC;
    		}
    		
    		
    		if (NO_OF_POTS > 3)
    			ADMUX = 0x43;
    		else
    			ADMUX = 0x40;
    		break;		
    	
    	}
    	
    	ADCSRA |= (1 << ADSC);  //next conversion
    	
    } 
    
    
    
    
  8. DanielDk

    DanielDk Member

    Joined:
    Feb 27, 2012
    Messages:
    38
    Balance:
    386Coins
    Ratings:
    +12 / 1 / -0
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Cool! - i can use your work on setting up the prescalers pretty much as is - nice.
    i've been looking around the net a bit and luckily for me there are allready high performance quad encoder libraries made in assembler for the arduino. and a PID library. i'll probably be looking heavily into your code on how to implemet the pid controller part though :)
  9. gazz

    gazz Member

    Joined:
    Feb 16, 2012
    Messages:
    35
    Location:
    Scarborough
    Balance:
    105Coins
    Ratings:
    +3 / 0 / -0
    My Motion Simulator:
    Arduino
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    thankyou for pointing me to your post Dan, i'm running your code on my arduino right now, and have X-sim controlling the one servo i have,

    i wonder how hard it would be to alter the arduino code to output a varying frequency, as i would like to drive a few air-core gauges as well, the one i have is a rev counter, and wants a 0 to 433Hz signal at 50% duty cycle,
    i tested it with the arduino's tone follower sketch, replacing the light resistor with a pot, and she works, so i guess i just need to change the sketch to put say the Y axis to use the frequency library, or is it not as simple as that.
  10. DanielDk

    DanielDk Member

    Joined:
    Feb 27, 2012
    Messages:
    38
    Balance:
    386Coins
    Ratings:
    +12 / 1 / -0
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Your welcome - thanks for testing :)

    i would think it would be as simple as:

    the z-axis ~a03~ is your tonegenerator (currently pin 9)

    Code:
    //-----------------------------------------3DofDuino 0.01 - tonehack for gazz---------------------------------------
    //-------------------------------Daniel Christiansen - X-Sim->Arduino mega Interface -------------------------------
    //--------------------------------------daniel.christiansen+xsimulator.net@gmail.com ----------------------------------------------
    
    
    //--------------------------------------------------USAGE-----------------------------------------------------------
    
    // ##protocol##
    // syntax:
    // $<axis><value>#<checkvalue>*
    
    // example:
    // $X123#123*
    
    // 1-axis example for x-sim2:
    // ~36~X~a01~~35~~a01~~42~   // Axis in CAPITAL letters
    
    // 3-axis example for x-sim2:
    // ~36~X~a01~~35~~a01~~42~~36~Y~a02~~35~~a02~~42~~36~Z~a03~~35~~a03~~42~  // Axis in CAPITAL letters
     
    // Use the USO output 16 bits - decimal - 115200 - 8 - NOPARITY - ONESTOPBIT
    
    //--------------------------------------------------USAGE-----------------------------------------------------------
    
    
    //--------------------------------------------Configuration---------------------------------------------------------
    
    // ##Pin Assignment##
    int rxOkLed     = 32;
    int rxNotOkLed  = 33;
    int ServoXPin   = 7;
    int ServoYPin   = 8;
    int tonePin   = 9; //pin for rpmcounter
    // ##Pin Assignment##
    int servosMinValue = 0; // servos motion range minimum value
    int servosMaxValue = 180; // servos motion range maximum value
    unsigned int servoval = 90; // servos initial start point
    
    //--------------------------------------------Configuration---------------------------------------------------------
    
    
    #include <Servo.h>
    
    Servo servoX;
    Servo servoY;
    Servo servoZ;
     
    unsigned int charbuffer[50];
    int bytesread = 0;
    int serialchar;
    int axis;
    boolean packageRecieved = false;
    boolean PackageVaild = false;
    int packageLength;
    
    
     
     
    void setup() {
      Serial.begin(115200);        // Connect to the serial port
    
      pinMode(rxOkLed,OUTPUT);     // Package verified led    
      pinMode(rxNotOkLed,OUTPUT);  // Package  Corrupt led
     
      servoX.attach(ServoXPin);           
      servoY.attach(ServoYPin);
    
    }
    
    void loop () {
      unsigned int axisValue;
      unsigned int axisValueCheck;
    
      if(Serial.available() > 0) {
        serialchar = Serial.read();
           // Serial.print(\nbyte: );
           // Serial.print(serialchar);
       
        if (serialchar == 42){
          packageRecieved = true;
          packageLength = bytesread;
          bytesread = 0;
        // Serial.print(\nPackage recieved!!);
        }
       
        else {
       
          if ((serialchar == 36) || (bytesread > 0) && (packageRecieved == false)) {
           charbuffer[bytesread] = serialchar;
           bytesread ++; // ready for next char
           //Serial.print(\nbytesread: );
           //Serial.print(bytesread);
           //Serial.print(\nbyte: );
           //Serial.print(serialchar);
           }
         }
       }
    digitalWrite(rxOkLed,LOW);
    digitalWrite(rxNotOkLed,LOW);
    
      if (packageRecieved == true){
       int valueLength = (packageLength - 3) / 2;
       int decMultiplier = 1;
       axisValue = 0;
       axisValueCheck= 0;
      
       for (int i=valueLength; i > 0; i--){
        axisValue = axisValue + ((charbuffer[i + 1 ] - 48) * decMultiplier);
        axisValueCheck = axisValueCheck + ((charbuffer[i + valueLength + 2] - 48) * decMultiplier);
        decMultiplier = decMultiplier * 10;
        }
     
      if (axisValue == axisValueCheck){
        axis = charbuffer[1];
        PackageVaild = true;
        //Serial.print(\naxisValue: );
        //Serial.print(axisValue);
        //Serial.print(\naxisValueCheck: );
        //Serial.print(axisValueCheck);
       
        if (PackageVaild == true){
          digitalWrite(rxOkLed,HIGH); // blink the OK led
         
         
          switch (axis) {
            case 88: //ascii for X
                  servoval = map(axisValue, 0, 65535, servosMinValue, servosMaxValue);
                 servoX.write(servoval);
            break;
           
            case 89: //ascii for Y
                 servoval = map(axisValue, 0, 65535, servosMinValue, servosMaxValue);
                 servoY.write(servoval);
            break;
           
            case 90://ascii for Z
                servoval = map(axisValue, 0, 65535, 0, 433);
                tone(tonePin,servoval);
          
           }
         }
       }
        else {
          digitalWrite(rxNotOkLed,HIGH); //blink the Not OK led
          }
       
      packageRecieved = false; // were now done with this package - on to the next one
      
    }
    
    }
    
    Last edited: Feb 17, 2015
  11. gazz

    gazz Member

    Joined:
    Feb 16, 2012
    Messages:
    35
    Location:
    Scarborough
    Balance:
    105Coins
    Ratings:
    +3 / 0 / -0
    My Motion Simulator:
    Arduino
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    woohoo, it's alive.....

    A little tweak to the values of the frequency... 10Hz min, as going under that causes the needle to flip round to the end stop and get stuck there, and the rev counter is nicely twiddeling round from below zero to off the scale and back again,

    little annoying is the way he force sender seems to have a dead zone when it crosses zero, so the needles stop halfway through their sweep before moving again, slower the auto slider is set, the more pronounced this pause is, but i imagine that wont be there when i feed it the values from the sim.

    But thanks to Dan i now have a servo driven gauge working and my rev counter working on it's origional pulse counter and air-core driver board.

    Next up is the fuel and water gauges, they need a voltage referance to earth, so i imagine something like a standard pwm signal through a transistor is needed for them.

    But i am just so happy the needles are moving, may sound simple to most, but it's a big leap forwards for me, i can now study the code and figure out what's going on, and hopefully learn from it.

    i gather it isnt too hard to add extra outputs to the arduino code? going to try in a minute anyways,

    but thanks again Dan and the others who've helped me get this far,
  12. gazz

    gazz Member

    Joined:
    Feb 16, 2012
    Messages:
    35
    Location:
    Scarborough
    Balance:
    105Coins
    Ratings:
    +3 / 0 / -0
    My Motion Simulator:
    Arduino
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Been having a play with your code slightly Dan,

    i've now got one servo guage, 1 air-core fuel gauge (pwm to earth) and 1 rev counter (air-core with pulse counter board, fed a frequancy from 50 to 433Hz)

    and they are all swinging from stop to stop, :clap:
    Rev counter is the smoothest, as it has a circuit board to take the pulses and smooth them out, the servo is pretty jerky, but i have a naff servo from a crashed plane,
    but the fuel gauge is pretty jerky too, and the coils of the driver motor sing a bit, but i know that's down to the very basic pwm code i've used,

    need to see if i can smooth the pwm output of the arduino a bit, or maybe use external circuitry involving a few capacitors... mind the fuel gauge shouldent swing about anyway, so it's not the end of the world, i just want to get rid of the singing coils as even when holding a position the coils are singing, which is almost as annoying as the racket a servo makes.

    The rev counter and fuel gauge's signals go through a common emitter transistor each, so they are referenced to 12 volts, and the current from the gauge isnt going back through the arduino,

    Heres the code i'm using:
    Code:
      //------------3DofDuino 0.01 - tone output for RPM, PWM output for Fuel Gauge-----------------------
    //-------------------------------Daniel Christiansen - X-Sim->Arduino mega Interface -------------------------------
    //--------------------------------------daniel.christiansen@gmail.com ----------------------------------------------
    
    
    //--------------------------------------------------USAGE-----------------------------------------------------------
    
    // ##protocol## 
    // syntax:
    // $<axis><value>#<checkvalue>*
    
    // example:
    // $X123#123*
    
    // 1-axis example for x-sim2:
    // ~36~X~a01~~35~~a01~~42~   // Axis in CAPITAL letters
    
    // 3-axis example for x-sim2:
    // ~36~X~a01~~35~~a01~~42~~36~Y~a02~~35~~a02~~42~~36~Z~a03~~35~~a03~~42~  // Axis in CAPITAL letters
      
    // Use the USO output 16 bits - decimal - 115200 - 8 - NOPARITY - ONESTOPBIT
    
    //--------------------------------------------------USAGE-----------------------------------------------------------
    
    
    //--------------------------------------------Configuration---------------------------------------------------------
    
    // ##Pin Assignment##
    int rxOkLed     = 32;
    int rxNotOkLed  = 33;
    int ServoXPin   = 7;
    int FuelPin   = 8; //Pin for fuel gauge
    int tonePin   = 9; //pin for rpmcounter
    // ##Pin Assignment##
    int servosMinValue = 0; // servos motion range minimum value
    int servosMaxValue = 180; // servos motion range maximum value
    unsigned int servoval = 90; // servos initial start point
    
    //--------------------------------------------Configuration---------------------------------------------------------
    
    
    #include <Servo.h> 
    
    Servo servoX;
    Servo servoY;
    Servo servoZ;
      
    unsigned int charbuffer[50];
    int bytesread = 0;
    int serialchar;
    int axis;
    boolean packageRecieved = false;
    boolean PackageVaild = false;
    int packageLength;
    
    
      
      
    void setup() {
      Serial.begin(115200);        // Connect to the serial port
    
      pinMode(rxOkLed,OUTPUT);     // Package verified led     
      pinMode(rxNotOkLed,OUTPUT);  // Package  Corrupt led
      
      servoX.attach(ServoXPin);            
    
    }
    
    void loop () {
      unsigned int axisValue;
      unsigned int axisValueCheck;
    
      if(Serial.available() > 0) {
        serialchar = Serial.read();
           // Serial.print(\nbyte: );
           // Serial.print(serialchar);
        
        if (serialchar == 42){
          packageRecieved = true;
          packageLength = bytesread;
          bytesread = 0;
        // Serial.print(\nPackage recieved!!);
        }
        
        else {
        
          if ((serialchar == 36) || (bytesread > 0) && (packageRecieved == false)) {
           charbuffer[bytesread] = serialchar;
           bytesread ++; // ready for next char
           //Serial.print(\nbytesread: );
           //Serial.print(bytesread);
           //Serial.print(\nbyte: );
           //Serial.print(serialchar);
           }
         } 
       }
    digitalWrite(rxOkLed,LOW);
    digitalWrite(rxNotOkLed,LOW);
    
      if (packageRecieved == true){
       int valueLength = (packageLength - 3) / 2;
       int decMultiplier = 1;
       axisValue = 0;
       axisValueCheck= 0;
       
       for (int i=valueLength; i > 0; i--){
        axisValue = axisValue + ((charbuffer[i + 1 ] - 48) * decMultiplier);
        axisValueCheck = axisValueCheck + ((charbuffer[i + valueLength + 2] - 48) * decMultiplier);
        decMultiplier = decMultiplier * 10;
        }
      
      if (axisValue == axisValueCheck){
        axis = charbuffer[1];
        PackageVaild = true;
        //Serial.print(\naxisValue: );
        //Serial.print(axisValue);
        //Serial.print(\naxisValueCheck: );
        //Serial.print(axisValueCheck);
        
        if (PackageVaild == true){
          digitalWrite(rxOkLed,HIGH); // blink the OK led
          
          
          switch (axis) {
            case 88: //ascii for X
                  servoval = map(axisValue, 0, 65535, servosMinValue, servosMaxValue); 
                 servoX.write(servoval); 
            break; 
            
            case 89: //ascii for Y
                 servoval = map(axisValue, 0, 65535, 0, 235); 
                 analogWrite(FuelPin,servoval); 
            break;
            
            case 90://ascii for Z
                servoval = map(axisValue, 0, 65535, 50, 433);
                tone(tonePin,servoval); 
           
           }
         }
       } 
        else {
          digitalWrite(rxNotOkLed,HIGH); //blink the Not OK led
          }
        
      packageRecieved = false; // were now done with this package - on to the next one
       
    }
    
    }
    i'm sure there are more bits i should have removed, as it's now only driving one servo, but your code deffinately works, and if it wasnt for it, i'd still be pulling my hair out wishing i could get the gauges to do something,
  13. Crashtender

    Crashtender New Member

    Joined:
    Mar 7, 2012
    Messages:
    4
    Balance:
    0Coins
    Ratings:
    +0 / 0 / -0
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Hi Dan,

    Got an Arduino over here as well. :yes:
    Did some programming for it in the past, looked similar to your code except i did not do the error checking.
    Maybe I can be of any help?

    PM me if you like to team up :cheers:

    Erwin
  14. Crashtender

    Crashtender New Member

    Joined:
    Mar 7, 2012
    Messages:
    4
    Balance:
    0Coins
    Ratings:
    +0 / 0 / -0
    Re: Dan's 3dofDuino - Arduino based interface for X-Sim2

    Hi Dan,

    Got an Arduino over here as well. :yes:
    Did some programming for it in the past, looked similar to your code except i did not do the error checking.
    Maybe I can be of any help?
    I wanted to try your code and see how it runs over here, but at the moment I can't download the x-sim software as the server seems to be down.

    PM me if you like to team up :cheers:

    Erwin
  15. DanielDk

    DanielDk Member

    Joined:
    Feb 27, 2012
    Messages:
    38
    Balance:
    386Coins
    Ratings:
    +12 / 1 / -0
    Re: Ver. 0.02 - Dan's 3dofDuino - Arduino interface for X-Sim2

    Hi Erwin

    As of ver 0.02 - Neither does mine :)
    Thanks for the offer - i might take you up on that.
    right now I cant figure out the XORing function :)

    Daniel
  16. Crashtender

    Crashtender New Member

    Joined:
    Mar 7, 2012
    Messages:
    4
    Balance:
    0Coins
    Ratings:
    +0 / 0 / -0
    As far as I can understand the XOR function returns either a 0 (if both opperands are 0 or both apperands are 1) or a 1 (if both opperands are different). What's it needed for?
  17. Crashtender

    Crashtender New Member

    Joined:
    Mar 7, 2012
    Messages:
    4
    Balance:
    0Coins
    Ratings:
    +0 / 0 / -0
    To translate the XOR function in plain english:

    I have two opperands, A and B. Do they differ?

    1 = yes
    0 = no
  18. caiubbo84

    caiubbo84 Member

    Joined:
    May 19, 2010
    Messages:
    40
    Location:
    italy
    Balance:
    240Coins
    Ratings:
    +2 / 0 / -0
    Hi Dan,
    Nice job, i buyed an arduino mega 2560 r3 right now, my ask is your code ready for more then 3 dof, so what i need to change to have a 4 dof? Thanks for help, i'm very new in programming.

    Regards
    Caiubbo
  19. DanielDk

    DanielDk Member

    Joined:
    Feb 27, 2012
    Messages:
    38
    Balance:
    386Coins
    Ratings:
    +12 / 1 / -0


    yup - - up to 12x servos and 9 pwms simultaneously - its in the feature log in the first post :)
  20. arsal1233

    arsal1233 New Member

    Joined:
    Oct 5, 2012
    Messages:
    1
    Balance:
    0Coins
    Ratings:
    +0 / 0 / -0
    You have mentioned different codes can you please mention which code i will use to interface my system with x-sim?
    Please i need help as i am nob in this field..