1. 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!
  2. 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
  3. 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 here. Do not following these rules will lead to permanent exclusion from this website: Read the forum rules.

3DOF Concept Model using RaspberryPi

Discussion in 'DIY Motion Simulator Projects' started by Leo Salo, Jul 15, 2017.

  1. Leo Salo

    Leo Salo New Member

    Joined:
    May 30, 2017
    Messages:
    11
    Occupation:
    Electronics Engineering
    Location:
    Melbourne, Australia
    Balance:
    219Coins
    Ratings:
    +19 / 0 / -0
    My Motion Simulator:
    3DOF, DC motor
    Here is my first concept model. Made on a shoe-string budget, so it's a bit rough and looks ridiculous - but I'm happy with it! My daughter volunteered Foxy to be the test pilot.
    P1070041.JPG I have used a Raspberry Pi running a simple python script to interface with the GameEngine via LAN. The PWM for the servos is provided by an Adafruit PCA9685.
    Here is a video of Foxy's first test drive.

    and a closer looks at the servos in action:


    The reason I have used a Raspberry Pi is simple because I had one sitting around gathering dust. I used the network to interface it because this was the easiest way to achieve this with the Pi, since they don't have a serial port as such. The Adafruit PCA9685 is a 16 channel PWM controller - primarily designed for controlling LEDs. It does the job for RC servos although the movement resolution is not great.

    To explain breifly for anyone wondering - the PCA9685 has a 12-bit timebase, so each PWM cycle is divided into 4096 'steps'. The RC servos require a 50Hz PWM signal, which is 20ms per cycle. (So each 20ms is divided into 4096 steps). The normal range of motion on these servos requires a pulse between approx. 1ms - 2ms. So there is only about 1ms difference in the pulse length between one end of movement to the other. We are only using about 1/20th of the 4096 steps. This equates to around 200 steps for a 90 degree movement - which is not too bad I guess. In practice most servos can move somewhat beyond this - and also can run a slightly higher frequency which helps too.

    I chose to use Python for scripting the software, although this was not my first choice. I only chose this because there was a ready made Adafruit library for interfacing the PCA9685. I was concerned that there may be some lag doing it this way - but it seems ok.
    • Like Like x 6
    • Winner Winner x 2
  2. Ads Master

    Ads Master

    Balance:
    Coins
    Ratings:
    +0 / 0 / -0
  3. Mmcool

    Mmcool Member

    Joined:
    Jun 26, 2015
    Messages:
    67
    Location:
    USA
    Balance:
    1,118Coins
    Ratings:
    +19 / 7 / -0
    My Motion Simulator:
    2DOF
    This is cool! I have some raspberry pi lay around, and I'd like to try that. Do you have available the code for the python script?
  4. Leo Salo

    Leo Salo New Member

    Joined:
    May 30, 2017
    Messages:
    11
    Occupation:
    Electronics Engineering
    Location:
    Melbourne, Australia
    Balance:
    219Coins
    Ratings:
    +19 / 0 / -0
    My Motion Simulator:
    3DOF, DC motor
    @Mmcool here is the script. You will also need to enable I2C (can do this with raspi-config on Raspbian) for the PCA9685. A quick google will show you how this is connected to the GPIO header.
    The Adafruit library for this is on GitHub - see comments in code.

    Code:
    from __future__ import division
    import time
    # you will need to install the library for PCA9685
    # available on github
    # https://github.com/adafruit/Adafruit_Python_PCA9685
    import Adafruit_PCA9685
    
    import socket
    import sys
    import re
    
    
    pwm = Adafruit_PCA9685.PCA9685() #init pwm default address 0x40
    
    # you may need to tweak these values depending on the servo you use
    # pulse starts at count zero
    # pulse ends somewhere between SERVO_MIN and SERVO_MAX
    SERVO_MIN = 150 # of 4096
    SERVO_MAX = 550 # of 4096
    SERVO_FREQ = 60 # some servos can work at higher frequencies - this will give you better resolution
    DATA_BITS = 4096 # incoming data bit width... 1024 for 10 bit, 4096 for 12 bit, etc.
    # note: I found there was a glitch with GameEngine when set to 10-bit.
    # When the sliders in test mode were put to ZERO - it would output 1024.
    # But they seem to work ok in 12-bit mode.
    
    # helper funtion to convert x-bit input to viable servo output
    # eg. input of 4096 will return SERVO_MAX
    #     input of 0 will return SERVO_MIN
    def crunch(a):
        return int(((a * (SERVO_MAX - SERVO_MIN)) / DATA_BITS) + SERVO_MIN)
    
    # i added some notes about the data coming in from LIVE FOR SPEED
    # not sure if all games will be the same.
    # just need to reverse the +'s and -'s if something is back to front.
    
    def addsurge(fs):
        # surge goes up under accelleration
        global leftpwm
        global rightpwm
        global backpwm
        global SURGEGAIN
    
        backpwm += (int(fs)-2048) * SURGEGAIN
        leftpwm -= (int(fs)-2048) * SURGEGAIN
        rightpwm -= (int(fs)-2048) * SURGEGAIN
    
    def addpitch(fs):
        # pitch goes up as nose of vehicle goes down
        global leftpwm
        global rightpwm
        global backpwm
        global PITCHGAIN
    
        backpwm -= (int(fs)-2048) * PITCHGAIN
        leftpwm += (int(fs)-2048) * PITCHGAIN
        rightpwm += (int(fs)-2048) * PITCHGAIN
    
    def addheave(fs):
        # heave goes up when airbourne - ie. zero G
        global leftpwm
        global rightpwm
        global backpwm
        global HEAVEGAIN
    
        backpwm -= (int(fs)-2048) * HEAVEGAIN
        leftpwm -= (int(fs)-2048) * HEAVEGAIN
        rightpwm -= (int(fs)-2048) * HEAVEGAIN
    
    def addsway(fs):
        # sway goes up around right hand bends
        global leftpwm
        global rightpwm
        global backpwm
        global SWAYGAIN
    
        leftpwm += (int(fs)-2048) * SWAYGAIN
        rightpwm -= (int(fs)-2048) * SWAYGAIN
    
    def addroll(fs):
        # roll goes up around left hand bends
        global leftpwm
        global rightpwm
        global backpwm
        global ROLLGAIN
    
        leftpwm -= (int(fs)-2048) * ROLLGAIN
        rightpwm += (int(fs)-2048) * ROLLGAIN
    
    #set pwm servo frequency
    pwm.set_pwm_freq(SERVO_FREQ)
    
    UDP_IP = '10.0.0.25'  # you will need either a staic IP for your Raspi, or use DHCP and reserve an address in your router (preferred)
    UDP_PORT = 3883  # any port will do - just make sure the GameEngine settings match
    
    # gains for each input.  Note: setting these too high will cause servos to reach their limits and clip the movement.
    SURGEGAIN = 0.5
    SWAYGAIN = 0.5
    HEAVEGAIN = 0.5
    PITCHGAIN = 0.5
    ROLLGAIN = 0.5
    
    # set up UDP server
    sock = socket.socket(socket.AF_INET, # Internet
                         socket.SOCK_DGRAM) # UDP
    
    server_address = (UDP_IP, UDP_PORT)
    print >> sys.stderr, 'starting up on %s port %s' % server_address
    
    sock.bind(server_address)
    
    # main program loop
    while True:
        # get data set
        data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
        dofs = data.split('|') #dofs is an array of strings
    
        # init accumulators - 2048 is the middle of movement in 12-bit mode
        leftpwm = 2048
        rightpwm = 2048
        backpwm = 2048
    
        # add the effects of incoming data
        addpitch(int(dofs[0]))
        addroll(int(dofs[1]))
        addsurge(int(dofs[3]))
        addsway(int(dofs[4]))
        addheave(int(dofs[5]))
    
        # limits - let us know when we hit a limiter.
        if leftpwm > 4096:
            leftpwm = 4096
            print "CLIP Left High"
    
        if leftpwm < 0:
            leftpwm = 0
            print "CLIP Left Low"
    
    
        if rightpwm > 4096:
            rightpwm = 4096
            print "CLIP Right High"
    
        if rightpwm < 0:
            rightpwm = 0
            print "CLIP Right Low"
    
        if backpwm > 4096:
            backpwm = 4096
            print "CLIP Back High"
    
        if backpwm < 0:
            backpwm = 0
            print "CLIP Back Low"
    
    
        # set the PWMs
        # I'm using channel 4, 5 & 6 on the PCA9685
        pwm.set_pwm(4, 0, crunch(leftpwm))  #LEFT
        pwm.set_pwm(5, 0, crunch(rightpwm))  #RIGHT
        pwm.set_pwm(6, 0, crunch(backpwm))  #BACK
    
    # debug stuff
    #    print "pitch: ", dofs[0], " roll: ", dofs[1], " surge: ", dofs[3], " sway: ", dofs[4], " heave: ", dofs[5]
    #    print "L: ", leftpwm, " R: ", rightpwm, " B: ", backpwm
    
    
    
    The GameEngine settings I used... (note: yaw is not used)

    Axis settings:
    motion_axis_assign.png

    Interface settings:
    motion_interface.png
    • Informative Informative x 4
    • Like Like x 1
  5. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    14,758
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    109,049Coins
    Ratings:
    +8,897 / 43 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
    • Like Like x 2
  6. Wanegain

    Wanegain Active Member

    Joined:
    Nov 6, 2013
    Messages:
    550
    Location:
    Bruxelles
    Balance:
    1,462Coins
    Ratings:
    +276 / 2 / -0
    My Motion Simulator:
    2DOF, DC motor, Arduino
    Really good idea to use a Rpi
    • Agree Agree x 1
  7. yobuddy

    yobuddy Well-Known Member Staff Member Moderator SimAxe Beta Tester SimTools Developer Gold Contributor

    Joined:
    Feb 9, 2007
    Messages:
    3,716
    Occupation:
    Computer Technician
    Location:
    Portland, Oregon - USA
    Balance:
    31,910Coins
    Ratings:
    +3,781 / 10 / -0
  8. Leo Salo

    Leo Salo New Member

    Joined:
    May 30, 2017
    Messages:
    11
    Occupation:
    Electronics Engineering
    Location:
    Melbourne, Australia
    Balance:
    219Coins
    Ratings:
    +19 / 0 / -0
    My Motion Simulator:
    3DOF, DC motor
    Just scored some nice geared motors, so the next phase can begin. Apparently they are off some kind of garage door opener. 300W peak and 100W nominal @24V and a 15:1 gearbox. They also have a nice 100 step optical rotary encoder already fitted. They might run a little fast to attach the servo arm directly to the motor, but I'm thinking with the drive belt cog that's already there I might be able to run a belt to another bigger cog to give it more reduction. WP_20171023_19_08_36_Pro.jpg
    • Like Like x 1
  9. ferslash

    ferslash Active Member

    Joined:
    Feb 8, 2011
    Messages:
    489
    Balance:
    4,697Coins
    Ratings:
    +177 / 2 / -0
    would rapberry be better than a simple oldschool arduino in terms of speed and soo on?
  10. Leo Salo

    Leo Salo New Member

    Joined:
    May 30, 2017
    Messages:
    11
    Occupation:
    Electronics Engineering
    Location:
    Melbourne, Australia
    Balance:
    219Coins
    Ratings:
    +19 / 0 / -0
    My Motion Simulator:
    3DOF, DC motor
    I don't think there would be any benefit in terms of speed - the opposite is probably more likely if anything because there is a fairly heavy operating system running in the background on the RPi. I only used it because it was sitting on my desk gathering dust! Ultimately I was thinking of using a PIC. Maybe one small benefit would be that the RPi itself is the development machine - so you don't need to upload your programs off a separate machine to test them. EDIT: The main benefit I found was the onboard ethernet/LAN support. This made a convenient way of communicating to the PC running the game engine without worrying about a separate serial interface. WiFi would also be an easy addition, and even comes on-board with the new RPi3's
    • Like Like x 1
    Last edited: Oct 24, 2017
  11. Leo Salo

    Leo Salo New Member

    Joined:
    May 30, 2017
    Messages:
    11
    Occupation:
    Electronics Engineering
    Location:
    Melbourne, Australia
    Balance:
    219Coins
    Ratings:
    +19 / 0 / -0
    My Motion Simulator:
    3DOF, DC motor
    I saw a thread a while back, back couldn't find it now. There was some discussion on using stepper motor driven linear actuators, and the power and speed they are capable of, etc. As it happens, I was working with one of these actuators for a bag filling machine, and I thought I would test it out - and they are not too bad. I just made a quick video to show the speed. More speed would also likely be possible with a better controller. I'm not sure how much force it produces, but it can lift me off the ground (90kg) without missing a beat.
  12. Leo Salo

    Leo Salo New Member

    Joined:
    May 30, 2017
    Messages:
    11
    Occupation:
    Electronics Engineering
    Location:
    Melbourne, Australia
    Balance:
    219Coins
    Ratings:
    +19 / 0 / -0
    My Motion Simulator:
    3DOF, DC motor


    I've finally had a bit of time to work on my servos. Here I have just finished some fine tuning of the PID control, and I am pretty happy with the result. I plan to have the pulley wheels on these motors replaced with eccentric wheels, and this will move a swinging arm with a roller to produce the linear motion. I have used an IBT-2 H-bridge motor drive connected to a home-made PCB with a PIC16F1503 microcontroller. The software is not entirely finished yet, and there is no control input. For testing I just have it moving back and forward between two positions to get the PID gains tuned in. I chose the IBT-2 motor drive because it has a high 30A rating, and was cheaper to buy complete than the parts would cost me on their own. The PIC16F1503 was chosen only because I had a few spares of these. This is a very basic PIC, and is a bit limited - but it may just be ok. I have not decided yet on the format of the control input - my prototype model used standard servos, so I might attempt a standard servo control input. I'm just not sure if this PIC can do the job - it took a bit of trickery to get it reading the encoder fast enough... but I will find out soon.
  13. Gadget999

    Gadget999 Active Member

    Joined:
    Dec 27, 2015
    Messages:
    870
    Location:
    London
    Balance:
    6,392Coins
    Ratings:
    +192 / 4 / -0
    My Motion Simulator:
    2DOF, DC motor, Arduino, 6DOF
    What type of cnc actuator is that ? Are they expensive ?