mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Gertbot DCC Python example

Tue Jun 30, 2015 11:08 pm

Very nice unit - but I am having a major mental blockage on getting it working utilizing the Python library provided. Has anyone got the basics going using pure Python? Forward, back etc, once I have that I will work the rest out.

Thanks

User avatar
Gert van Loo
Posts: 2487
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: Gertbot DCC Pyhton example

Wed Jul 01, 2015 8:17 am

At the bottom of this page: http://www.gertbot.com/download.html
there is a python example: http://www.gertbot.com/gbdownload/src/py_rover.tgz
It is for two brushed motors.
Is that the one you are using?

p.s. I corrected the typo in the title to make it easier for others to find.

mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Wed Jul 01, 2015 3:07 pm

I'm trying to do DCC. Used the rover to get some basics stuff going (UART etc) but now I'm up to trying to send it a DCC command and I'm not sure of the structure.
Do we send preamble, the DCC decoder address is included in the data packet etc...

Thanks
Mike

User avatar
Gert van Loo
Posts: 2487
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: Gertbot DCC Python example

Wed Jul 01, 2015 3:36 pm

I am at work and have a better look later.

If I remember:
To send a DCC command you put all the standard DCC data in a array and send it to a board and to a channel.
Simplest is to send it to ALL channels. (Channels which are not in DCC mode will just ignore the command)

the python arguments are: send_dcc_mess(board,channel,data)
I hope you know what your board ID is set to.
For channel use 0x0F.
To send a stop command fill data with two values: the locomotive number and the stop command.
e.g. Loc = 0x03 and stop = 0x40
The 'send_dcc_mess' routine will do the rest.

User avatar
Gert van Loo
Posts: 2487
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: Gertbot DCC Python example

Thu Jul 02, 2015 5:13 pm

Sorry, yesterday was gone before I realized it.
I have unearthed some Python code I used to test the DCC.

Code: Select all

   board = 0
   print("DCC test on board %d\n" % board)
   for chan in range(0,4) :
     gb.set_mode(board,chan,gb.MODE_DCC)
     
   print("Performing number of writes\n")
   message = [0x03, 0x68 ]
   print("0x03,0x68: move loc 3. Press return to send")
   input()
   gb.send_dcc_mess(board,0xF,message)
   
   message = [0x02, 0x67 ]
   print("0x02,0x67: move loc 2. Press return to send")
   input()
   gb.send_dcc_mess(board,0xF,message)

   message = [0x00, 0x40 ]
   print("0x00,0x40: Stop All. Press return to send")
   input()
   gb.send_dcc_mess(board,0xF,message)

mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Thu Jul 02, 2015 5:38 pm

Awesome thanks, I am familiar with those days.

I reread the spec last night (that's a great way to get to sleep) and I think the critical point was that each thing that you want the train to do is a separate packet. So turn light on and go x speed are different packets.
The way the spec is written, or I read it, it takes a deep dive to determine that.
I'll test today and let you know how it goes.

Mike

mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Thu Jul 02, 2015 10:12 pm

Hi Gert - got it working sort of.

Here's whats happening.
Track is connected to channel 0
If I run the python code (below) - I get an error and nothing happens.
ERROR Enable 0 was negated.

Move the track to channel 1.
ERROR Enable 1 was negated.

However if I run the Raspbian gb_dcc GUI then the train gets power to it's track (so can't be a short or anything).
Then if I run the python code I get no errors and the train moves as programmed.

Any suggestions?

Code: Select all

import gertbot as gb
import curses
import time

BOARD       = 0         # Which board we talk to
PHY_CHANNEL = 0          # channel for  track
LOCO        = 0x04
gb.open_uart(0)

#gb.set_mode(BOARD, PHY_CHANNEL, MODE)

print("DCC test on board %d\n" % BOARD)
for chan in range(0,4) :
 gb.set_mode(BOARD,chan,gb.MODE_DCC)

print ("ERROR" , gb.error_string(gb.read_error_status(BOARD)))
print ("MOTOR CONFIG " , gb.get_motor_config(BOARD, 0))


print("Performing number of writes\n")
message = [0x04, 0x63 ]
print("0x04,0x68: move loc 4. Press return to send")
input()
gb.send_dcc_mess(BOARD,0xF,message)

User avatar
Gert van Loo
Posts: 2487
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: Gertbot DCC Python example

Fri Jul 03, 2015 7:35 am

You are right!
I could not remember the details but I had a recollection that I also saw the enables activating.
I just went into the C-GUI code and found this:

Code: Select all

  case MOT_MODE_DCC:
    // First switch channel short circuit to off
    uart_tx(CMD_STOPSHORT,id,ENDSTOP_OFF|ENB_ERR_IGNORE); // No short no endstops 
    // DCC mode  
    uart_tx(CMD_OPMODE,id,mode);
Just as a note: the short circuit protection is never switched off completely.
You just switch off that the CPU disables the channel.

I have to update the python drivers to include that.

mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Fri Jul 03, 2015 2:55 pm

Thanks, I'll test and let you know.

Mike

mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Mon Jul 06, 2015 5:51 pm

I added the three missing globals and then used send_raw to transmit them. I still get the "Enable 1 was negated" message but the train moves.

Code: Select all

ENB_ERR_IGNORE = 0x00
CMD_START_VAL  = 0xA0  # Serial protocol start flag
CMD_STOP_VAL   = 0x50  # Serial protocol end flag

print("DCC test on board %d\n" % BOARD)
for chan in range(0,4) :
 message = []                                      
 gb.ENDSTOP_OFF | ENB_ERR_IGNORE, CMD_STOP_VAL)
 message.append(CMD_START_VAL)                      
 message.append(gb.CMD_STOPSHORT)                   
 message.append((BOARD<<2) | chan)                  
 message.append(gb.ENDSTOP_OFF | ENB_ERR_IGNORE)    
 message.append(CMD_STOP_VAL)                       

 gb.send_raw(message)
 gb.set_mode(BOARD,chan, gb.MODE_DCC)


mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Fri Jul 24, 2015 5:23 pm

Hey Gert,

This was working and now it's stopped with a weird message:

('ERROR', 'Illegal error status code')
('MOTOR CONFIG ', [])

Dumbed down the code to minimum and still failing. Not sure what the message means:

Code: Select all

ENB_ERR_IGNORE = 0x00
CMD_START_VAL  = 0xA0  # Serial protocol start flag
CMD_STOP_VAL   = 0x50  # Serial protocol end flag
for chan in range(0,4) :
  message = []
  #gb.send_raw(gb.ENDSTOP_OFF | ENB_ERR_IGNORE, CMD_STOP_VAL)
  message.append(CMD_START_VAL)
  message.append(gb.CMD_STOPSHORT)
  message.append((BOARD<<2) | chan)
  message.append(gb.ENDSTOP_OFF | ENB_ERR_IGNORE)
  message.append(CMD_STOP_VAL)
  gb.send_raw(message)
  gb.set_mode(BOARD,chan, gb.MODE_DCC)

print ("ERROR" , gb.error_string(gb.read_error_status(BOARD)))
print ("MOTOR CONFIG " , gb.get_motor_config(BOARD, 0))

User avatar
Gert van Loo
Posts: 2487
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: Gertbot DCC Python example

Fri Jul 24, 2015 5:46 pm

Code: Select all

Dumbed down the code to minimum and still failing. Not sure what the message means:
Most likely an error in the driver.
I get an error number from the board "gb.read_error_status(BOARD)"
Then I look that up in set of strings. "gb.error_string(...)"
If the error number is outside the sets of strings the program will fail.

Please print out the error number only. So what is the value of "gb.read_error_status(BOARD)".
Then I can have a look in the code and see what the actual error is.

mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Fri Jul 24, 2015 5:55 pm

print ("ERROR STRING" , (gb.read_error_status(BOARD)))

returns -1

User avatar
Gert van Loo
Posts: 2487
Joined: Tue Aug 02, 2011 7:27 am
Contact: Website

Re: Gertbot DCC Python example

Fri Jul 24, 2015 9:04 pm

OK, that suggest the gb.read_error_status call failed.
The board returned garbage or nothing at all.
See the python driver code below.

Code: Select all

#
# Return error status of board
# (zero means no pending errors)
# (-1 means read error)
def read_error_status(board):
   # To do : check the arguments
   dest = board<<2
   wrtbuf = [PRE, CMD_GET_ERROR, dest, POST, POST, POST, POST]
   os.write(filehandle,bytes(wrtbuf))
   termios.tcdrain(filehandle)
   ok , data = read_uart(4)
   if (not ok) : 
     return -1
   val = (data[2]<<8) | data[3]
   return val
It also explains the error text you are seeing.
The gb.error_string code reports "Illegal error status code" for any code outside the expected range:

Code: Select all

...
"DCC illegal message (length)",                   # ERROR_DCC_MESS     0x0020 
"Illegal error status code"  )                    # MAX_ERROR

def error_string(error_number):
  if (error_number<0 or error_number>MAX_ERROR):
    error_number = MAX_ERROR
  return error_text[error_number]

I can't say why there is a read error.
Most likely the return data stream got out of sync.
That is: one or two bytes got lost.
I have no good solution to prevent that.

mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Sun Jul 26, 2015 3:34 pm

hey Gert,

Thanks for the help. Did some hardware troubleshooting and after swapping the Pi it started working again, grrr...

Mike

mike21724
Posts: 10
Joined: Tue Jun 30, 2015 10:56 pm

Re: Gertbot DCC Python example

Tue Nov 24, 2015 7:54 pm

My adventure continues...

Working great so far BTW. I have now built a RESTFul API that controls the train via the GertBot.

My next question is about power.

I need to pull more than the 2.5a from the track (closer to 5-6a). Reading the docs I was a little confused as there seems to be 2 options (one untested).

Option 1 seems to be to sync the control signals and then parallel out the outputs.
Option 2. Is untested.

What would you recommend?

Return to “HATs and other add-ons”