Looking for Faster Objects for Nordic Wireless Modules nRF24L01+ and nRF2401A

13»

Comments

  • vanmunchvanmunch Posts: 567
    edited 2013-11-08 - 09:54:51
    Hi Duane,

    I don't mind at all, thank you for sharing your knowledge with us. I think these Nordic wireless modules have a lot of use for everyone.

    I've been working with the demo program from Post 9 and have it running with the cheap ebay modals. :) I've been able to mess around a bit with making some very, very minor changes to what it sends, but my experience with bit manipulation and hex is close to zero and I was wondering if you could help me a little bit.

    My end goal is to be able to send a device ID, variable name, and variable number as one packet. I then need to be able to read the device ID, variable name, and variable number on the slave. I don't need to be able to do it very quickly, 10 times per second is fast enough. It would be nice to send decimal numbers, but that would be icing on the cake.

    I'm able to follow the code to the "PreparePacket" method, but I'm lost once it goes to the "hex" method. I think I need to swap out the "hex" method with the "Dec" method from "FullDuplexSerialPlus". Am I on the right track or is there a better way? Thanks again for your time!

    Dave
  • Duane DegnDuane Degn Posts: 10,340
    edited 2013-11-08 - 11:08:13
    There are a variety of communication strategies.

    Some involve sending raw data while others convert the data to ASCII characters before sending.

    Is this what the Hex method looks like?
    PUB Hex(value, digits, localPtr)'' Print a hexadecimal number
      value <<= (8 - digits) << 2
      repeat digits
        byte[localPtr++] := lookupz((value <-= 4) & $F : "0".."9", "A".."F")
          
    

    If so, I think I took it from one of the serial drivers. What's nice about hex is a byte is always two characters. If you convert your numbers with a Dec method you can end up with three characters.

    I think I converted the data to ASCII in an attempt to make the demo easier to read. The demo just sends characters which can be immediately displayed when received.

    If you're not already familiar with ASCII, read the Wikipedia article about it. It's really important to understand the difference between characters and numbers (I think you already know this though).

    A good example of sending raw data are the Dynamixel servos. The trick with sending raw data is you either need to always use a set number of bytes with each transmission or you need to indicate how many bytes will be in the transmission as part of the header (this is what Dynamixels do). With raw data you can't use end of message characters since you wouldn't be able to tell the difference between an end of message character and a data point with same value as the end character.

    So you need to decide how you will send the data. If you're using text for the variable name then it sounds like you want to send ASCII characters. How many character can the device ID be and how many characters can the variable number be?

    How long can the variable name be? Is it always the same size? If not how will you mark it's end?

    I think you can start to understand why I used hex in the demo. It's always the same size for any particular number of bytes (two hex characters per byte).

    One thing I usually add to my packets but I don't think I included in the demo is a packet ID number (one raw byte). If the data is important, I generally send multiple transmissions of each packet. The receiver then sends an acknowledgement which includes the packet ID. Once the original transmitting unit receives the acknowledgement it stops sending that particular packet. Using the packet ID the receiving unit can tell if the received packet is new information or just a repeat of the previous packet. I use this technique in my chemistry lab where I don't want to miss any information being transmitted. It may not be practical to use this technique for a robot remote where lots of data needs to continuously stream.

    After attempting various communication protocols I start to see the value of some sort of wireless ethernet connection but of course that comes with a lot of overhead.

    As with so many things there are trade offs between the various protocols. Sending ASCII characters allows the use of control characters but comes at the expense of having to send twice as many bytes of data.

    Sorry for the long rant. I've thought about this stuff a lot. It can get really complicated really fast particularly if you want data to hop from one transceiver to another.

    If you can describe in more detail what you want to send and how you want it encoded I can give more specific advice. If you want to use Dec instead of Hex how many characters long will the number be?
  • vanmunchvanmunch Posts: 567
    edited 2013-11-08 - 12:59:37
    Hi Duane,

    Thank you for all of the information. It's very useful. I'm going through the ASCII article, it's mostly new stuff for me. I can see why converting everything to hex before you send it is so useful. You've sold me on it.

    For this project I'm monitoring I'm basically monitoring a ball that has pressure sensors mounted on the outside and a 6DOF IMU that I created inside. When the ball hits a wall, I want it to send me the greatest pressure sensor value with the sensor's ID (sensor12 1000), the x and y angles of the ball at the moment of impact (sensor0X 012.87;sensor0Y 102.45), and the rate of rotation at impact (sensor0R 0231) All sensor work and math has been done and I can scale the numbers a bit to get ride of decimal points. I've used XBees a lot in the past and I could use them for this project too, but the Nordics looked like a lot of fun and you can't beat the price. Please let me know if this is too complicated for the Nordic and if I should just stick with the XBee. I know that sometimes you start climbing a hill only to later find out that it's Mt. Borah. :)

    Thanks again for all of your time and help,

    Dave
  • Duane DegnDuane Degn Posts: 10,340
    edited 2013-11-08 - 13:42:37
    vanmunch wrote: »
    I'm going through the ASCII article, it's mostly new stuff for me.

    It's really important to distinguish between ASCII characters and raw data. A good learning exercise on using raw data is learning to use an AX12 Dynamixel servo. It's data protocol doesn't use ASCII characters so it can send data faster than if it had to convert the data to and from ASCII characters.

    I tend to use a mixture of raw data and ASCII character. I send some values as raw data if I know it's not going to contain a carriage return (13) since I used the carriage return as an end of message marker.

    I'm not really happy with my present wireless Prop to Prop communication protocol. I'll probably make the change to using raw data and including the message size in part of the header.
    vanmunch wrote: »
    I can see why converting everything to hex before you send it is so useful. You've sold me on it.

    I'm not completely sold myself. You still have to transmit two characters (each character takes up one byte in the packet) in order to send a single byte of data.
    vanmunch wrote: »
    . . . with the sensor's ID (sensor12 1000), the x and y angles of the ball at the moment of impact (sensor0X 012.87;sensor0Y 102.45), and the rate of rotation at impact (sensor0R 0231) All sensor work and math has been done and I can scale the numbers a bit to get ride of decimal points.

    The maximum packet size is 32 bytes. If you want to send all the above data in a single packet you probably will need to send raw data. You could have each position within the packet assigned to contain specific information. The first byte could hold the sensor's ID number (assuming you don't have more than 256 sensors), the second could be a message ID (so you know if you've missed data or if it's a retransmission of the same data). Each of the sensor values could be packed into two to four bytes depending on the resolution of the sensor.

    Alternatively you could send the data as ASCII characters but include an identifier indicating what type of data the packet contains. For example "sensor12 1000,sensor0X 012.87" could probably fix in a packet. If you trimmed the names of "sensor" to "s" you would fit additional data in the packet.

    I had considered attempting a UART type interface for these modules but the overhead of sorting the outgoing and incoming packets would use up a lot of program space (and it would be hard to program). So for now, the present and next version drivers will use packets.
    vanmunch wrote: »
    I've used XBees a lot in the past and I could use them for this project too, but the Nordics looked like a lot of fun and you can't beat the price. Please let me know if this is too complicated for the Nordic and if I should just stick with the XBee.

    The XBee is using packets internally but it shields the user for these details. XBees have there place. I have lots of XBees myself but these Nordic modules are so inexpensive I think it's worth the extra work to use them.

    I know I've used these Nordic modules to send data at least as complicated as what you're sending. You may want modify the way the data is being sent to make it more packet friendly.
    vanmunch wrote: »
    I know that sometimes you start climbing a hill only to later find out that it's Mt. Borah. :)

    But could you still live with yourself if you took the easy way out? :smile:
  • T ChapT Chap Posts: 4,036
    edited 2013-11-08 - 14:06:31
    I have really enjoyed messing with these modules. Once you get your basic understanding of the concepts of Status Bytes, Packet Length, Date Pipes, you can pretty much write up code to solve most any wireless need as if it were a straight wire. One neat thing about these modules is that there are 6 datapipes. Upon a receiver unit getting a packet, it fires a pin to let the processor know you have data. If you simply read the Status Byte you can find out what data pipe it was received on. In some cases where you don't really need to get data, but instead you just want to have a fast "wireless button", you simply read the Status Byte, determine the data pipe number, then perform some function based solely on the datapipe number. So, for example you can fire 6 buttons at about 297uS from the contact on one Propeller input pin to the output pin on the receiving Propeller. If you do need data, at 2meg you it is pretty fast as well.
  • Duane DegnDuane Degn Posts: 10,340
    edited 2013-11-08 - 14:22:59
    T Chap wrote: »
    . . . One neat thing about these modules is that there are 6 datapipes. . .

    Yes, I thought about the datapipes right after I submitted my last post. The current demo code (and driver) only uses the first datapipe.

    The code I hope to post soon (and now with all this activity around these modules it will probably be soon) will have the option of submitting the packet on any of the datapipes. I'll need to make sure there's a way to access the datapipe a message was received on from Spin. It's been too long since I've worked on this to remember what the faster driver did.

    I will be working on this in the coming week. I just got the touchscreen portion of my robot remote to work (I'll post a video soon in the other thread).

    @T Chap, I'll make sure and leave out the parts we discussed.
  • T ChapT Chap Posts: 4,036
    edited 2013-11-08 - 14:29:51
    Duane, no need to spend much time on editing my stuff to leave anything out. Maybe just use better terms that make more sense for the forum for general purpose button type trigger use versus my specific project terminology for the datapipe fast firing usage. I can post some examples sometime in the next week. Sending on any data pipe is simple, parsing per datapipe is easy, just read the status byte and get the datapipe number then get the data if there is something to do.
  • Duane DegnDuane Degn Posts: 10,340
    edited 2013-11-21 - 08:52:27
    I think I'm starting to get a handle on getting the new driver ready.

    I just thought I'd let you all know I'm actively working on this.
    0: result = 2
    0: Switching to data pipe # 2
    2: Slave has received a new transmission.
    2: rxCount[1] = 1936
    2: status = 000100
    2: Nordic #1 is received on data pipe #2 payload = "Hello World from data pipe two!!"
    

    The numbers at the beginning of each line identifies which cog is using the serial driver.

    I still need to make the changes suggested by T Chap and to break the demo into to separate (master/slave) programs.

    I think I should have something to post soon (maybe today if I have time to work on this).
  • T ChapT Chap Posts: 4,036
    edited 2013-11-21 - 12:11:09
    Duane, I use a version for master, one for slave, and one that is both depending on the use. Maybe your demo should be selectable mode versus either/or? With selectable modes, you can receive something then turn around and send it to other devices or reply to the original sender. I like to have all devices sitting in receive mode unless it needs to send something, then it sends and immediately flips back to rx.
  • vanmunchvanmunch Posts: 567
    edited 2013-11-25 - 08:47:04
    Looking forward to it. :) I'm curious, do you have any idea on how fast it will be able to send messages? 10 per second, 100?
  • T ChapT Chap Posts: 4,036
    edited 2013-11-25 - 09:05:56
    When you say "send a message", what do you mean? The devices can send 1 - 32 bytes in one packet, and can send packets back to back with only the time required to reload the TX payload data and tell it to transmit. I timed it once but can't find my notes. I think it was in the range of 400 - 500us for 32bytes.
  • Duane DegnDuane Degn Posts: 10,340
    edited 2013-11-25 - 10:21:45
    vanmunch wrote: »
    Looking forward to it. :) I'm curious, do you have any idea on how fast it will be able to send messages? 10 per second, 100?

    I made some progress this weekend. I should have some form of demo to post later today. I need to find my 16 channel logic analyzer so I can monitor two modules at once. The current demo requires a delay when I don't think there should be one.

    As T Chap says, the communication rate depends a lot on what you consider a message. It also depends on whether or not you need an acknowledgement of the data received (this will really slow things down).

    One feature I can see being useful would be some sort of rotating rx buffer. In my experiments this weekend I found one message would be overwritten by a second before the main program had time to retrieve the first.

    I have some working code now but I'd like to get to work a bit better before posting it. I'll post something today even if I don't have time to improve it.

    The current demo (not yet posted) can use two modules on one Propeller or you can use the same code and have the modules on separate Props. The program will shut down the cogs normally used to control a module if no module is detected.
  • Duane DegnDuane Degn Posts: 10,340
    edited 2020-03-07 - 18:24:19
    Previously Post #74

    I'm not happy with this demo yet, but I did promise to upload something.

    I received some of my encoder PCBs today so I ended up spending some of my time on my encoder project and I didn't get back to this project until late.

    As I mentioned before, the communication rate could be increased if it were just one direction.

    Still, this code should be able to run faster than it does. I intend to continue work on this driver next week.

    The datapipe methods work in the child object, I didn't include any datapipe use within the demo.

    I'm pretty sure I have some glitches in my code. It's been a while since I've read the nRF24L01+ datasheet and I think I'll need to spend some time with it and a logic analyzer to get this code up to speed. I haven't run any speed comparisons with the old driver, but my guess is this new version should be faster even with its rough edges.

    Edit(3/11/15): Warning, the code attached is an old version. There are better options available.
    I plan to upload this program or an improved version to my GitHub account
    If there isn't a replacement on GitHub send me a message and I'll make sure to upload the replacement code.

    Edit(9/29/15): I added the above edit because Parallax had warned a forum upgrade would leave old threads read only. I wanted anyone looking for more recent code to have a chance to find it in my GitHub account. I have not worked on the Nordic driver recently and I don't think I have any better code. I would like to improve the driver but I don't know when I'll have a chance to do so.
    Edit(3/7/20): Fixed link.
  • ItWillDoItWillDo Posts: 2
    edited 2013-12-03 - 12:38:50
    Hey guys,

    I'm new to this board and got linked here through this topic because I'm particularly interested in the NRF24L01+. I was thinking of using this component to "stream" audio but I'm really starting to doubt whether it's feasible. I've also looked at the objects you have posted, and I assume these are meant to be used to program the line of Parallax-microcontrollers? As far as I can interpret them, these contain some settings (for the parallax or the NRF24L01+?) and functional code written in assembly.

    My objective is to use a 16-bit ADC to sample audio at 96kHz (or 48 kHz if the prior isn't doable) and stream it to a receiver at a distance of about +- 30m. Right now I'm going to try and get a working prototype using the FRDM-KL25Z board with a built-in ARM Cortex M0+. The microcontroller on this board has pretty much all functionality I need built-in and is meant for low-power applications (I'll be making this a Li-ion powered module).

    Now the thing I'm struggling with most is whether I'll be able to stream audio-data at the desired speed. If my calculations are right:

    1B preamble - 3B address - 2B PCF (9bits) - 2B payload (16-bit samples from ADC) - 1B CRC = 9 bytes/sample. If I want to stream 96kHz audio, this would mean I need a whopping speed of 96000 * 9 = 864kB/s = 6,192 Mb/s. Even if I change it to 48kHz (which is approximately the minimum in my and Nyquists' opinion), it would come down to 3,096 Mb/s. Can someone clarify whether I made a mistake somewhere in my reasoning or are my fears in place and am I pretty much screwed?

    Thanks in advance,
    ItWillDo
  • Duane DegnDuane Degn Posts: 10,340
    edited 2020-03-07 - 18:21:29
    The fastest the nRF24L01+ can transmit is 2Mb/s and this data needs to include the preamble. I don't recall if the CRC can be completely turned off or not. I'm pretty sure you can send packets with up to 32-bits bytes (thanks T_Chap) of data,

    Mark_T has used these to stream audio. Here's a link to the post (#44 of this thread) where he attached the code. I believe he only posted the PASM portion of the code and didn't include an example of how to interface with it.

    As much as I love the Propeller, there may be other platforms with more mature drivers for doing what you want.

    It's been awhile since I've dealt with audio stuff but I really doubt there's an easy way to stream 96kHz audio.

    If you do try to use the Propeller to stream audio, I'm sure the code I posted is much too slow to do so (at least in its current form). Mark_T's code would be the code to try.

    Edit(3/7/20): Fixed link.
  • ItWillDoItWillDo Posts: 2
    edited 2013-12-03 - 14:05:49
    Well I'm not really using, nor planning to use, the Propeller to stream audio considering I also think it might cause some issues in the long run. I'll be using a MKL25Z128VLK4 . An ARM-based 32-bit MCU with a max speed of 48MHz. My main doubts lie in the throughput-capabilities of the NRF24L01+. I'll look into his code and see what I can find though!
  • T ChapT Chap Posts: 4,036
    edited 2013-12-03 - 14:18:01
    Duane meant to say a packet can include 32bytes, not bits.
Sign In or Register to comment.