Modify sequence

Hi hope someone can help. I'm using my Picoborg Reverse to control my sons model railway. I'm able use the GUI to move trains forward and backward. I've also run the sequence that comes with the examples, using the code as it is makes the train perform rather erratically as obviously this is for a robot allowing it to turn etc.
I've spent the weekend trying to modify the code for my own needs. I even tried using the fairground example.
Basically I need to insert a pause between each step.

Let me explain what I'm trying to achieve.

I would like the train(s) to move forward towards a station a set distance (in seconds) at 50% then speed up to 100% for a given distance (in seconds), then (upon approaching a station) it should slow down to 50% then stop. After a given time (for passengers to get on and off), the train is to move forward again at 50% and then 100%. ans so on.......This is to run continuously on a loop until stopped by CTRL+C.

Eventually I would like to fully automate this by having the code run when a button is pressed and stop when the sequence comes to an end. Any Ideas where to look? could I just insert a push button library at the beginning of the script?

Thanks in advance.

piborg's picture

That sequence should be simple enough to write.
I would suggest starting a completely new Python script to keep things simple.

Here is a quick example along the lines of what you want:

#!/usr/bin/env python

# Import library functions we need
import PicoBorgRev
import time

# Setup the PicoBorg Reverse
PBR = PicoBorgRev.PicoBorgRev()
PBR.Init()
PBR.ResetEpo()

# Loop over the sequence until the user presses CTRL+C
print 'Press CTRL+C to finish'
try:
    while True:
		print '50% speed'
		PBR.SetMotor1(0.5)
		PBR.SetMotor2(0.5)
		time.sleep(10)

		print '100% speed'
		PBR.SetMotor1(1.0)
		PBR.SetMotor2(1.0)
		time.sleep(10)

		print '50% speed'
		PBR.SetMotor1(0.5)
		PBR.SetMotor2(0.5)
		time.sleep(5)

		print 'Stop'
		PBR.SetMotor1(0.0)
		PBR.SetMotor2(0.0)
		time.sleep(5)
except KeyboardInterrupt:
    # User has pressed CTRL+C, turn both motors off
    PBR.MotorsOff() 
    print 'Done'

You can use the RPi.GPIO library to check if a push button connected to a GPIO pin is pushed.
There is a good guide here: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/robot/buttons_an...

Many thanks the code works just how I imagined it. However.......for some reason it never stops in the same spot. There is a slight over run of a few millimeters which after multiple runs adds up. I've tried slowing the train down to a crawl before stopping but it always runs over. I've yet to try the push button.
Thanks again.

piborg's picture

If you really need precise delays you can try busy waiting.
This is where the script spends the time doing something instead of sleeping.

If you add this function into the script before the try section:

def BusyWait(seconds):
    endTime = time.time() + seconds
    while (time.time() < endTime):
        pass

You can then swap any calls to time.sleep:

time.sleep(5)

with calls to BusyWait instead:

BusyWait(5)

The advantage to this is that it should be a much more accurate delay then using sleep calls.
There are a large number of downsides though:

  1. It will consume more CPU power, increasing power usage while running
  2. Anything else running at the same time will get less attention, this is often where short "hangs" come from while using a computer
  3. If you use this behaviour in threaded code it will typically cause one thread to hog all the time, preventing the script working correctly.

Once again thanks for your help. I've yet to try this. Will it operate like a brake or just give a more accurate form of timing? I've thought about slowing the train down and then going in reverse for a split second before calling for it to stop. Thanks again.

piborg's picture

The code above is just more accurate timing for the delay.

Going into reverse briefly should work well acting as a break.
i would suggest using lower output values in reverse to avoid getting wheel spin instead.

Well I tried the busy wait and it still creeps, tried reverse as a brake no joy. Tried both nada. Eventually I stcck a voltmeter on the track only to find with 19v input and 19v to track , running at 25% I get 4.5v ( forward) and.....-4.89V (reverse). Same for both motors. No wonder it creeps. I'm now going to try adjust my reverse timings to match the forward. I'll post my results.

Well after a frustrating weekend I have the following results. I have used a commercial Digital Multi-meter and measured a supply voltage of 19.47 v DC ( mains adapter)

Using the GUI to adjust the speeds and taking readings directly from the board

Motor 1 forward
10% +1.67 V ; 20% +3.73 V ; 30% +5.63 V ; 50% +9.50 V ; 75% +14.36 V ;90% +17.29 V ; 100% -19.46 V Motor 1 reverse
10% -2.05 V ; 20% - 4.03 V ; 30% -5.94 V ; 50% -9.93 V ; 75% -14.70 V ;90% -17.57 V ; 100% -19.48 V

Motor 2 has very similar readings.
I wondered if it might be PWM settings on the Raspberry Pi but I've tried swapping Pi's and get similar results. Is this normal ? Any ideas?
As a last resort I would like to use the Pi reverse with an Arduino as I have one lying around gathering dust. Would the code you gave above be similar and what pins are used?
But if the fault is with the Pi Reverse the results would be the same with the Arduino.

piborg's picture

This is actually normal, it is due to how the driver chips work on the PicoBorg Reverse itself.
In short the PWM is generated by the onboard PIC, not by the Raspberry Pi.

The cause is actually quite hard to explain, but it is due to something called "dead time".
Put simply the driver actually has three states: on, off, and floating.
When the PWM signal changes between high and low the chip goes into this floating state very briefly to avoid shorting the power connections.

What I would suggest is if the distance is always drifting the same way that you try adjusting the power levels slightly to compensate.
For example:
Forward: +0.10, Reverse: -0.09.
Bear in mind the multi-meter cannot accurately represent the voltage seen by the motors due to this dead time, so it may take some experimenting to find a good adjustment.

If you really need the trains to change speeds and stop at accurate positions you should probably look at some kind of feedback.
I would suggest either:

  1. Have some switches / sensors that detect the train passing a point
  2. Try to add an encoder to each train to measure how far it has gone

Without some feedback the distance will be slightly out to some degree each time so it is worth looking into.

Subscribe to Comments for &quot;Modify sequence&quot;