It all started with wanting to use a Kinect or other RGBD (Depth sensing) camera to do navigation... Things ended up slowly but surely with moving from a BeagleBone Black and custom nodejs script that I created as the heart to a quad core atom running ROS and many ROS nodes that I created ;)
The main gain to ROS is the nodes that other people have written. If you want to convert RGBD to a simulated laser scan in order to do 2d navigation then that's already available. If you want to make a map and then use it then that code is already there for you. And the visualization for these things. I'm not sure I'd have the time to write from scratch a 3d robot viewer and visualize my cut down 'fake' 2d laser scan data from the Kinect in OpenGL. But with ROS I got the joy of seeing the scan change in real time as Terry sensed me move in front of it.
I now have 3d control of the robot arm happening, including optional sinusoidal encoding of movements. The fun part is that the use of sinusoidal can be enabled or disabled without any code changes. I wrote that part as a JointTrajectory shim. For something to use smoother movement all it has to do is publish to that shim instead of directly to the servo controller itself. The publish and subscribe parts of the IPC that ROS has are very easy to get used to and allow breaking up the functionality into rather small pieces if desired.
The arm is one area that is ROS controlled, but not quite the way I want. It seems that using MoveIt is indicated for arm control but I didn't manage to get that to work as yet. The wizard only produced an arm that would articulate on one joint, so more tinkering is needed in that area. Instead I wrote my own ROS node to control the arm. It's all fairly basic trig to get the gripper at an x,y,z relative to the base of the arm. And an easy carry over to fix the gripper at a horizontal to the base no matter what position the arm is moved to. But in the future the option to MoveIt will be considered, can't hurt to have two codepaths to choose from for arm control.
As part of the refresh I updated the pan unit for the camera platform.Previously I used a solid 1/4 inch shaft with the load taken by a bearing and the gearmotor turning the shaft directly from below it. Unfortunately that setup has many drawbacks; no ability to use a slip ring, no torque multiplication, difficulty using an axle end rotary encoder IC to gain real world position feedback. The updated setup uses a 6 rpm gearmotor offset with a variable motor mount to drive a 24 tooth brass gear. That mates with an 80 tooth gear which is affixed to a hollow 1/2 inch alloy tube. As you can see at the top of the image, I've fed the tilt servo cable directly into the inside of that tube. No slip ring right now, but it is all set to allow the USB cable to slip through to the base and enable continuous rotation of the pan subsystem. So the Kinect becomes a radar style. One interesting aside is that you can no longer manually rotate the pan system because the gearmotor, even unpowered, will stop you. The grub screw will slip before the axle turns.
As shown below, the gearmotor is driven by an Arduino which is itself connected to a SparkFun breakout of the TB6612FNG HBridge IC. This combo is attached using double sided 3M tape to a flat bit of channel. Then the flat bit of channel is bolted to Terry. I've used this style a few times now and quite like it. A single unit and all it's wires can be attached and moved fairly quickly.
At first I thought the Arudino gearmotor control and the Web interface would be a bit outside the bounds of ROS. But there is an API for Arduino which gives the nice publish and subscribe with messages that one would expect on the main ROS platform. A little bit of python glue takes the ttyUSB right out of your view and you are left with a little extension from the main ROS right into the MCU. I feel that my 328 screen multiplexer will be updated to use this ROS message API. Reimplementing packeting and synchronization at the serial port level becomes a little less exciting after a while, and not having to even think about that with ROS is certainly welcome.
Below is the motherboard setup for all this. Unfortunately many of the things I wanted to attach used TTL serial, so I needed a handful of USB to TTL bridges. The IMU uses I2C, so its another matter of shoving a 328 into the mix to publish the ROS messages with the useful information for the rest of the ROS stack on the main machine to use at its will.
The web interface has been resurrected and extended from the old BBB driven Terry. This is the same Bootstrap/jQuery style interface but now using roslibjs to communicate from the browser to Terry. I'm using WebSockets to talk back, which is what I was doing manually from the BBB, but with ROS that is an implementation choice that gets hidden away and you again get a nice API to talk ROS like things such as publishing and subscribing standard and custom messages.
The below javascript code sends an array of 4 floats back to Terry to tell it where you want to have the arm (x,y,z,claw) to be located. The 4th number allows you to open and close the claw in the same command. The wrist is held horizontal to the ground for you. Notice that this message is declared to be a Float32MultiArray which is a standard message type.The msg and topic can be reused, so an update is just a prod to an array and a publish call. You can fairly easily publish these messages from the command line too for brute force testing.
var topic_arm_xyz = new ROSLIB.Topic({
ros : ros,
name : '/arm/xyzc',
messageType : 'std_msgs/Float32MultiArray'
});
var msg = new ROSLIB.Message({
data : [ x,y,z, claw ]
});
topic_arm_xyz.publish( msg );
The learning curve is a bit sharp for some parts of ROS. Navigation requires many subsystems to be brought up, and at first I had a case that the robot model was visualized 90 degrees out of phase to reality. Most of the stuff is already there, but you need to have a robot base controller that is compatible. It is also a trap for the new players not to have a simple robot model urdf file. Without a model some parts of the system didn't work for me. I'd have liked to have won with the MoveIt control, and will get back to trying to do just that in the future. I think I'll dig around for shoe string examples, something like building a very basic three servo arm with ice cream sticks and $5 servos would make for an excellent example of MoveIt for hobby ROS folk. Who knows, maybe that example will appear here in a future post.
C++, Linux, libferris and embedded development. Yet another blog from yet another NARG.
Showing posts with label arduino. Show all posts
Showing posts with label arduino. Show all posts
Friday, January 9, 2015
Sunday, June 15, 2014
Arduino and wireless networking
The nRF24L01 module allows cheap networking for Arduinos. Other than VCC which it wants at 3v3 it uses SPI (4 wires) and a few auxiliary wires, one for an interrupt line. One of the libraries to drive these chips is the RF24. Packets can be up to 32 bytes in length, and by default attempts to send less than 32 bytes result in sending a whole 32 byte block. Attempts to send more than 32 bytes seem to result in only the first 32 being sent. There is a CRC which is a 2 byte and is on by default.
For doing some IoT things using a HMAC might be much better choice than just CRC. The major advantage being that one can tell that something coming over a wireless link was from the expected source. Of course, if somebody has physical access to the arduinos then they can clone the HMAC key, but one has to define what they want from the system. The HMAC provides a fairly good assurance that sensor data is coming from the arduino you think it is coming from rather than somebody trying to send fake data. Another rather cute benefit is that the system doesn't accept junk data attacks. If your HMAC doesn't match the packet doesn't get evaluated by the higher level software.
Using a Sha256 HMAC the return ping times go from 50 to 150ms. The doubling can be explained by the network traffic, as the HMAC is 32 bytes and will double the amount of traffic. I think perhaps the extra 50ms goes into hashing but I'll have to measure that more specifically to find out.
Once I clean up the code a little I'll probably push it to github. A new RF24HMAC class delegates to the existing RF24 class and sends a HMAC packet right after the user data packet for you. The interface is similar, I'm adding some writenum() calls which I might make more like nodejs buffer. Once you have added the user data packet call done() to send everything including the HMAC packet.
RF24 radio(9,10);
RF24HMAC radiomac( radio, "wonderful key" );
radiomac.beginWrite();
radiomac.writeu32( time );
bool ok = radiomac.done();
The receiving end boils down to getting a "packet" which is really just the 32 bytes of user data that was sent. The one readAuthenticatedPacket() call actually gets 2 packets off the wire, the user data packet and the HMAC packet. If the hmac calculated locally for the user data packet does not match the HMAC that was received from the other end then you get a null pointer back from readAuthenticatedPacket(). The data is either authenticated or you don't get to see any of it.
RF24HMAC radiomac( radio, "wonderful key" );
uint8_t* packetData = 0;
if( packetData = radiomac.readAuthenticatedPacket() )
{
int di = 0;
uint32_t v = readu32( packetData, di );
got_time = v;
printf("Got payload %lu...\n\r",got_time);
}
Oh yeah, I also found this rather cute code to output hex while sniffing around.
For doing some IoT things using a HMAC might be much better choice than just CRC. The major advantage being that one can tell that something coming over a wireless link was from the expected source. Of course, if somebody has physical access to the arduinos then they can clone the HMAC key, but one has to define what they want from the system. The HMAC provides a fairly good assurance that sensor data is coming from the arduino you think it is coming from rather than somebody trying to send fake data. Another rather cute benefit is that the system doesn't accept junk data attacks. If your HMAC doesn't match the packet doesn't get evaluated by the higher level software.
Using a Sha256 HMAC the return ping times go from 50 to 150ms. The doubling can be explained by the network traffic, as the HMAC is 32 bytes and will double the amount of traffic. I think perhaps the extra 50ms goes into hashing but I'll have to measure that more specifically to find out.
Once I clean up the code a little I'll probably push it to github. A new RF24HMAC class delegates to the existing RF24 class and sends a HMAC packet right after the user data packet for you. The interface is similar, I'm adding some writenum() calls which I might make more like nodejs buffer. Once you have added the user data packet call done() to send everything including the HMAC packet.
RF24 radio(9,10);
RF24HMAC radiomac( radio, "wonderful key" );
radiomac.beginWrite();
radiomac.writeu32( time );
bool ok = radiomac.done();
The receiving end boils down to getting a "packet" which is really just the 32 bytes of user data that was sent. The one readAuthenticatedPacket() call actually gets 2 packets off the wire, the user data packet and the HMAC packet. If the hmac calculated locally for the user data packet does not match the HMAC that was received from the other end then you get a null pointer back from readAuthenticatedPacket(). The data is either authenticated or you don't get to see any of it.
RF24HMAC radiomac( radio, "wonderful key" );
uint8_t* packetData = 0;
if( packetData = radiomac.readAuthenticatedPacket() )
{
int di = 0;
uint32_t v = readu32( packetData, di );
got_time = v;
printf("Got payload %lu...\n\r",got_time);
}
Oh yeah, I also found this rather cute code to output hex while sniffing around.
Sunday, May 19, 2013
Some amateur electronics: hand made 8x8 LED matrix
So I made an 8x8 matrix of LEDs in a common cathode arrangement. Only one column is ever on at any time, but they cycle from left to right so quick that you and your camera can't get to see that little artefact. This does save on power though so the whole layer can be run directly from the arduino LeoStick in the top right of picture. Thanks again to Freetronics for giving those little gems away at LCA!
8x8 LED matrix, two 595 shifties and a ULN2003 current sink from Ben Martin on Vimeo.
The LEDs to light on a row are selected by a 595 shift register providing power for each row. The resistors are on the far right of the grid leading to that shift register. The cathodes for each individual column are connected together leading to the top of the grid (as seen in the video). Those head over to a uln2003 current sink IC. In the future I'll use either two 2003 chips or one single 2803 (which can do all 8 columns at once) to get the first column to light up too.
The uln2003 is itself controlled by supplying power to the opposite side to select which column's cathodes will be grounded at any given moment. The control of the uln2003 is also done by a 595 shift register which is connected to the row shifty too. The joy of all this is you can pump in the new state and latch the shift registers at once to apply the new row pattern and select which column is lit.
The joy of this design is that I can add 8x8 layers on top at the cost of 8 resistors and one 595 to perform row select.
There are also some still images of the array if you're peaked.
The 595 chips can be had for around 40c a pop and the uln2003 for about 30c. LEDs in quantity 500+ go at around 5-7c a pop.
The code is fairly unimaginative, mainly to see how well the column select works and how detectable it is. In the future I should setup a "framebuffer" to run the show and have a timer refresh the array automatically...
#define DATA 6
#define LATCH 8
#define CLOCK 10 // digital 10 to pin 11 on the 74HC595
void setup()
{
pinMode(LATCH, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
}
void loop()
{
int i;
for ( i = 0; i < 256; i++ )
{
int col = 1;
for( col = 1; col < 256; col <<= 1 )
{
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST, col );
shiftOut(DATA, CLOCK, MSBFIRST, i );
digitalWrite(LATCH, HIGH);
}
delay(20);
}
}
8x8 LED matrix, two 595 shifties and a ULN2003 current sink from Ben Martin on Vimeo.
The LEDs to light on a row are selected by a 595 shift register providing power for each row. The resistors are on the far right of the grid leading to that shift register. The cathodes for each individual column are connected together leading to the top of the grid (as seen in the video). Those head over to a uln2003 current sink IC. In the future I'll use either two 2003 chips or one single 2803 (which can do all 8 columns at once) to get the first column to light up too.
The uln2003 is itself controlled by supplying power to the opposite side to select which column's cathodes will be grounded at any given moment. The control of the uln2003 is also done by a 595 shift register which is connected to the row shifty too. The joy of all this is you can pump in the new state and latch the shift registers at once to apply the new row pattern and select which column is lit.
The joy of this design is that I can add 8x8 layers on top at the cost of 8 resistors and one 595 to perform row select.
There are also some still images of the array if you're peaked.
The 595 chips can be had for around 40c a pop and the uln2003 for about 30c. LEDs in quantity 500+ go at around 5-7c a pop.
The code is fairly unimaginative, mainly to see how well the column select works and how detectable it is. In the future I should setup a "framebuffer" to run the show and have a timer refresh the array automatically...
#define DATA 6
#define LATCH 8
#define CLOCK 10 // digital 10 to pin 11 on the 74HC595
void setup()
{
pinMode(LATCH, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
}
void loop()
{
int i;
for ( i = 0; i < 256; i++ )
{
int col = 1;
for( col = 1; col < 256; col <<= 1 )
{
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST, col );
shiftOut(DATA, CLOCK, MSBFIRST, i );
digitalWrite(LATCH, HIGH);
}
delay(20);
}
}
Wednesday, April 18, 2012
LFSR & arduino: a subset in hardware
The Linear Feedback Shift Register might appear to be "random" but it is of course far from it. The first two words should make you suspicious of how random things are. Version 1 does the actual production on the arduino chip. I'm hoping to break out the logic onto the breadboard for a future version. The arduino would then be relegated to a provider of voltage and ground.
Since it is all rather predictable, it would be fun to have a second arduino with light sensors on it be able to come close to the existing model and then sync its own LFSR and output to the LFSR.
Since it is all rather predictable, it would be fun to have a second arduino with light sensors on it be able to come close to the existing model and then sync its own LFSR and output to the LFSR.
Subscribe to:
Posts (Atom)