Basic Micro/Orion Robotics RoboClaw library

Status
Not open for further replies.

KurtE

Senior Member+
I thought I would continue this on a new thread as to not pollute GeekGuys thread:
http://forum.pjrc.com/threads/25067-W-A-L-T-E-R-2-0-and-the-Teensy-3-1

Just thought I would give an update. I talked with Nathan at Orion Robotics and I am trying out a couple of approaches.

The easiest would be to hack on their BMSerial class which the Roboclaw library is derived from and either do minimal like he did to support Arduino Due and check for IO pins and redirect to their hardware serial code. The Bitbanging code plane wont work in it. Or as an extension of this could put the Teensy changes in SoftwareSerial into BMSerial, which is not a bad idea regardless.

Alternatively derive their class from the class Serial and pass in the actual serial object like Serial1 or a SoftwareSerial object, into the constructor. I personally like this approach as it removes the redundant code, like there is read with timeout support in the stream class. Plus if you have different hardware, like maybe one based on Atmega644p who has Serialx on different pins, no problem or maybe you have some other class derived from Stream you wish to try...

I have a version of the library that I have updated to use the stream approach that I am currently testing. So far I am testing out the query functions as this is where most of my changes are, to remove the redundant reading with timeouts. So far most of this working great. However I am having a problem with a Hang/crash when I use the variable number of arguments version of his read. Not sure if this is because I did something wrong, or the Variable number arguments code is having problems, or because for some reason this query function uses pass the argument by reference, where all of the other Query functions, do it by passing pointers...

That is, if I do:
Code:
  Serial.println("Enter Min/Max");
  fValid = RClaw.ReadMinMaxLogicVoltages(ADDRESS, uMinV, uMaxV);
  Serial.print("Min/Max: ");
  Serial.print(fValid, DEC);
  Serial.print(" ");
  Serial.print(uMinV, DEC);
  Serial.print(" ");
  Serial.println(uMaxV, DEC);
I get the prints entering the function, but not after. I did not touch the function The function RoboClawStream::ReadMinMaxLogicVoltages
Code:
bool RoboClawStream::ReadMinMaxLogicVoltages(uint8_t address,uint16_t &min,uint16_t &max){
	uint16_t value;
	bool valid = read_n(1,address,GETMINMAXLOGICVOLTAGES,&value);
	min=value>>16;
	max = value&0xFFFF;
	return valid;
}
However I Did update the read_n function:
Code:
bool RoboClawStream::read_n(uint8_t cnt,uint8_t address,uint8_t cmd,...)
{
    uint8_t data[6];
	uint8_t crc;
    uint8_t cbRead;

	write(address);
	crc=address;
	write(cmd);
	crc+=cmd;

    Serial.print("Enter read_n: ");
    Serial.print(cnt, DEC);
    
	//send data with crc
	va_list marker;
	va_start( marker, cmd );     /* Initialize variable arguments. */
	for(uint8_t index=0;index<cnt;index++){
		uint32_t *ptr = (uint32_t *)va_arg(marker, void *);
        Serial.print(" Loop ");
        cbRead = _pstream->readBytes(data, (index==(cnt-1))? 5 : 4);    // hack read checksum on last read
        Serial.print(cbRead, DEC);
        *ptr = ((uint32_t)data[0]<<24) | ((uint32_t)data[1]<<16) | ((uint32_t)data[2]<<8) | ((uint32_t)data[3]);
        crc += data[0] + data[1] + data[2] + data[3];
	}
	va_end( marker );              /* Reset variable arguments.      */
    Serial.println("Exit");
    // Assuming cnt is not zero last iteration should have read in the crc value

    // BugBug Could actually look to see if we read in data...
	return ((crc&0x7F)==data[4]);
}
As you see, I added prints to again see what was happening. I got the prints, I expected, including the "Exit" at the end, so I am suspecting the stack is being trashed...

Still investigating. If anyone wishes to look at the stuff. I did upload both the library and the test program up to Lynxmotion forum: http://www.lynxmotion.net/viewtopic.php?f=9&p=89534#p89534
 
Quick update: I recompiled it to run on Arduino Mega (1280). I needed to edit the library a little and add a few castings from byte* to char*...

It appears to not be hanging on the call I mentioned. So again thinking probably different on how variable parameters are handled...

Or maybe, I see something in the function calling it:
Code:
bool RoboClawStream::ReadMinMaxMainVoltages(uint8_t address,uint16_t &min,uint16_t &max){
	uint16_t value;
	bool valid = read_n(1,address,GETMINMAXMAINVOLTAGES,&value);
	min=value>>16;
	max = value&0xFFFF;
	return valid;
}
On the other side he is using value as 32 bit value, but here is 16 bit, that is also shifting 16 bits...
 
Last edited:
Thanks, yep - I think what you did may work for limited setup (i.e. only to Hardware Serial ports), which is a start. This is also what he did for the Arduino Due and this may be the approach that wins out. He actually thought maybe we should go the next step and put your changes for SoftwareSerial into his BMSerial code base, which is a good thing to do regardless as they have other hardware that uses SoftwareSerial in half duplex mode (1 pin), which I don't think is supported in the standard SoftwareSerial code base.

Thanks again
 
Question: suppose I wish to play with making the BMSerial code to work better. Obviously I can and should merge some of Teensy SoftwareSerial code into the BMSerial code. Personally I would like to remove the need for BMSerial, but that is different story. The one thing that some of their (Basic Micro / Orion Robotics) devices do is their own half duplex serial output/input code using one IO pin. It is easy enough for me to do on Hardware Serial ports as the processor has this built-in. I used this for my support of the AX servos.

But for some of their devices I hate to always have to use one of the HardwareSerial ports, so I thought I would use the SoftwareSerial support. But looking at the SoftwareSerial code base I see:
// TODO implement reception using pin change DMA capturing
// ARM_DWT_CYCCNT and the bitband mapped GPIO_PDIR register
// to a circular buffer (8 bytes per event... memory intensive)
So I was wondering is there some sample code showing how to do the equivalent of Pin change interrupts for the Teensy 3.x?

Thanks
Kurt
 
On that other thread, I posted this attempt to port BMserial and RoboClaw.

Not sure if that's the best way, but maybe it can help?
Thanks, I think the BMSerial changes may help some, at least it allows some stuff to be hooked up on Hardware Serial ports. Personally I like your version of the SoftwareSerial better than Nathans, for this as you simply check once at begin and save away a ptr to the Stream object and then if defined use it. Versus in his, it is always testing against the IO pins, in Read/Write/Avail...

I put a copy of your updated BMSerial code up on my Orion Github project as well as a copy of my RoboclawStream. While looking at BMSerial, I also made some changes to hopefully help it as well on ATMega32u4 based Arduino boards (Leonardo, ...), where IO pins 0,1 do not map to Serial, but instead Serial1
 
I am not sure how many people may be interested in this, but I did some more hacking on the Orion Robotics/Basic Micro libraries, to see if the Roboclaw will work with the standard roboclaw library (with the minor fixes and updates to BMSerial and Roboclaw). It does ;)

Then I wondered for the few of us who has one of their Playstation2 controllers, whose receiver uses a half duplex serial communication at 57600 (one 3 pin connector), instead of the normal PS2 which uses an SPI interface (minimum of 4 IO pins). Since there is no Bitbang Software Serial functions for the Teensy (or Due), I decided to hack on the BMPS2 library to detect when both RX/TX pins passed in are to one of the hardware serial ports TX pins. If so, I again redirect to the appropriate Hardware Serial Port and put it into half duplex mode. I also go and enable the PU resistor on the TX pin and then at the appropriate times, I set the direction on the TX pin. Did have to fix a few additional issues. The BMSerial object does the begin on the Serial port at c++ object constructor time frame, which I believe was hanging the teensy out to dry. I updated the code to only do the begin on the first read of the PS2. There was a casting issue in the analog method. That is suppose you have:
Code:
int foo() {
 unsigned char b = 0xff;
 return (char)b;
}
On an Arduino this would return -1. On the Teensy this returned 255. In fact it would not return any negative values. But if I changed the return to:
Code:
return (signed char)b;
Now it returns values like the Arduino.

To test the code out, I first have a simple PS2 test program that simply loops reading the values and printing them out. But also made a version of the simple rover that uses my version of Roboclaw, BMPS2 and BMserial and allows me to run the rover. In case anyone is interested in any of this, I have put all of this up in my Orion Github project (https://github.com/KurtE/Orion)
 
I am not sure how many people may be interested in this, but I did some more hacking on the Orion Robotics/Basic Micro libraries, to see if the Roboclaw will work with the standard roboclaw library (with the minor fixes and updates to BMSerial and Roboclaw). It does ;)
You're doing great work, Kurte! Thanks also goes to Nathan for helping out! :D I'm getting closer and closer to restarting my porting to the Teensy 3.1 now. I now have two robots (W.A.L.T.E.R. 2.0 and the SES Rover) that have RoboClaw 2x5 motor controllers and GHM-04 motors. I am very close to having both of them operational to some degree. :)

8-Dale
 
Status
Not open for further replies.
Back
Top