EV3 BCC / C software problem(s)

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: EV3 BCC / C software problem(s)

Post by afanofosc »

Quite some time ago I told doc to add "-lpthread" to the LDFLAGS line in the makefile template. If he doesn't have a line that starts with LDFLAGS then he has an old template and needs to click Default on that page - and be running the latest BricxCC test release.

If he were to look in the template he would see where LDFLAGS winds up being used further down in the template. It would show him that anything he puts into the LDFLAGS value would get passed into the linker. Alternatively, he could add -lpthread to the end of the line with %LINKOBJS% on it, separated by a space, just below the comment which says "how to link executable".

The most important thing for Doc to do is to google "makefile tutorial" or something similar and read a bit. I strongly suspect he would find tutorials on the web written in his native language even. But certainly he would find a lot that are very easy to read and follow. He could even try reading the PDF documentation that comes with the CodeSourcery Lite compiler. It is also easy to read and follow.

The "-l" switch for GCC says "link with the following library" and it is followed by the library name without "lib" and ".so", e.g., libpthread.so would be linked with by adding -lpthread to the compiler command line. If you need to link with a lot of libraries then you add each one, e.g., -lev3 -lpthread -lusb, would link with libev3.so, libpthread.so, and libusb.so.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 BCC / C software problem(s)

Post by HaWe »

I don't know what a "makefile template" is and I have no imagination of LDFLAGS or what this is all about the "link with..."
do you mean that edit field with

Code: Select all

PROGRAM=%PROGRAM%
DOBJECTS=%DOBJECTS%
TOOLPREFIX=%TOOLPREFIX%

all:: realclean $(DOBJECTS) $(PROGRAM)
should it look like this:

Code: Select all

 
PROGRAM=%PROGRAM%
DOBJECTS=%DOBJECTS%
TOOLPREFIX=%TOOLPREFIX%

all:: realclean $(DOBJECTS) $(PROGRAM)
-lpthread
 
?
this looks not very convincing...

The only fields with flags in it I could find is "GCC flags" "FPC flags" in edit/preferences/compiler, no idea if you mean this instead, and I actually expected something additionally like edit/preferences/makefile or edit/preferences/linker or edit/preferences/linkto in the IDE.
But I actually don't like to make a makefile tutorial or a gcc tutorial just in order to enable multithreading, I expect the IDE to do the important stuff automatically.
So I would appreciate one or the other screenshot how to do it.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 BCC / C software problem(s)

Post by HaWe »

edit,
new try:

I tried that with
LIBS=-lpthread

(thanks to Xander!)

in the big edit field with this code:

Code: Select all

// Multitasking-Demo:
// 3 Motoren an die Motorausgänge A,B,C anschließen !
// die Motoren werden automatisch angesteuert,
// die Encoderwerte werden simultan angezeigt!

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

#include "ev3_constants.h"
#include "ev3_command.h"
#include "ev3_button.h"
#include "ev3_timer.h"
#include "ev3_lcd.h"
#include "ev3_sound.h"
#include "ev3_output.h"

#define clreol  DRAW_OPT_CLEAR_EOL

void *DisplayValues(void *threadid) {
  while(true) {
    TextOut(0,56, "Enc.A:             "); NumOut(42,56, MotorRotationCount(OUT_A));
    TextOut(0,48, "Enc.B:             "); NumOut(42,48, MotorRotationCount(OUT_B));
    TextOut(0,40, "Enc.C:             "); NumOut(42,40, MotorRotationCount(OUT_C));
    Wait(40);
  }
  pthread_exit(0);
}


void *MotorControl(void *threadid) {
  int speed;

  while(true) {
    speed=Random(201) - 100; // ergibt eine Zufallszahl für die Motorleistung  zwischen -100 und +100
    OnFwd(OUT_A);

    speed=Random(201) - 100;
    OnFwd(OUT_B);

    speed=Random(201) - 100;
    OnFwd(OUT_C);

    Wait( 200+ (Random(2800)) ); // ergibt eine Zufallszahl für die Aktionsdauer von 200 - 3000 ms
  }
  pthread_exit(0);
}

main()  {
  pthread_t f2_thread, f1_thread;
  pthread_create(&f1_thread,NULL,MotorControl,NULL);
  pthread_create(&f2_thread,NULL,DisplayValues,NULL);
  pthread_join(f1_thread,NULL);
  pthread_join(f2_thread,NULL);
}

I get the error:
Errors found during compilation
...
[F12]
c:\Temp\ccO5orTW.o: In function `DisplayValues':
mt-demo.c:(.text+0x20): undefined reference to `TextOutEx'
mt-demo.c:(.text+0x28): undefined reference to `MotorRotationCount'
mt-demo.c:(.text+0x40): undefined reference to `NumOutEx'
mt-demo.c:(.text+0x54): undefined reference to `TextOutEx'
mt-demo.c:(.text+0x5c): undefined reference to `MotorRotationCount'
mt-demo.c:(.text+0x74): undefined reference to `NumOutEx'
mt-demo.c:(.text+0x88): undefined reference to `TextOutEx'
mt-demo.c:(.text+0x90): undefined reference to `MotorRotationCount'
mt-demo.c:(.text+0xa8): undefined reference to `NumOutEx'
mt-demo.c:(.text+0xb0): undefined reference to `Wait'
c:\Temp\ccO5orTW.o: In function `MotorControl':
mt-demo.c:(.text+0xd8): undefined reference to `Random'
mt-demo.c:(.text+0xf4): undefined reference to `OnFwdEx'
mt-demo.c:(.text+0xfc): undefined reference to `Random'
mt-demo.c:(.text+0x118): undefined reference to `OnFwdEx'
mt-demo.c:(.text+0x120): undefined reference to `Random'
mt-demo.c:(.text+0x13c): undefined reference to `OnFwdEx'
mt-demo.c:(.text+0x144): undefined reference to `Random'
mt-demo.c:(.text+0x154): undefined reference to `Wait'
c:\Temp\ccO5orTW.o: In function `main':
mt-demo.c:(.text+0x17c): undefined reference to `pthread_create'
mt-demo.c:(.text+0x194): undefined reference to `pthread_create'
mt-demo.c:(.text+0x1a4): undefined reference to `pthread_join'
mt-demo.c:(.text+0x1b4): undefined reference to `pthread_join'
collect2: ld returned 1 exit status
make: *** [mt-demo] Error 1
maybe it's a project file issue?

but that's too complicated to see through for me.
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: EV3 BCC / C software problem(s)

Post by afanofosc »

It is certain that if the edit window on the Compilers/EV3 tab that says "Makefile template" next to it does not contain the word "LDFLAGS" then you have an old template and you need to click the Default button on that tab, if you are running the very latest BricxCC test release. This will reset all compiler settings, including your NXC compiler settings, to their default values. If this concerns you then I recommend taking screenshots of the other tabs so you can change the values as needed.

People who don't know how BricxCC creates and uses a Makefile have given you bad suggestions. If you just listened to what I said for a change then everything would work just fine.

Step 1: Get a makefile template that mentions "LDFLAGS" by clicking the Default button.
Step 2: Add -lpthread to the end of the line that starts with LDFLAGS= with a space separating the - from whatever is in front of it.
Step 3: Read the readme_1st.txt and do what it says in step 30, i.e., create a Project file and add the necessary ev3_*.c files to it.
Step 4: As an alternative to step 3 add -lev3 to the end of the line that starts with LDFLAGS= and make sure that libev3.so is in the same folder as your source file.

Image

If you say "too many words" or "that's too hard for people to understand" then you will not see me ever trying to help you again.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 BCC / C software problem(s)

Post by HaWe »

thank you, by this screenshot I could understand it.

now this is my edit text window:

Code: Select all

PROGRAM=%PROGRAM%
DOBJECTS=%DOBJECTS%
TOOLPREFIX=%TOOLPREFIX%

all:: realclean $(DOBJECTS) $(PROGRAM)

download:: all

#pscp -scp -pw "%PW%" %PROGRAM% root@%IPADDR%:%FOLDER%

clean::
	rm -f *.o *.ppu *.rst

realclean:: clean
	rm -f $(PROGRAM)

FLAGS=%FLAGS%
LDFLAGS=-Wl,-R/media/card/lib -lpthread

CC=$(TOOLPREFIX)%CCNAME%

# how to link executable
%PROGRAM%: %MAINSRC%
	$(CC) $(FLAGS) $(LDFLAGS) $< -o$@ %LINKOBJS%

# how to compile source
%.o: %%EXT%
	$(CC) $(FLAGS) %LINKONLY% $< -o$@

the project manager contains everything of the pattern "ev3_*.c"
SetMotor is still of incorrect use (outcommented)
this is my current code:

Code: Select all

// mt-demo.c
// Multitasking-Demo:
// 3 Motoren an die Motorausgänge A,B,C anschließen !
// die Motoren werden automatisch angesteuert,
// die Encoderwerte werden simultan angezeigt!

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

#include "ev3_constants.h"
#include "ev3_command.h"
#include "ev3_button.h"
#include "ev3_timer.h"
#include "ev3_lcd.h"
#include "ev3_sound.h"
#include "ev3_output.h"

#define clreol  DRAW_OPT_CLEAR_EOL

void *DisplayValues(void *threadid) {
  while(true) {
    TextOut(0,56, "Enc.A:             "); NumOut(42,56, MotorRotationCount(OUT_A));
    TextOut(0,48, "Enc.B:             "); NumOut(42,48, MotorRotationCount(OUT_B));
    TextOut(0,40, "Enc.C:             "); NumOut(42,40, MotorRotationCount(OUT_C));
    Wait(40);
  }
  pthread_exit(0);
}


inline unsigned long Random(unsigned long x) {
   return (rand() % x);
}


void *MotorControl(void *threadid) {
  int speed;

  while(true) {
    speed=Random(201) - 100; // ergibt eine Zufallszahl für die Motorleistung  zwischen -100 und +100
    //SetMotor(OUT_A,speed);
    OnFwd(OUT_A);

    speed=Random(201) - 100;
    //SetMotor(OUT_B,speed);
    OnFwd(OUT_B);

    speed=Random(201) - 100;
    //SetMotor(OUT_C,speed);
    OnFwd(OUT_C);

    Wait( 200+ (Random(2800)) ); // ergibt eine Zufallszahl für die Aktionsdauer von 200 - 3000 ms
  }
  pthread_exit(0);
}

main()  {
  pthread_t f2_thread, f1_thread;
  pthread_create(&f1_thread,NULL,MotorControl,NULL);
  pthread_create(&f2_thread,NULL,DisplayValues,NULL);
  pthread_join(f1_thread,NULL);
  pthread_join(f2_thread,NULL);
}
no error by F5

but absolutely nothing happens when I press ctrl+F5 except there is this file shown on the ev3 screen:
mt-demo

if I try to start the file via BCC Explorer tool nothing happens neither (I observed that the EV3 hung up/ was blocked).

if I press the Center Button (because nothing happened instead) there is an ugly sound like "taaa-da" and the display shows:
/ ! \ error!

[OK]
Admittedly, the last thing was expected though.

The Lego Demo file runs fine anyway, so the EV3 brick is ok.
ps:
a little something unimportant but unlovely:
in the BCC editor "reserved words" are always shown in grey (clSrollbar or sth).
If I switch it to "Black" (Color>>>C++) at first it's shown black, but nevertheless at a new BCC start its back to clScrollbar-Grey again.
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: EV3 BCC / C software problem(s)

Post by afanofosc »

I was about to try your program myself but then I noticed you seem to have ignored my test programs.

Notice the first function call in the LCD test program. Notice the fourth function call in the Output test program. Also, can you tell me what on earth is this SetMotor function you are trying to call? If you look in the Output test program you will see how to set the power level of the outputs. Hint: it is the same as in the NQC API.

http://bricxcc.sourceforge.net/nqc/doc/NQC_Guide.pdf

All of the API functions are written to do nothing if the associated module has not yet been initialized. This could possibly be changed in the future.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 BCC / C software problem(s)

Post by HaWe »

of course I did, the LCD and sound test programs run fine (I already reported that some time before)
By outtest.c the motor is running but just 1 sec instead of 5 sec, even if I enlarge the seconds to wait to 20 sec:

Code: Select all

#include <stdio.h>
#include <unistd.h>

#include "ev3_output.h"
#include "ev3_timer.h"
#include "ev3_command.h"

int main()
{

  int i;

  printf("hello world\n");

  printf("start of out_test\n");
  Wait(SEC_1);

  // initialize
  if (!OutputInit())
    printf("output init returned false\n");

  ResetAllTachoCounts(OUT_ABCD);
  OutputSetTypes(DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO);


  RotateMotor(OUT_AB, 75, 360);  //works
  //RotateMotor(OUT_A,75, 360);  //crashes

  printf("Wait(SEC_20)\n");
  Wait(SEC_20);  // alternatively also tried:  Wait (20000)

  OutputClose();
  OutputExit();
  printf("end of out_test\n");

  return 0;
}
(I'm curious if I'm the only one who tried and then came upon this issue)

In my mt-demo.c I exchanged SetMotor by SetPower.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 BCC / C software problem(s)

Post by HaWe »

now I added

Code: Select all

int i;

  printf("hello world\n");

  printf("start of mt-demo\n");
  Wait(SEC_1);

  // initialize
  if (!OutputInit())
    printf("output init returned false\n");

  ResetAllTachoCounts(OUT_ABCD);
  OutputSetTypes(DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO);
  
at start of main().


EDIT:
the following was still missing:

Code: Select all

 OutputClose();
  OutputExit();
the code now looks like this:

Code: Select all

// mt-demo.c
// 0.3
// Multitasking-Demo:
// 3 Motoren an die Motorausgänge A,B,C anschließen !
// die Motoren werden automatisch angesteuert,
// die Encoderwerte werden simultan angezeigt!

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

#include "ev3_constants.h"
#include "ev3_command.h"
#include "ev3_button.h"
#include "ev3_timer.h"
#include "ev3_lcd.h"
#include "ev3_sound.h"
#include "ev3_output.h"

#define clreol  DRAW_OPT_CLEAR_EOL

void *DisplayValues(void *threadid) {
  while(true) {
    TextOut(0,56, "Enc.A:             "); NumOut(42,56, MotorRotationCount(OUT_A));
    TextOut(0,48, "Enc.B:             "); NumOut(42,48, MotorRotationCount(OUT_B));
    TextOut(0,40, "Enc.C:             "); NumOut(42,40, MotorRotationCount(OUT_C));
    Wait(40);
  }
  pthread_exit(0);
}


inline unsigned long Random(unsigned long x) {
   return (rand() % x);
}


void *MotorControl(void *threadid) {
  int speed;

  while(true) {
    speed=Random(201) - 100; // ergibt eine Zufallszahl für die Motorleistung  zwischen -100 und +100
    SetPower(OUT_A,speed);
    OnFwd(OUT_A);

    speed=Random(201) - 100;
    SetPower(OUT_B,speed);
    OnFwd(OUT_B);

    speed=Random(201) - 100;
    SetPower(OUT_C,speed);
    OnFwd(OUT_C);

    Wait( 200+ (Random(2800)) ); // ergibt eine Zufallszahl für die Aktionsdauer von 200 - 3000 ms
  }
  pthread_exit(0);
}

main()  {

  int i;

  printf("hello world\n");

  printf("start of mt-demo\n");
  Wait(SEC_1);

  // initialize
  if (!OutputInit())
    printf("output init returned false\n");

  ResetAllTachoCounts(OUT_ABCD);
  OutputSetTypes(DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO, DEVICE_TYPE_TACHO);
  

  pthread_t f2_thread, f1_thread;
  pthread_create(&f1_thread,NULL,MotorControl,NULL);
  pthread_create(&f2_thread,NULL,DisplayValues,NULL);
  pthread_join(f1_thread,NULL);
  pthread_join(f2_thread,NULL);

  OutputClose();
  OutputExit();
}
result:

motors start driving, but constantly / continuously, no change in direction, program hangs up, blocks, batteries need to be removed.

If possible, please modify the whole code so that it is able to work as expected, I then will try to transform the changes to other programs in future.
Thanks in advance!
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: EV3 BCC / C software problem(s)

Post by afanofosc »

Doc,

You know your program can't ever end since the two threads go on forever, right? That means the VM will look like it is hung since it is waiting for your program to quit running.

Why did you add anything other than the OutputInit call and why did you leave out the required LCDInit call? One of your threads is trying to draw on the LCD which it cannot do if you have not initialized the LCD module.

It would help if you try the out_test_c.c that comes with the API zip and not a version I do not recognize even slightly. In the code you posted it never ever tries to rotate any motors for 5 seconds. And RotateMotor waits until the rotation has completed so it has finished and stopped the motors before execution goes on to the Wait statement. Why are you calling OutputSetTypes? You can see that I do not call that function at all in my sample test programs.

If you think that calling OnFwd with a negative power should reverse the motor I think you might be mistaken (though I could be wrong). What does the NQC API say OnFwd does? "Set outputs to forward direction and turn them on". If you don't want to confuse the the EV3 by toggling the direction via OnFwd and OnRev and you want the power level to be the only factor that influences direction then I would recommend using On instead of OnFwd or OnRev. The latter two functions adjust the polarity on the outputs which, in my testing, did not seem to work reliably in the firmware, but it is possible I am not using it correctly. My point being that you should stick to either positive power levels and direction/polarity toggling OR you should use positive and negative power levels and leave the direction toggling alone but don't mix the two things together.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: EV3 BCC / C software problem(s)

Post by HaWe »

I'm actually not quite sure what you mean which function is probably safe or not safe for BCC/C.

So 1 question before I'll change my code:

In NXC OnFwd(outputs, pwr) is fine for positive and/or negative pwr values, I use it successfully for my multithreaded PID position control.

So provided that I need a BCC/C function which switchs a motor forward or reverse depending on the signum of the pwr value -

do you think that On() is safe for positive and negative values in BCC/C ?
or do you think sth like the following will be more safe ?

Code: Select all

inline void Motor(int outputs, int pwr) {
  int buf=pwr;
  pwr=abs(pwr);
  SetPower(outputs, pwr);
  if(buf>=0) {OnFwd(outputs);} 
  else {OnRev(outputs);}
}
it's admittedly a little complex but should work (CMIIW).
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest