Drive fault above 18 volts

Forums:

Dear Piborg,

I have a problem with my script that is use. normally when i have my output voltage to the motors set to 18v everything works fine. But when i set it to 20v or higher i get the fault failed sending motor drive level.
Do you know how this is possible? This is the script im using.

#!/usr/bin/env python

###
#
# diabloJoystick.py: A script for controlling motors with the Diablo using a joystick.
#
# 04-07-2019
# Thieu Verstijnen
###

# Load library functions we want
from __future__ import print_function
from diablo import *
from time import sleep
from os import environ
from sys import exit, stdout, stderr
import pygame
import RPi.GPIO as GPIO

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT, initial=GPIO.LOW)

# Power settings
voltageIn = 24.0              # Total battery voltage to the Diablo
voltageOut = 18.0             # Maximum motor voltage
 
# Setup the power limits
if voltageOut > voltageIn:
    maxPower = 1.0
else:
    maxPower = voltageOut / float(voltageIn)

# Re-direct our output to standard error, we need to ignore standard out to hide some nasty print statements from pygame
stdout = stderr

# Setup the left Diablo
DIABLO1 = Diablo()
DIABLO1.i2cAddress = 38
DIABLO1.Init()
if not DIABLO1.foundChip:
    boards = ScanForDiablo()
    if len(boards) == 0:
        print('No Diablo found, check you are attached :)')
    else:
        print('No Diablo at address %02X, but we did find boards:' % (DIABLO1.i2cAddress))
        for board in boards:
            print('    %02X (%d)' % (board, board))
        print('If you need to change the I2C address change the set-up line so it is correct, e.g.')
        print('DIABLO1.i2cAddress = 0x%02X' % (boards[0]))
    exit()
#DIABLO1.SetEpoIgnore(True)                 # Uncomment to disable EPO latch, needed if you do not have a switch / jumper
DIABLO1.ResetEpo()
 
# Setup the right Diablo
DIABLO2 = Diablo()
DIABLO2.i2cAddress = 55
DIABLO2.Init()
if not DIABLO2.foundChip:
    boards = ScanForDiablo()
    if len(boards) == 0:
        print('No Diablo found, check you are attached :)')
    else:
        print('No Diablo at address %02X, but we did find boards:' % (DIABLO2.i2cAddress))
        for board in boards:
            print('    %02X (%d)' % (board, board))
        print('If you need to change the I2C address change the set-up line so it is correct, e.g.')
        print('DIABLO2.i2cAddress = 0x%02X' % (boards[0]))
    exit()
#DIABLO2.SetEpoIgnore(True)                 # Uncomment to disable EPO latch, needed if you do not have a switch / jumper
DIABLO2.ResetEpo()


# Settings for the joystick
axisUpDown = 1                          # Joystick axis to read for up / down position
axisUpDownInverted = False              # Set this to True if up and down appear to be swapped
axisLeftRight = 2                       # Joystick axis to read for left / right position
axisLeftRightInverted = False           # Set this to True if left and right appear to be swapped
buttonResetEpo = 16                     # Joystick button number to perform an EPO reset (Start)
buttonSlow = 8                          # Joystick button number for driving fast whilst held (L2)
slowFactor = 1.0                        # Speed to slow to when the drive fast button is not held, e.g. 0.5 would be half speed
buttonFastTurn = 9                      # Joystick button number for turning fast (R2)
buttoncross = 14                        # Button cross for lights on                
buttoncircle = 13                       # Button circle for lights off
buttonsquare = 15                       # Button square for claxon on
buttontriangle = 12                     # Button triangle for claxon off
interval = 0.00                         # Time between updates in seconds, smaller responds faster but uses more processor time

# Setup pygame and wait for the joystick to become available
environ["SDL_VIDEODRIVER"] = "dummy" # Removes the need to have a GUI window
pygame.init()
print ('Waiting for joystick... (press CTRL+C to abort)')
while True:
    try:
        try:
            pygame.joystick.init()
            # Attempt to setup the joystick
            if pygame.joystick.get_count() < 1:
                pygame.joystick.quit()
            else:
                # We have a joystick, attempt to initialise it!
                joystick = pygame.joystick.Joystick(0)
                break
        except pygame.error:
            # Failed to connect to the joystick
            pygame.joystick.quit()
            time.sleep(0.1)
    except KeyboardInterrupt:
        # CTRL+C exit, give up
        print ('\nUser aborted')
print ('Joystick found')
joystick.init()

try:
    print('Motors are ready to drive.')
    print('Press CTRL+C to quit')
    driveLeft = 0.0
    driveRight = 0.0
    running = True
    hadEvent = False
    upDown = 0.0
    leftRight = 0.0
    # Loop indefinitely
    while running:
        # Get the latest events from the system
        hadEvent = False
        events = pygame.event.get()
        # Handle each event individually
        for event in events:
            if event.type == pygame.QUIT:
                # User exit
                running = False
            elif event.type == pygame.JOYBUTTONDOWN:
                # A button on the joystick just got pushed down
                hadEvent = True
                if event.button == buttoncross:
                    GPIO.output(8, GPIO.HIGH)
                if event.button == buttoncircle:
                    GPIO.output(8, GPIO.LOW)
            elif event.type == pygame.JOYAXISMOTION:
                # A joystick has been moved
                hadEvent = True
            if hadEvent:
                # Read axis positions (-1 to +1)
                if axisUpDownInverted:
                    upDown = -joystick.get_axis(axisUpDown)
                else:
                    upDown = joystick.get_axis(axisUpDown)
                if axisLeftRightInverted:
                    leftRight = -joystick.get_axis(axisLeftRight)
                else:
                    leftRight = joystick.get_axis(axisLeftRight)
                # Apply steering speeds
                if not joystick.get_button(buttonFastTurn):
                    leftRight *= 0.5
                # Determine the drive power levels
                driveLeft = -upDown
                driveRight = -upDown
                if leftRight < -0.05:
                    # Turning left
                    driveLeft *= 1.0 + (2.0 * leftRight)
                elif leftRight > 0.05:
                    # Turning right
                    driveRight *= 1.0 - (2.0 * leftRight)
                # Check for button presses
                if joystick.get_button(buttonResetEpo):
                    DIABLO.ResetEpo()
                if not joystick.get_button(buttonSlow):
                    driveLeft *= slowFactor
                    driveRight *= slowFactor
                # Set the motors to the new speeds
                # Set the motors to the new speeds
                    DIABLO1.SetMotors(driveLeft * maxPower)
                    DIABLO2.SetMotors(driveRight * maxPower)
        # Wait for the interval period
        sleep(interval)
    # Disable all drives
    DIABLO1.MotorsOff()
    DIABLO2.MotorsOff()
except KeyboardInterrupt:
    # CTRL+C exit, disable all drives
    DIABLO1.ResetEpo()
    DIABLO2.ResetEpo()
    print('Terminated')
print()
GPIO.cleanup()

Greetings Thieu

piborg's picture

There are two main reasons for getting the "Failed sending motor X drive level" errors:

  1. The 5V power is not stable
  2. The I2C lines are have signal problems

Since things work properly at lower power we can rule out anything related to wiring problems.

The most likely problem is the 5V power stability. If this is the case it suggests the 5V regulator is unable to get enough power from the battery when the motors are running at higher power levels. We often see this kind of problem as batteries are starting to get flat. If you have not already I would suggest fully recharging the battery and try again. It is also possible that the battery cannot provide enough current for both the motors and the regulator at the same time.

I2C problems are less likely, but still possible. It is possible that the electrical "noise" generated by the motors is being picked up by the I2C lines like an antenna would. It might sound odd, but we have seen this twice before with other robots. If this is the case you can shield the 3-pin cables by carefully wrapping them in tinfoil - be careful to ensure that the foil cannot come into contact with any of the boards. Shorter cables between the Raspberry Pi and Diablo may also help.

Many thanks, this evening i will fully charge the batteries. I will let you know if it works

The batteries are now fully charged and everything works fine again thanks. I have 2 lead baterries of 12v parralel 7ah each, what kind of lipo battery do you recommend as replacing battery?

piborg's picture

Great news :)

For bigger projects (such as DoodleBorg) we have stuck with lead-acid because they are easy to get in higher capacities and relatively safe when handled properly.

Based on your code I presume you meant the batteries are in serial to produce a 24V battery:

Source: http://beautyinscience.com/ms-sem-4-physical-science.html

The best options would be either a 6S LiPo - 22.2V, or a 7S LiPo - 25.9V. The 6S will have a slightly lower maximum output and you would need the full 7Ah / 7000mAh for the same running time. The 7S would run at about 93% to get a 24V output so you can have a lower capacity, 6.5Ah / 6500mAh would give about the same running time.

Remember that you will also need an appropriate charger for the LiPo that supports the correct type.

Subscribe to Comments for &quot;Drive fault above 18 volts&quot;