Spin Programming Questions
NASA Robotics Team
Posts: 24
Ok so I come from a C background in programming and I'm finally getting familiar with the Spin language, but there are a couple of things that I have not been able to figure out. Hopefully someone out there has run into these problems and can steer me in the right direction. I'll put the C code that I'm trying to emulate and hopefully you can see what I mean in the statements. I do have the Spin programming book, but I have not been able to find help in it or on the web. Here goes nothing!
1) Are there user defined structures in Spin? I was trying to create a data type called robot that would contain the X and Y position, heading, speed, etc. In C I would have used a structure, but I haven't found an equivalent for Spin.
2) When declaring variables (VAR section), I would like to use constants (CON section) to declare array sizes. The compiler won't let me use anything but literal numbers.
3) 2D arrays... are they supported?
4) This last one is giving me the run around. I'm trying to communication to a SICK LADAR using serial. I have used the FullDuplexSerial, ExtendedFullDuplexSerial, SimpleSerial, and SimpleDebug. We haven't run into any problems transmitting data, but we're running into some problems using the receive. We can rx less than 16 bytes fine, even over multiple successive messages, however the message that contains the distance data from the LADAR is 100+ bytes long. We have tried using all of the spin objects from the exchange and have not been able to get the data after 16 or so bytes. I even tried the ExtendedFullDuplexSerial and someone else's modified one that allowed for 256 bytes, neither worked. We know the data we are supposed to be seeing and they are not matching. Has anyone run into problems rxing many bytes of data?
Thanks for all of the help,
NASA_Robotics (Josh)
1) Are there user defined structures in Spin? I was trying to create a data type called robot that would contain the X and Y position, heading, speed, etc. In C I would have used a structure, but I haven't found an equivalent for Spin.
typedef struct { int x; int y; int heading; } robot_t;
2) When declaring variables (VAR section), I would like to use constants (CON section) to declare array sizes. The compiler won't let me use anything but literal numbers.
#define MAX_SIZE 10 int array[noparse][[/noparse]MAX_SIZE];
3) 2D arrays... are they supported?
int array[noparse][[/noparse]10][noparse][[/noparse]12];
4) This last one is giving me the run around. I'm trying to communication to a SICK LADAR using serial. I have used the FullDuplexSerial, ExtendedFullDuplexSerial, SimpleSerial, and SimpleDebug. We haven't run into any problems transmitting data, but we're running into some problems using the receive. We can rx less than 16 bytes fine, even over multiple successive messages, however the message that contains the distance data from the LADAR is 100+ bytes long. We have tried using all of the spin objects from the exchange and have not been able to get the data after 16 or so bytes. I even tried the ExtendedFullDuplexSerial and someone else's modified one that allowed for 256 bytes, neither worked. We know the data we are supposed to be seeing and they are not matching. Has anyone run into problems rxing many bytes of data?
Thanks for all of the help,
NASA_Robotics (Josh)
Comments
obviously you will have to use different names. Also, you would have to put them in the order long, word, byte. You would then use it something like this
2) Should work but you will need to put the array in a VAR section like this
3) Nope. But its not that hard to do it just using a single array.
4) Could be that the buffer isn't big enough. What speed is the data stream and how long does it take you to use the data? I think the buffer is only 16 bytes long for fullDuplexSerial
CON
SIZE = 10
VAR
word array[noparse][[/noparse]SIZE]
3. No but creat an array 10x12 and index correctly e.g. array[noparse][[/noparse]x*10+y]
4. Some things to look at:
The rx routines will overwrite the receive buffer if you dont read from the rx buffer fast enough, so make sure you are reading quickly when testing i.e. reading and writing to PC is a problem if the pc speed is slower than the ladar speed.
Does the ladar support cts/rts flow control, there is a version of the serial driver that supports flow control (at least cts is tested), this might help if the ladar is sending a lot very quickly and overwriting the receive buffer
I have found the serial routines dont have the same tolerence for baud rates that most hardware uarts have. i.e. I have a serial camera that works to a PC at 115200 but with prop the baud rate is 116500 (at 115200 is close but not every char is correct but some are) so try a few baud rates around the one the ladar uses
1) I'm going to try using the objects as a structure and see how that turns out.
2) I don't why that didn't work when I tried it. Went over and over the code and couldn't figure out why I couldn't use the CON defines as array sizes, but it's working now. Hmm.... go figure [noparse]:)[/noparse]
3) I was hoping that 2D arrays were supported ... just makes reading the code a bit easier to read.
4) We're still at odds about the serial data. Going to try the suggestions and see if we can make any headway.
Thanks guys!!!
Rayman's suggestion is worth a look [noparse]:)[/noparse]
Using C may help solve the packet problem if the corruption is a function of speed in getting data off the hopper ... you could also write the interface in Propeller asm. It is quite easy to make a .spin assembly driver work with C, and a FullDuplexSerial example already exists.
Look this post for·FullDuplexSerial·C code: http://forums.parallax.com/showthread.php?p=727942
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
While we're at it. Here's another one:
I'm trying to compute the heading of the robot based off of (X,Y) position data. Since we're simulating navigation on the moon, a compass won't help and we can't use GPS. To compute the angle I need to use an inverse trig function (ie: arccos, arcsin, etc). Is there anything in Spin that can compute this? I'm looking through the Math Lib but nothing stuck out at me. Is there other ways of computing an angle using distances that the Prop could handle?
[noparse][[/noparse]edit]
Is is possible to have a common header file between all of the objects? I have a bunch of CON defines that I would like to only change in one place.
Post Edited (NASA Robotics Team) : 6/30/2008 7:14:21 PM GMT
This maps nicely to the propellor hardware architecture, but doesn't seem to suit the object encapsulation at all well, as the central object will be re-instantiated by any callers rather than sharing the data. The solution in the FAQ thread (put the data in DAT) doesn't really help as it makes more sense to hold a large data item in the
Am I structuring it the wrong way ? I'm a C programmer really .. and yes, I might be better off using iccv7 but I'd like to get some understanding of the native environment before I try something else.
-adrian
CON
val =1
var
long avariable
pub get
return avariable
pub set(p)
avariable := p
But I'd need to include that file at the top level (receiving updates from the comms object) and also in some of the device driver objects. Wouldn't that result in several instances of the data object in VAR space ? And if I put it in DAT space, I'll be limited to the RAM on a cog, I think. Is that right ?
I could include it just once at the top level and have the code there shuttling data from comms object to data and out to devices .. which sounds fine, except that there are a lot of operations to perform and I think the top level object will become large and difficult to maintain - I'd prefer to split it into an update object for each of the devices. I guess that means I need to embed the data into each device.
Tim, we came to the same type of solution. Having one cog be more or less the scheduler/data transporter and the other cogs doing continuous processing on the information. So far that seems to working out good for us. Thanks!
Post Edited (NASA Robotics Team) : 7/2/2008 4:42:15 PM GMT
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
You should be able to cut float32 down so that you only need one cog. You can even copy just the code you need if you are using pasm. There is info in the pdf about the different float libraries (it should be in your library folder)
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
http://www.youtube.com/user/NASAROBOTICS
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
This is the beginning section of code from the LmmPrint.spin. I see that you send cognew the AsmAddress of 'lmm' to begin execution, but I don't understand how you can pass a Parameter of '@MainEntry'. You get the address of MainEntry, but it's assembly code. I'm confused as to how the assembly code is calling the Spin code through the '@onechar', '@putx', '@putc', etc functions.
I guess before you answer that one. VGATextProxy is watching 'vpcmd' and executing commands based off of that value. I see that this works using two cogs and a shared variable, but I need to be able to do this on one cog. Here's a bit of pseudo-code for what I'm trying to do:
How can you get the assembly to return back to the Spin code in 'start'? Or vise versa?
Thanks,
Josh
<Edit> : I'm looking through some of the libraries and I think one of the SPI objects I'm using might have what I am looking for. Hmm....
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
http://www.youtube.com/user/NASAROBOTICS
Post Edited (NASA Robotics Team) : 7/10/2008 7:56:22 PM GMT
The example I gave complicates matters a little. Like I said ignore the LMM stuff. I should have just provided a straight asm example; sorry about that. You should replace the "jmp #LmmCall" with call #subroutine and "jmp #LmmReturn" with subroutine_ret.
You can change the start routine to directly start the asm cog with the MainEntry as "cognew(@MainEntry, @SomeParameterTable)" ... SomeParameterTable could be a variable or array with control/status info. The "par" variable is used to get SomeParameterTable data to cog memory.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
You can't return to Spin from assembly code. COGNEW or COGINIT forks a new processor (execution thread), then returns as soon as the new processor is set up. After the COGNEW, you can put code to communicate with the new processor through shared variables and you can wait until the new processor has done something, but this is not a return. You've essentially got several independent computers in the same room and they're connected to a network and can communicate back and forth (through shared variables or I/O pins). The 2nd processor can't "return". It can only do stuff or turn itself off. The Spin interpreter happens to be a program that's stored in ROM. An assembly program can load and execute a copy of the Spin interpreter either on top of itself or it can fork a new processor to do it. The instruction that does this has an operand that points to some tables in shared memory that define the Spin program to be executed. This is not a return. You're starting a new processor on a new program.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔