GH3 Bot - Attempt Two

chigley

Senior Member
Hey all,

Been a while since I actually posted here, but I still read most of the threads out of interest. :)

Some may remember my attempts at a Guitar Hero playing robot a couple of months back, which was only a partial success. I've now decided that, after a bit of a break, its time to finish it off!

Here's a quick recap of how it works, and how successful it's been so far:



The photos above show the full robot setup and a close-up of the circuit board. It's a PICAXE 28X1 based circuit, using a combination of analog switches and transistors to interface with an Xbox 360 controller.

I've also uploaded a video on YouTube, which shows how far through the song the bot manages to get before it fails. Watch the video here - http://www.youtube.com/watch?v=F2dNWlYIVRw.

As you can see from the video, the bot fails after 438 notes because it suddenly stops playing, whereas my aim is for the bot to fully play this song without missing a note. It fails because the 28X1's programme memory isn't large enough to store the note data for the entire song as the code currently looks like this:

Code:
setfreq em16

main:
if porta pin0 = 1 then play_song
goto main

play_song:
let pins = %01000000
pause 210
let pins = %00000000
pause 100
let pins = %10000000
pause 158
let pins = %00000000
pause 156
let pins = %00100000
pause 210
let pins = %00000000
pause 100
let pins = %10000000
pause 158
let pins = %00000000
pause 152
let pins = %00010000
pause 210
let pins = %00000000
pause 104
let pins = %10000000
pause 158
let pins = %00000000
pause 152
let pins = %01000000
pause 210
let pins = %00000000
pause 104
let pins = %10000000
pause 158
let pins = %00000000
pause 152
let pins = %00100000
pause 210
let pins = %00000000
[...]
This, obviously, isn't an efficient way to programme the IC, as the song is far too long for all of the note data to be stored on the IC alone. I therefore looked for alternative storage solutions:

  • I originally tried to use an EEPROM IC to hold note data for the song. Unfortuntely this was very inconsistent as data was being read at a different rate each time, which made it impossible to perfectly time the playing of the bot.
  • I also tried using a Vinculum VDRIVE2, as seen in the first of the two photos above. This was also unsuccessful for similar reasons. It was inconsistent in that random characters would creep in to a string whilst reading from a text file. I also found the VDRIVE incredibly difficult to work with from a PICAXE.

This is where I really need some advice. What other methods could you suggest for storing note data for the song? I've extracted the data for the entire song, and can manipulate it into any format required. I just need some means of storing it, such that the PICAXE can read it, whilst preventing the timing of the PICAXE's operations from being affected.

Sorry for the epic post, but all advice would be very much appreciated - it's about time I actually finished a project! :)

Charlie
 

MartinM57

Moderator
A pragmatic approach might be to swap to a PICAXE 28X2 with 1024 bytes of scratchpad memory. How many bytes in the song?

Have the bulk of the code writing the data to the scratchpad (might need to do it in another slot, depending on how much code space is taken up by writing all the bytes to scratchpad*) and then a read/set pins loop using @ptrinc (should be constant timing) to play it.

* - or you could even load the scratchpad from your EEPROM IC, which would minimise code space creating it

Have a look at manual 2 searching for "scratchpad", "RUN", "@ptrinc" etc

OT: how have you recorded the game in such high definition? I'm impressed :)
 

chigley

Senior Member
A pragmatic approach might be to swap to a PICAXE 28X2 with 1024 bytes of scratchpad memory. How many bytes in the song?

Have the bulk of the code writing the data to the scratchpad (might need to do it in another slot, depending on how much code space is taken up by writing all the bytes to scratchpad*) and then a read/set pins loop using @ptrinc (should be constant timing) to play it.

* - or you could even load the scratchpad from your EEPROM IC, which would minimise code space creating it

Have a look at manual 2 searching for "scratchpad", "RUN", "@ptrinc" etc

OT: how have you recorded the game in such high definition? I'm impressed :)
Thanks for the advice! Not entirely sure how many bytes the song is, but it's roughly 8 minutes long and has over 3,000 notes. I'd therefore estimate it at ~1kb, with 3 bytes per note (output state, duration held, duration before next note.) On second thought, it may be a lot longer, as some of the pause values will need two bytes and will have to be read into a word variable (I think...)

Will have a read of the manual shortly!

I use a Blackmagic Intensity Pro capture card for my Xbox 360 footage recording, see here: http://www.blackmagic-design.com/products/intensity/. The quality is a lot better pre-upload, as I've still not quite got my render settings perfect.
 

Technical

Technical Support
Staff member
With a 28X2 you could probably just work as you already have been doing. When out of program space in slot 0 program simply use a 'run 1' command at the end of the program and then continue your new data from that point in a new program in slot 1. Repeat for slots 2 and 3.

Your program will then use slots 0-1-2-3 in order. This is much greater than the 28X2 single slot memory capacity.

Also look for repetition within the sequences so that 'chunks' could be loaded into sub-procedures and called multiple times. This will greatly reduce memory usage.
 
Last edited:

womai

Senior Member
As a more sophisticated version: Instead of using pause commands for the note timing, use a timer interrupt. I.e. put out the first note, then set up the timer so the interrupt occurs after the specifed note duration. In the interrupt routine, put out the next note, set up the timer for its duration. And so on. While one note plays you are then pretty much free to do what you want, the timing would remain spot-on. You could either use that time to pull the next note info from EEPROM, or - for basically unlimited storage - request it from a simple program running on the PC. That program could read the note info from a text file. Advantage - very easy to change the song.
 

lanternfish

Senior Member
Also look for repetition within the sequences so that 'chunks' could be loaded into sub-procedures and called multiple times. This will greatly reduce memory usage.
There should be very large chunks of repeated notes/phrases, as it is rock after all ;). Just a matter of determing where they are. Could be a help to hop onto one of the guitar tab sites and look at the structure there.

Hope this helps
 

chigley

Senior Member
Thanks for all of your replies! :)

When I read Technical's post about the 28X2, I thought that this may be a simple solution to all of my problems! However, when I looked more realistically at it, there still wouldn't be anywhere near enough programme space for the entire song. The code would be about 14,900 lines long, which wouldn't fit on a 28X2 even if I filled all four slots. Not even close :(

@wombai - I could go back to the EEPROM, with more sophisticated timing methods, although I'd rather not as this would involve making a third board which would take a lot of time! I'll wait to see if there's any more suggestions which can be applied on my existing circuit first.

Charlie
 

MartinM57

Moderator
...or Ramtron FRAM - quite big storage and very quick - far quicker than PICAXE Basic so if your PICAXE code path is the same for every note, the runtime performance will be predictable (and constant).

Need a new board though - and you would have to search around for some code to write/read FRAM - it exists somewhere here...
 

chigley

Senior Member
...or Ramtron FRAM - quite big storage and very quick - far quicker than PICAXE Basic so if your PICAXE code path is the same for every note, the runtime performance will be predictable (and constant).

Need a new board though - and you would have to search around for some code to write/read FRAM - it exists somewhere here...
So you're saying that I could read in data on a loop from FRAM and the read time would be constant all of the time? Is it going to be difficult to talk to from the PICAXE? (As that's the problem I had with the VDRIVE...)
 

MartinM57

Moderator
Should be...(but then I'm surprised that EEPROM reading is too variable)

I suppose the problem is that you're playing 'open loop' and have to have pretty good accuracy on every note or else after n hundred notes you're sufficiently out of sync that it foobars on you?

How about something (much more complex and maybe not even do-able at PICAXE Basic speeds) where it can re-sync (with what? that's the problem) every, say, 100 notes..?

FRAM isn't that hard to interface to and is certainly reliable once you've got the right code.
 

chigley

Senior Member
Should be...(but then I'm surprised that EEPROM reading is too variable)

I suppose the problem is that you're playing 'open loop' and have to have pretty good accuracy on every note or else after n hundred notes you're sufficiently out of sync that it foobars on you?

How about something (much more complex and maybe not even do-able at PICAXE Basic speeds) where it can re-sync (with what? that's the problem) every, say, 100 notes..?

FRAM isn't that hard to interface to and is certainly reliable once you've got the right code.
You'd be surprised how much 1ms actually makes. Towards the earlier days of this project I was so frustrated about it losing time after playing about 50 notes, all it took was adding 1ms to each delay and it managed over 100! The game does, of course, allow some leeway but the more synchronous the method the better.

The problem with the EEPROM was that notes were being held for different lengths where the length should have been constant. It couldn't even manage a simple loop with accurate enough timing!

A fully-synchronous method would be far better, as opposed to timing it based on the previous note. I originally hoped to use something like the settimer command, but a major tick of 1ms isn't possible. The original time values extracted from the game are all timed in ms from the start of the song, which would be far more sensible than timing from the previous note.

Just had a quick search of the forum and can't see any FRAM code lying about. Going to read some datasheets now :)

Thanks for all your advice!
 

chigley

Senior Member
Woah, never heard of an SMD adapter before :) Can't find any 8-pin ones though, do they exist or will I have to make-do with a 16-pin?

EDIT: Spoke to soon, found one the second after I posted!
EDIT2: Actually, I'm not sure I've found the right thing after all...
 
Last edited:

chigley

Senior Member
@Charlie.

Another try:
http://cgi.ebay.co.uk/Surface-Mount-Converter-SOIC-8-JEDEC-AND-EIAJ-STANDARD_W0QQitemZ360185226311QQcmdZViewItemQQptZUK_BOI_Electrical_Components_Supplies_ET?hash=item53dcb66447

I bought some earlier this year, from the same supplier.
See pic below.

In fact, I've got a couple spare,
if you can find a good home for them.

PM if you're interested.

e
Thanks a lot for finding those - I swear I looked at a list of all items from that seller, but didn't see them!

Are you sure you wouldn't mind donating one? I'd feel incredibly guilty :p

What do you think the chances are of this working with a setup of 28X2 and FRAM? If the general consensus is that it'll probably be successful, then I may just make a PCB, in which case I'd just solder the SMD straight onto the board.

Charlie

EDIT: I meant to ask, do you think that the PICAXE could talk to the FRAM using the usual writei2c/readi2c commands, or would it be more complicated, as these commands are intended for EEPROM?
 
Last edited:

eclectic

Moderator
Thanks a lot for finding those - I swear I looked at a list of all items from that seller, but didn't see them!

Are you sure you wouldn't mind donating one? I'd feel incredibly guilty :p

What do you think the chances are of this working with a setup of 28X2 and FRAM? If the general consensus is that it'll probably be successful, then I may just make a PCB, in which case I'd just solder the SMD straight onto the board.

Charlie

EDIT: I meant to ask, do you think that the PICAXE could talk to the FRAM using the usual writei2c/readi2c commands, or would it be more complicated, as these commands are intended for EEPROM?
1. No problems in sending a couple of adapters.
Just PM where to.

2. Do NOT solder directly to the board!!
The chips are £4 - £7 each.
Use a TPS adapter. Breadboard then Veroboard with socket.

3. 28X2 and FRAM? Sorry, but I'll pass on that one. :)

e
 

MartinM57

Moderator
Code to write to and read from FRAM...255 reads of a 3 axis analogue accelerometer, once every 250mS, writing to FRAM. Then reads back all the data from the FRAM.

Uses hardware spi on a PICAXE 40x1

Enjoy.
Code:
'#########################################################
' Directives
'#########################################################
#picaxe 40x1
#terminal 19200
'#########################################################
' Symbols
'#########################################################
' accelerometer pins
symbol X_ACCEL_PORT	= 5
symbol Y_ACCEL_PORT	= 6
symbol Z_ACCEL_PORT	= 7

' FRAM constants
symbol cs           = 0
symbol FRAMAddress  = w13
symbol FRAM_WREN    = 6 'Set Write Enable Latch
symbol FRAM_WRITE   = 2 'Write Memory Data
symbol FRAM_READ    = 3 'Read Memory Data
symbol FRAM_WRSR    = 1 'Write Status Register

'#########################################################
' Start of code
'#########################################################
setfreq em16

'#########################################################
' Init code
'#########################################################
' spi mode 0,0 - and setfreq em32 with spimedium seems to work fine
hspisetup spimode00, spimedium

' send write enable
low cs 
hspiout (FRAM_WREN) 
high cs

' remove block protection..or else we won't get very far!
low cs 
hspiout (FRAM_WRSR,0) 
high cs

'#########################################################
' Main loop
'#########################################################
main:

	FRAMAddress = 0
	
	'255 writes
	for b13 = 1 to 255
		READADC X_ACCEL_PORT, b1
		READADC Y_ACCEL_PORT, b2
		READADC Z_ACCEL_PORT, b3
	
		gosub write_to_FRAM
		pause 1000
	next

	'255 reads
	FRAMAddress = 0
	for b13 = 1 to 255
		gosub read_from_FRAM
	next

goto main

'#########################################################
' Write to FRAM
'#########################################################
write_to_FRAM:
' write contents of registers b01, b1 and b2 to FRAM 
' starting at location FRAMAddress

sertxd ("Writing FRAMAddress = ", #FRAMAddress, " X=", #b1, " Y=", #b2, " Z=", #b3, 13, 10)

' send write enable
low cs 
hspiout (FRAM_WREN) 
high cs

' write to location FRAMAddress (w13 == b26:b27)
low cs 
hspiout (FRAM_WRITE, b26, b27)
hspiout (b1)
hspiout (b2)
hspiout (b3)
high cs

' increment FRAM address for next time...
FRAMAddress = FRAMAddress + 3
' ...and wrap around if full
IF FRAMAddress = 8190 THEN {FRAMAddress = 0} ENDIF

return

'#########################################################
' Read from FRAM
'#########################################################
read_from_FRAM:
' read contents of registers b01, b1 and b2 from FRAM 
' starting at location FRAMAddress

' read from location FRAMAddress (w13 == b26:b27)
low cs
hspiout (FRAM_READ, b26, b27) 
hspiin  (b0) 
hspiin  (b1) 
hspiin  (b2) 
high cs

sertxd ("Reading FRAMAddress = ", #FRAMAddress, " X=", #b0, " Y=", #b1, " Z=", #b2, 13, 10)

'increment FRAM address for next time...
FRAMAddress = FRAMAddress + 3
'...and wrap around if full
IF FRAMAddress = 8190 THEN {FRAMAddress = 0} ENDIF

return
 

chigley

Senior Member
@MartinM57 - thanks for finding that. FRAM also supports I2C, would this be an easier option for me? Assuming the PICAXE's i2c commands would work as standard, I imagine it'd be far simpler than an SPI setup.

Cheers
 

MartinM57

Moderator
Find it:grrr:

Good grief - I wrote it after extensively studying the FRAM data sheet. Worked first time as well :D

You need another grown up for I2C FRAM - SPI isn't exactly that hard though....apart from giving you the pin connections, I've done it all for you ;)
 

chigley

Senior Member
Find it:grrr:

Good grief - I wrote it after extensively studying the FRAM data sheet. Worked first time as well :D

You need another grown up for I2C FRAM - SPI isn't exactly that hard though....apart from giving you the pin connections, I've done it all for you ;)
Woah, thanks a lot :)

Think that's enough questions from me tonight! Going to have a good read now.

Thanks to both of you.
 

chigley

Senior Member
Well, it's been a couple of days and I've gathered my thoughts together. I'm going to give this a shot using a combination of the 28X2 alongside a 256Kb FRAM chip using SPI comms. Hopefully I'll have full success this time!

Here's the schematic I've put together tonight, quite a big image sorry but I wanted to make sure it was all legible:



Next step is to build it! Already have my SO8 adapter(s) thanks to electic, and I'll start to gather the rest of the kit over the next week or so. I'm getting excited! :)

Charlie
 

MartinM57

Moderator
Haven't looked in detail, but I wouldn't advise closing that reset switch on the left. I suppose it will reset the chip (at the same time that the power supply blows) ;)

You probably want the top of the switch directly on the RESET pin rather than across the power supply....
 

chigley

Senior Member
Haven't looked in detail, but I wouldn't advise closing that reset switch on the left. I suppose it will reset the chip (at the same time that the power supply blows) ;)

You probably want the top of the switch directly on the RESET pin rather than across the power supply....
Eep - glad you spotted that ! Cheers :)
 

hippy

Ex-Staff (retired)
Also the 10K in the download circuit is on the wrong side of the 22K - It's not meant to be a potential divider; it's a 22K current limit with the 10K to stop it floating when the cable is removed.
 
Top