Stackable? Daisy chaining? dev tree compatible to Jessie? [C/C++]

I’m working on a lot of firmware improvements, and once I finish that and update the Python drivers to take advantage of the changes, I plan to start working on the C/C++ drivers. Since you’re willing to do some debugging and deal with problems in the early stages, I should be able to give you access to the drivers prior to them being polished for release.

Indeed I know you like perfection. I won’t guarantee it, but if you’re available to test and provide feedback, it’s likely to be better suited to your needs. I’ll email you when I have something ready for you to test.

1 Like

That’s great news, thank you for your kindness and obligingness! :smiley:
I’m gladly looking forward to it; I’ll stay tuned! :sunglasses:

@HaWe Here my perspective on C/C++. I was playing with computers as a kids writing programs. Computers were super slow and many languages had very limited functionality, it was common that programs had to be written in C/C++ just to get the speed. I then didn’t turn on a computer for more than 25yrs as I discovered girls and drugs but have just recently engaged in computers for the purpose of teaching my kids what I now consider very important life skills for the world they will live in. What I discovered is that programming has very much changed, computers are now super fast and most ;languages have become very powerful with lots of functionality, the other thing that I discovered was this open source sharing code concept. The increase in speed of computers and the increase in power of languages means it is now not as necessary to use a super low level language like C/C++ also being able to make use of open source code is now a super important part of coding, no one sits down and writes every line of their own program but more uses open source moduals and just writes the little bits in between. So using a language that has lots of open source code and API is a very important part of coding, it seems like Java and Python win for most amount open source code out there. One of my students that I teach to paragliding is in senior management in a software company here is Australia but did live in silicon valley for over 20yrs working as a programmer for Microsoft. He advised me not to worry about teaching my kids to program in C/C++ as it is now rarely used professionally, he said out of all the programmers he knows only 2 of his friends use C/C++ professionally, one still works for Microsoft writing compilers and the other works for a military contractor writing missile guidance code. C/C++ has become a small niche language.

@shane:
you wouldn’t ever convince me. I 'll stay with C or even with C++ because of multiple reasons, I will never change that. C is exactly what I need, it’s the way my brain works itself, it’s direct and straight, it’s extremely powerful, and it’s insanely fast, just as asm.
Python instead is a nightmare. to me, if I see that “coding” I feel like I have to vomite, honestly. Discussion futile :dizzy_face:
Nonetheless, C is capable of building both handsome and still powerful wappers for high-level APIs, and that’e exactly what will be required for the BrickPi. Matt knows what I am talking about :wink:

1 Like

@Matt:
I just duscovered that SPI on BrickPi3 is just at 500Kbs - is that true?
IIRC, the Pi can provide SPI speed at 32Mbs, and AVR and ARM Cortex (SAM, SAMD) are providing SPI at up to cpu clock (16MHz vor Atmega, 32-48Mhz ARM Cortex M0, 84MHz ARM Cortex M3). Also on my Arduino Due (M3) I am running SPI at 84 MHz (SPI clock divider = 1).
So I assume the SAMD on-board the BrickPi3 is also supposed to work at at least 32 Mhz SPI clock, too.

Especially when running different additional SPI shields and HATs a faster SPI clock speed would be very helpful, don’t you agree?

It is true. The SAMD could clock in data much faster, but it does most of the data processing as it’s receiving data from the RPi. To increase the speed too much, there is a risk that the data will be coming in faster than it can be processed (or attempting to be clocked out faster than it can be processed). I have done some testing with higher speeds, and 750kbps seems at least some-what reliable (only minimally tested), but 1mHz fails. 500kbps is still very fast. I just tested the example program EV3-Color_Sensor_Color.py, and if I take out the delay, at 500kbps it loops about 4150 times per second, and at 750kbps it only increases to about 4270 (less than a 3% difference). Note that the EV3 color sensor (and other sensors) won’t actually update anywhere near that fast. The BalanceBot program is configured to run at 120 Hz (120 loops per second), but it is capable of running well over 200 (I forget how fast, but I remember it was at least 200 when I tested it), and it’s reading two sensors, two encoders, and controlling two motors (plus doing a lot of math).

As it is, each command/read is done with a single SPI transfer. An alternative would be to have two messages for reads; one that tells the BrickPi3 what values are needed, and then another to retrieve the values once they are ready. This could work, but I don’t think it would save time, and I know it would make it more complex. Another alternative would be to bit-bang the master SPI on the RPi, and use a hand-shake line that the BrickPi3 toggles between each byte (probably not much of an advantage there either).

Even though there is potential that the communication speed could be increased slightly, I can’t think of a scenario that a BrickPi3 project would need more than 4000 reads/writes per second.

I agree, and for common sensors I assume 1x /ms is more than enough.
Even though, for reading lots of rotary encoders simultaneously
(4 motors x 4 HATs =16 motors , x2 =32 pin states),
I assumed SPI clock could perhaps make a difference.
Or don’t you process all the encoder values on the Pi , but instead on the SAMD remotely / outsourced (e.g., even for PID control) ?
I’m just asking because I’m curious, you surely will have performed lots of tests by which you already have confirmed this performance.

The EV3 medium motor runs at 260 RPM (no-load at 9v, according to Philo’s motor tests), which would be 1560 encoder line changes per second (on each of the two signals). Multiply that by 4 motors, and that’s up to about 6240 changes per second that need to be serviced.

The BrickPi3 SAMD firmware handles all this using interrupts, and the encoder pin states are not accessible from the RPi (just the running total encoder position, maintained by the firmware). Likewise the I2C, UART, and other communication with sensors is being managed by the firmware so that the RPi doesn’t need to deal with it.

The BrickPi3 SAMD does handle motor control algorithms (such as for motor position control) so that the user program doesn’t need to deal with it. However, access to the encoders and the motor PWM power is available to the user program, so custom algorithms can be implemented if necessary (such as for the BalanceBot).

ok, thank you, that was exactly what I was interested in!

just to mention, for stacking multiple BrickPi3 HATs there should be a way to mount them just by 4x 2.5" brass spaces like those ones
http://www.ebay.de/itm/50-Stuck-Nylon-Sechskant-Bolzen-Distanzbolzen-Abstandshalter-F-M-M2-5x20-6mm-/351955386402?hash=item51f22d0022:g:ZwIAAOSwol5Yy6Sk
without any acrylic case at all.

I think you would want to use more like 17mm or 18mm tall (rather than 20mm), but those should work.

perfect, the future may begin! :sunglasses:

@Matt
So if I am understanding what your saying above is that all the calculations needed for the motor control are on BrickPi3 board and not by the RPi meaning it doesn’t bog down the RPi? And that the RPi can communicate with the brickPi3 at 4000 times per second? Does this mean that when I run the line of code to update motor speed in my program that line of code will only take 1/4000 of a second to execute before moving onto the next line of code in my program?

I may answer for matt, because I know those architectures already for my proprietary Arduino IO Muxers to my Pis (AVR and ARM Cortex M3):
Yes, if IO control for sensors and motors and especially motor PID is performed on the HATs, it does not affect the Pi then at all, just data transmission by the SPI asynchronous communication protocol needs cpu power - which is actually just 1 single thread of not a compellingly high priority for just a single core. Linux maintains that automatically for the 4 ARM7 or ARM53 cores.
And because Linux itself is written in C, it’s highly effective and insanely quick, even when it’s just performed in the Linux user space. :sunglasses:

Nonetheless, Python is comparingly extremely slow, and Python is interpreted also just in the Linux user soace, so the timing of Python is not predictable.

If the program on the Pi wouldrun by a native Linux executable (e.g., by a compiled C program) by high-priority threads (e.g., POSIX pthread), then indeed that would be feasable. In my C programs I am reading 8 rotary encoders provided by Arduino Due in real-time in 100µs loops (optionally even in 1-10µs timers, but there is no need so far for me to do that):
So to me Encoder reading and processing is possible in real-time (quicker than 10 thousand times each sec is possible, GPIO reading even in 130ns each), without issues.
But that’s C, not Python.

1 Like

Is this the difference between BrickPi+ and BrickPi3?
BrickPi+ the RPi maintained the motor processing and BrickPi3 it is all done on the Hat?

now that question is off-topic, because the BrickPi+ is probably not SPI but UART, and UART devices are not stackable.

(BTW, I meanwhile edited my post above, just FYI)

@Shane.gingell indeed motor control calculations are done on the BrickPi3 so that the RPi doesn’t need to run the algorithms. However, for some applications it will be necessary to implement on the RPi in user code (a great example is the BalanceBot) for the sake of flexibility (some projects require unique motor control algorithms). As far as the RPi communicating with the BrickPi3 at 4000 times per second, yes, that seems to be a rough average for most messages (1/4000 of a second), so yes, it would only take about 1/4ms to execute that line of code.

There are many differences between the BrickPi+ and BrickPi3, some of which include firmware motor control, significantly faster communication, better support for EV3 sensors (the original BrickPi was designed before EV3 was released), and the ability to update the firmware by simply running a command on the RPi (or from DI Update, on the Raspbian for Robots OS).

@HaWe the biggest speed limiting factor is SPI communication speed (very fast, so hardly a limit), not Python execution speed. Python is very fast. On any system that is not real-time (e.g. Raspbian, and at least a majority of Linux), timing is not predictable even for programs written in C. On such systems, at any time, the OS can pause executing the program to give a time slice to a different process. I think the only real runtime advantage of C over Python would be in situations where an enormous amount of data needs to be processed quickly (very intense algorithms).

From a hardware/electrical perspective, the BrickPi+ actually could/can be stacked, but since the drivers don’t support it, it was never advertised.

Matt, if you’ll port that program to Python,
which values will you get for GPIO reading on a Pi2?


/*     Program GPIO speed test
 *     Raspberry Pi 2
 *     ver   002     
 *
 */




#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <sys/time.h>
#include <errno.h>
#include <pthread.h>

#include <wiringPi.h>
#include <wiringSerial.h>
#include <wiringPiI2C.h>
#include <softPwm.h>

// tasks


unsigned long itime0, itime1, xtime0, xtime1;
int s0=1, s1=1;
int counts = 100000;

void* thread0 (void* ) {       // 
   volatile int ival;
   
   itime0=millis();
    for (int i=0; i<counts; i++) {
       ival=digitalRead(5);
       digitalWrite(20, HIGH);
       ival=digitalRead(5);
       digitalWrite(20, LOW);
    }   
    xtime0=millis();
    s0=0;
    return NULL;
}


void* thread1 (void* ) {       // 
   volatile int ival;
   
   itime1=millis();
                                 // optionally outcomment or uncomment the for() loop 
                                 //  for multithreding test!
    
   for (int i=0; i<counts; i++) {
       ival=digitalRead(6);
       digitalWrite(21, HIGH);
       ival=digitalRead(6);
       digitalWrite(21, LOW);
    }   
    

    xtime1=millis();
    s1=0;
    return NULL;
}


//
void setupwiringPi() {
 
    int iores;
    putenv ("WIRINGPI_GPIOMEM=1");                 // no sudo for gpios required
    iores = wiringPiSetupGpio();                   // init by BCM pin numbering
    if( iores == -1 ) exit(1);     
   
    pinMode(  5, INPUT); pullUpDnControl( 5, PUD_UP);
    pinMode(  6, INPUT); pullUpDnControl( 6, PUD_UP);
     
    pinMode( 20, OUTPUT); 
    pinMode( 21, OUTPUT); 
   
   
   
}





// main


int main() {
    int key;
    unsigned long t=0, t0, t1;
    double ns0, ns1;
   
    sleep(1);
   
    setupwiringPi();     
   
    pthread_t tid0, tid1;
    struct  sched_param  param;

    pthread_create(&tid0, NULL, thread0, NULL);    // 
     param.sched_priority = 80;
     pthread_setschedparam(tid0, SCHED_RR, &param);
   
    pthread_create(&tid1, NULL, thread1, NULL);    // 
     param.sched_priority = 20;
     pthread_setschedparam(tid1, SCHED_RR, &param); // edited
   
    while(s0 || s1) {
      printf("%ld\n", t);
      delay(100);
      t+=100;      
   };
   
     
    // wait for threads to join before exiting
    pthread_join( tid0, NULL);
    pthread_join( tid1, NULL);
   
    printf("\n\n");
    t0=xtime0-itime0;
    t1=xtime1-itime1;
   
    ns0=t0*1000000/(float)(4*counts);
    ns1=t1*1000000/(float)(4*counts);
   
    printf("time thread0: %ld ms,   time thread1: %ld ms\n", t0, t1);
    printf("time delta0:  %.1f ns,  time delta1:  %.1f ns\n", ns0, ns1);
   
   
    key=getchar();

   
    exit(0);
}


I’m not sure what you mean. Can you re-phrase the question?

Are you asking how fast python can toggle a GPIO? I’m not sure, but I can test.