Cannot compile with Orangutan Libraries (328p)

Hello, I have been attempting to compile a simple program to drive motors forward using the Baby Orangutan 328p and the pololu c++ libraries.

I have gotten it to build using set_motors(50, 50); but I’d really like to get the C++ libraries working.

My environment is Windows 7 (64 bit) using AvrStudio4.

I have verified that all files have installed correctly, and have pictures of my build environment and error here: http://imgur.com/a/Q1M4X
[size=85](I figured a screenshot would explain things better than me.)[/size]

It seems like it’s looking for OrangutanTime for some reason although I do not use it. I’ve tried including OrangutanTime.h and it hasn’t helped.

Also, not included in the screen shot, is the contents of the pololu folder, so I’ve posted it here:

C:\WinAVR-20100110\avr\include\pololu>ls
3pi.h                   OrangutanResources     analog.h
OrangutanAnalog         OrangutanResources.h   buzzer.h
OrangutanAnalog.h       OrangutanSPIMaster     digital.h
OrangutanBuzzer         OrangutanSVP           encoders.h
OrangutanBuzzer.h       OrangutanSerial        lcd.h
OrangutanDigital        OrangutanSerial.h      leds.h
OrangutanDigital.h      OrangutanServos        motors.h
OrangutanLCD            OrangutanServos.h      orangutan
OrangutanLCD.h          OrangutanTime          orangutan.h
OrangutanLEDs           OrangutanTime.h        pulsein.h
OrangutanLEDs.h         OrangutanX2            pushbuttons.h
OrangutanMotors         Pololu3pi              qtr.h
OrangutanMotors.h       Pololu3pi.h            resources.h
OrangutanPulseIn        PololuQTRSensors       serial.h
OrangutanPulseIn.h      PololuQTRSensors.h     servos.h
OrangutanPushbuttons    PololuWheelEncoders    time.h
OrangutanPushbuttons.h  PololuWheelEncoders.h

I’ve read through the documentation, browsed the forum a bit, and spent hours trying to get this to work already.

If anyone has any idea what I am doing wrong, please tell me!

Could you copy and paste the build output from AVR Studio here? Your screenshot does not allow us to see the entire error message on the longer lines. --David

My appoligies, I was forgetting the output wasn’t line wrapping. Here is my entire build/error message:

Build started 8.4.2011 at 06:36:43
avr-g++ -I"C:\Users\PageFault\Documents\..\..\..\WinAVR-20100110\avr\include" -I"C:\Users\PageFault\Documents\..\..\..\WinAVR-20100110\avr\include\pololu" -I"C:\Users\James Ihrig\Documents\..\..\..\WinAVR-20100110\avr\include\pololu\OrangutanTime"  -mm
cu=atmega328p -Wall  -gdwarf-2  -Os  -funsigned-bitfields  -fpack-struct -MD -MP -MT LineFollowingBot.o -MF dep/LineFollowingBot.o.d  -c  ../LineFollowingBot.cpp

In file included from C:\Users\PageFault\Documents\..\..\..\WinAVR-20100110\avr\include/pololu/orangutan.h:5,
                 from ../LineFollowingBot.cpp:1:
C:\Users\PageFault\Documents\..\..\..\WinAVR-20100110\avr\include/pololu/lcd.h:32: warning: '__progmem__' attribute ignored
In file included from C:\Users\PageFault\Documents\..\..\..\WinAVR-20100110\avr\include/pololu/pulsein.h:1,
                 from C:\Users\PageFault\Documents\..\..\..\WinAVR-20100110\avr\include/pololu/orangutan.h:13,
                 from ../LineFollowingBot.cpp:1:
C:\Users\PageFault\Documents\..\..\..\WinAVR-20100110\avr\include/pololu/OrangutanPulseIn/OrangutanPulseIn.h: In static member function 'static long unsigned int OrangutanPulseIn::toMicroseconds(long unsigned int)':
C:\Users\PageFault\Documents\..\..\..\WinAVR-20100110\avr\include/pololu/OrangutanPulseIn/OrangutanPulseIn.h:103: error: 'OrangutanTime' has not been declared
../LineFollowingBot.cpp: In function 'int main()':
../LineFollowingBot.cpp:8: error: 'OrangutanMotors' was not declared in this scope
../LineFollowingBot.cpp:9: error: expected `;' before 'motors'
../LineFollowingBot.cpp:12: error: 'motors' was not declared in this scope
make: *** [LineFollowingBot.o] Error 1
Build failed with 4 errors and 1 warnings...

Also, I realized it may be a good idea to paste my code here in case you needed to copy/paste any of it.

#include <pololu/orangutan.h>
#include <pololu/OrangutanMotors/OrangutanMotors.h>

int main()
{
	bool
		programRunning = true;
	OrangutanMotors
		motors;
	while (programRunning)
	{
		motors.setMotors(50,50);
	}
	return 0;
}

I think that should cover everything, but please let me know if there are any other important details that I have left out.

Edit: Just noticed that I have two OranutanMotors.h’s. I’ve tried including this instead of the one in its own directory:

#include <pololu/OrangutanMotors.h>

However, I get the same exact error message.

Hello.

Unfortunately, it turns out that pololu/time.h (the C version) is not compatible with pololu/OrangutanTime/OrangutanTime.h (the C++ version). Please try replacing all of your include statements with the following line, which only uses the C++ versions of the header files:

#include <pololu/orangutan>  // note there is no .h extension!

–David

Thank you for the response!

Alright, I’ve now done that but it then gave an error about “OrangutanX2.h” not existing. I checked, and sure enough it wasn’t there. So I opened to the “orangutan” C++ header, commented out the include line for that header file, recompiled and it built fine.

(Was that left out of the latest library?)

So I went on to use OrangutanDigital and OrangutanAnalog and realized I could use some debug info, so I looked into OrangutanSerial, but for some reason I’m getting an undefined reference to `OrangutanSerial::OrangutanSerial()’.

Here’s sample code that reproduces the problem on my machine:

#include <pololu/orangutan>
OrangutanMotors  motors;
OrangutanDigital muxSelector;
OrangutanAnalog  analogInput;
OrangutanSerial  serialDebug;
int main()
{
	bool
		programRunning = true;
	while (programRunning)
	{
		//Do nothing
	}
	return 0;
}

Here’s the error it threw at me:

Build started 8.4.2011 at 13:14:03
avr-g++ -I"C:\Users\PageFault\Documents\New folder\..\..\..\WinAVR-20100110\avr\include" -I"C:\Users\PageFault\Documents\New folder\..\..\..\WinAVR-20100110\avr\include\pololu" -I"C:\Users\PageFault\Documents\New folder\..\..\..\WinAVR-20100110\avr\i
nclude\pololu\OrangutanTime"  -mmcu=atmega328p -Wall  -gdwarf-2  -Os  -funsigned-bitfields  -fpack-struct -MD -MP -MT LineFollowingBot.o -MF dep/LineFollowingBot.o.d  -c  ../LineFollowingBot.cpp

avr-g++ -mmcu=atmega328p -Wl,-Map=LineFollowingBot.map LineFollowingBot.o    -lpololu_atmega328p  -o LineFollowingBot.elf
LineFollowingBot.o: In function `__static_initialization_and_destruction_0':
C:\Users\PageFault\Documents\New folder\default/../LineFollowingBot.cpp:5: undefined reference to `OrangutanSerial::OrangutanSerial()'
make: *** [LineFollowingBot.elf] Error 1
Build failed with 1 errors and 0 warnings...

Is there something else I’m missing? Any suggestions will be greatly appreciated!

Hello, PageFault.

OrangutanX2.h is included in the library, but unfortunately there was a typo in the #include statement in pololu/orangutan that included it. You don’t have an Orangutan X2 so commenting out that line of code is fine.

With regards to the second problem, we forgot to define a constructor for the OrangutanSerial library. All of the OrangutanSerial functions are static, so what I would do is call them using this syntax:

OrangutanSerial::setBaudRate(9600);

But if you like having an object for it, you can do that too. You’ll just have to define your own constructor. That’s easy, because the constructor shouldn’t do anything. Just add the following line in to your code, somewhere below the #include statement.

OrangutanSerial::OrangutanSerial(){}

Sorry for the inconvenience!

By the way, the structure of your main() function can lead to problems. You should never return from main() in an avr-gcc program because the results are unpredictable. If you want your program to stop running, you can write a little function like this and call it:

__attribute__((noreturn)) void stopProgram()
{
    cli(); // Stop interrupts
    // (...turn off motors and other peripherals...)
    while(1){}    // Loop forever.
}

–David

David,

Thank you for your help, I have successfully been able to compile a program with your C++ libraries, drive a motor, and send out serial data which will be useful for debugging. (For some reason, I initially thought serial came through the programmer wire, but I just hooked the tx pin to the rx pin of another micro-controller that does.)

As for the concern about returning from main, the variable was simply because I hate while(1)'s, even if the condition is never set to false, it makes me feel better to have a condition there. (Just an oddity on my end…) I was actually planning on having a second loop that just endlessly printed to the serial line once the main task of the robot quit. The concern was valid in general though, and is much appreciated!

It seems that most of my problems should be hardware related from here out. (Sensors, etc… I’m not an electrical guy!)

Thanks for your help!
Jim

I’ve built a program that uses OrangutanTime::ms(), but I need to track smaller time increments. So I tried using OrangutanTime::us() but I’m getting the error:

Seems rather odd that I can use one function in the same file but not the other. Is there some restriction in there somewhere somehow that I can’t get a time increment that small on the Baby Orangutan?

If so, it’s going to make creating the D term of my PID controller near impossible it seems since the difference in time between loops is always equating to zero. (I assume you guys know PID controllers… The code is irrelevant to my problem, but I’ll share it anyway in case it’s useful to anyone… It works well so far with 50:1 motors.)

//Decide what to do.
int think()
{
	static const int
		P = 35, //Perportional
		I = 0,  //Integral
		D = 0;  //Derivative
	static int
		sumError = 0,
		oldError = 0;
	int
		actual   = 0,
		desired  = 0,
		error    = 0,
		dError   = 0;
	static unsigned long
		lastFrameTime = OrangutanTime::ms();
	
	//Calculate Error ... one sensor on strip is bad... So, read middle 6 for now... 
	for (unsigned char i = 1; i < 7; i++)
	{
		if (i < 4)
		{
			if (lineSensor[i] > 400)
			{
				actual -= 2 * (4 - i);
			}
		}
		else
		{
			if (lineSensor[i] > 400)
			{
				actual += 2 * (i - 3);
			}
		}
	}

	//The P multiplicand
	error = desired - actual;

	//The D multiplicand
	dError = (error - oldError) / (OrangutanTime::ms() - lastFrameTime);
	
	char
		message[256];
	memset(message, 0, 256);
	sprintf (message, "deltaT = %d\r\n", dError);
	OrangutanSerial::sendBlocking(message, OrangutanTime::ms() - lastFrameTime); //Prints "deltaT = 0"

	//The I multiplicand
	sumError += error * (OrangutanTime::ms() - lastFrameTime);

	//Set old error to current
	oldError = error;

	lastFrameTime = OrangutanTime::ms();

	//Return desired turn rate
	return P * error + I * sumError + D * dError;
}

We do declare OrangutanTime::us() in the OrangutanTime.h, but that is a mistake. There is no us() function in the OrangutanTime.cpp file and no us() function is documented here:
pololu.com/docs/0J18/17

You can use OrangutanTime::ticksToMicroseconds(OrangutanTime::ticks()) instead.

But beware that if you use this method, you will get a bad result every 28 minutes when ticks() overflows from 2^32-1 to 0. If I were you, I would just do all of my time calculations in ticks using OrangutanTime::ticks() and forget about microseconds. If you do it this way, your subtraction will overflow every 28 minutes but it will be ok. See the command reference documentation of ticks() for details.

For Orangutan-based PID control, we usually don’t actually calculate the time difference; we just multiply by some scale factor and tweak the factor until we get good results. This relies on the assumption that our main loop will take approximately the same time each iteration. If the main loop had to do lots of other tasks that take variable amounts of CPU time then we would have to do something more complex. You can look at one of the 3pi PID examples in the AVR library to see what I’m talking about.

By the way, the second argument to sendBlocking should be the size of the message you want to send; it should definitely not be a difference in time. When I write Orangutan code I constantly refer to the library’s command reference to avoid mistakes like that. You should use the return value of sprintf to find out how long the message is and use that as the second argument to sendBlocking. After you make those changes, you should not need to use memset in the program because sprintf will append a null termination character. Also, beware that sprintf could possibly be a lot slower than the other computations you are doing.

–David

Wow, I’m surprised you got back to me tonight! I just thought of something that I might change to help with my time being zero problem and meant to add an edit to try initializing my lastFrameTime to a constant rather than a function call… (I’ll try that tomorrow) and was surprised to see a response already.

Yes, this sounds like it might be better for me since it should be finer resolution, and should still be just some measure of time.

This is just to help keep things slightly more consistent to when I comment serial in and out between runs or and and change code as I go. I plan on trying to get the orangutan to learn the best values for P,I and D, so as the memory fills with different combinations it stores, it may slow as it goes. I think that compensating for a difference in time is a complex as it needs to be. (I hope)

Yes, I knew that… That was a mistake… which I over looked… (copy paste error when changing message at some point) the message code was meant to look like this:

   char
      message[256];
   memset(message, 0, 256);
   sprintf (message, "deltaT = %d\r\n", OrangutanTime::ms() - lastFrameTime); //Not dError!! 
   OrangutanSerial::sendBlocking(message, strlen(message)); //Prints "deltaT = 0"

So that could have also been the reason my time difference seemed incorrect… I’m thinking with the serial output my time should have definitely been more than 0… But now I see that the print code was messed up I’ll need to look again.

sprintf’s return value should be just as good as strlen() I imagine… Well, maybe better since it’s one less function call I have to make… and yea, using memset() may just be me being overly cautious. All of the serial printing that happens during runs will be removed once I’m done debugging values… Anytime I use serial, the response time of my robot is way slower… maybe it is due to the sprintf and not just the blocking serial command… Either way, it should be removed in the end.

Thanks again!