In order to attach a sensor, motor, camera or other component to the Redtree Hydra, the FPGA inside must be programmed. We know that this is normally a tricky task, so we created a tool to simplify it. The Redtree Hydra has four I/O cards, each of which can be connected to devices. Our web tool lets you configure what is attached to each I/O card so that it will work with the Redtree Hydra API. The tool is located at: http://www.redtreerobotics.com/fpga (coming soon).
Digital or Analog I/O
The first step is to select whether the I/O card in each slot is digital or analog (right now we do not support mixed cards - but we do support a mixture of analog and digital cards).
Analog
If the card is analog, the next step is to specify the number of pins that will be used. Typically this will be 16 or 32 bit, but any number may be selected up to 32 bits.
Digital
If the card is digital, the next step is to specify the types of interfaces connected to the card. At the current time, we support IIC, UART, SPI, PWM and general purpose Digital. As interfaces are clicked, they are added to the pinout diagram which you should use when connecting the components to the Redtree Hydra.
Repeat for Remaining I/O Cards
Additional cards can be configured at this time by changing the slot and repeating the previous steps.
Program the FPGA
When you click finish, the tool will automatically generate the files to program the FPGA when the Redtree Hydra is booted. Take the SDcard out of the Redtree Hydra and insert it into your computer. The two files 'boot.bin' and 'system_wrapper.bit' should be moved to the SDcard. The SDcard can then be ejected and re-inserted into the Redtree Hydra.
Connect it all up
The next step is to connect together all the motors, sensors, cameras and all the other components and start up the Redtree Hydra. You can now begin programming with C/C++ and the Redtree Hydra API and interacting with the components
Program the Robot
If you want to see a complete example of sharing the sensor, check out the share a sensor app:
svn co http://www.redtreerobotics.com/svn/redtree-apps/trunk/ redtree-apps cd redtree-apps/share_a_sensor
or if you prefer git:
git clone https://github.com/redtreerobotics/redtree-apps.git cd redtree-apps/share_a_sensor
As you can see in the example, there are two sides to this type of code, one is the robot sharing the sensor, and the other is the robot receiving the updates. Another possibility is the robot is sharing the sensor, and your computer is the other "robot" system receiving the updates.
Compared to the Hello Robot example, there are two files in this app. The data_source.cpp code is for the robot sharing the tag. The data_sink.cpp code is for the robot or device receiving the tag updates.
Data Source
The main thing that this code does, is it generates a different random number every second between 0 and 100. As soon as a tag data type is created, it is placed into the tag database and it becomes available locally to other robots (it does not share it automatically to the cloud, however). Tag data types include m_tag, m_num, m_blob and others. To compile this code, enter the following:
make data_source
And run it with the usual:
sudo rtr-mid
#include <rtr.h> #include <iostream> using namespace std; void configure(void) {} void initialize(void) {} void setup(void) {} void start(void) {} class data_source : public m_device { public: using m_device::m_device; m_num<int> SomeNumber{this, "SomeNumber"}; //generates a new random tag value every second between 0 and 100 m_worker<void,void> generator_task{this, "generator_task", [&](){ cout << "Generating number change: " << SomeNumber() << endl; //we use the () at the end of the tag to turn the tag into its atomic value //instead of a tag object SomeNumber() = drand48()*100; }}; void initialize(void) { //set the random number generator task to fire every second when //the data_source module is Started generator_task.run_every_when(1000000, Started); } void start(void) { //start the module Started = true; } }; data_source generator{"generator"};
The only other important thing to note with this example, is how network tags are named. Since the tag exists in the "generator" module, it is named as follows: "generator.SomeNumber". This is what you will need to look for in the data sink side of the code to see how to request this tag.
Here's the output from this module:
Data Sink
To compile this code, enter the following:
make data_sink
And run it with the usual:
sudo rtr-mid
The key to this code is the "get_tag_broadcast" function. This function returns a vector of all the m_tags that have the name specified. It also have a timeout value in seconds. After the specified number of seconds expires, all of the values will be returned. Note, m_tag is the parent type of all tags, so this is why a dynamic cast must be done in order to get the value of the tag. Depending on if the tag is an integer, floating point, etc. this function can handle all types. Note - if there are more than one robots that have the same tag, you will receive updates from all the robots. Currently, there is not a way to sort or filter based on a specific robot name, but that will be coming very soon.
#include <rtr.h> #include <rt_types.h> #include <rt_ddb_user.h> #include <iostream> using namespace std; class data_sink : public m_device { public: using m_device::m_device; void configure(void){} void initialize(void); void setup(void){} void start(void){Started = true;}; private: void main(); m_worker<void, void> data_sink_main{this, "data_sink_main", std::bind(&data_sink::main, this)}; }; void data_sink::main() { unsigned int i; vector<m_tag *> tags = get_tag_broadcast("generator.SomeNumber", 1); for(i = 0; i < tags.size(); i++) { m_tag * t = tags.at(i); m_num<int> *nt = dynamic_cast<m_num<int>*>(t); if(nt != NULL) { int val = *nt; cout << nt->name << ":" << val << endl; } } } void data_sink::initialize() { data_sink_main.run_when(Started); } data_sink receiver{"receiver"}; void configure(void){}; void initialize(void){}; void setup(void){}; void start(void){};
To further explain this example, the initialize function says that when the module is loaded, the data_sink::main() function should run. It will run over and over again in a loop as long as Started == true. So essentially it continues to request the tag value over and over again.
Here's the output from this module:
Comments