15. Writing PC software to control the Jrk
- 15.1. Example code to run jrk2cmd in C
- 15.2. Example code to run jrk2cmd in Ruby
- 15.3. Example code to run jrk2cmd in Python
- 15.4. Running jrk2cmd with Windows shortcuts
- 15.5. Example serial code for Linux and macOS in C
- 15.6. Example serial code for Windows in C
- 15.7. Example serial code in Python
- 15.8. Example I²C code for Linux in C
- 15.9. Example I²C code for Linux in Python
This section is about writing computer software to control the Jrk G2.
Picking an interface
You should decide which interface of the Jrk your software will talk to: serial, I²C, or USB. The Jrk’s USB interface has three main components: a native USB interface, a virtual USB serial port called the Command Port, and another virtual USB serial port called the TTL Port.
The native USB interface is the most powerful interface. One of the main advantages of using the native USB interface is that the Jrk G2 Command-line Utility (jrk2cmd) uses this interface. Instead of writing your own low-level software to encode USB commands, you can execute jrk2cmd with the desired options. There is more information about using jrk2cmd in Section 6.1. Since the utility is open source, you can modify it to suit your needs. If you want to write your own software for the native USB interface instead of using jrk2cmd, see the “Picking a native USB API” subsection below.
The Command Port is part of the Jrk’s USB interface. If you set the Jrk’s serial mode to “USB dual port” or “USB chained”, you can connect to the Command Port the same way you would connect to any other serial port, and then use it to send commands to the Jrk. Each command would be encoded as a sequence of bytes, as documented in Section 12. Most programming environments have some kind of library that allows you to connect to a serial port and then send and receive bytes from it.
The TTL Port is another USB serial port like the Command Port. The Jrk G2 does not process commands from its own TTL Port. However, if you set the Jrk’s serial mode to “USB dual port” then you can use the TTL port to send and receive serial bytes on the Jrk’s TX and RX lines, and those bytes could be serial commands to other Jrk controllers that are connected to the first one via serial.
The Jrk’s TTL serial interface consists of its RX and TX pins. If you set the Jrk’s serial mode to “UART”, then you can send commands to the Jrk on its RX line and receive responses on its TX line. To use this interface, your computer will need to have a TTL-level serial port or a USB-to-TTL-serial adapter, and you will need to make sure that you specify the right baud rate when connecting to the port in your software. Once you establish a working serial connection, writing software for the Jrk’s serial interface is very similar to writing software for its USB Command Port as described above.
The Jrk’s I²C interface consists of its SCL and SDA/AN pins. The Jrk’s I²C commands are documented in Section 13. It is more common for I²C to be controlled from a programmable microcontroller than from a computer, but if you have a computer with I²C pins or a USB-to-I²C adapter, then you could most likely use those to control the Jrk G2.
The commands that the Jrk accepts over its serial, I²C, and USB interfaces are documented in Section 11. If you have not done so yet, it is a good idea to read that section and think about which commands you will need in your application. Many applications just need the “Set target” command: in that case, it should be relatively easy to use any of the Jrk’s interfaces, and you could consider writing your own code to send that one command instead of relying on our code or third-party code. On the other end of the spectrum, for an application that needs to use a large number of Jrk commands or do something relatively complex with the Jrk, there would be an argument in favor of using the native USB interface and the Jrk G2 Command-line Utility.
Picking a native USB API
If you decide to use the native USB interface to communicate with the Jrk, the next thing to do is decide which API you want to use to access it.
Almost every operating system has its own API for accessing USB devices, so you could use the native USB API of your operating system. You would need to decide which commands you are going to send to the Jrk by reading Section 11, then figure out how to encode those commands for the Jrk’s USB interface by reading Section 14, and finally figure out how to send those USB commands using the API you have chosen by reading the documentation of that API. These APIs are typically meant for C programs, so you have to carefully manage pointers and memory allocation yourself. However, you might be able to find an API wrapper in the language of your choice that takes care of managing pointers for you.
Another option is to use a USB abstraction library like libusbp or libusb. These libraries abstract away the differences between USB APIs for the different operating systems they support, so you can write code that works on multiple operating systems. You would still have to read the documentation of the Jrk’s commands and USB protocol, read the documentation of the API you have chosen, and carefully manage pointers. However, you might be able to find a library wrapper in the language of your choice that manages pointers for you.
In our Jrk G2 software, we provide a C library called libpololu-jrk2 that uses libusbp to talk to the Jrk G2. The library takes care of the details of encoding the Jrk’s USB commands so that you do not have to know much about the Jrk’s USB interface—you just have to call the appropriate function for each command you want to send. You would need to read the documentation of the library in the
include/jrk.h file to understand how to use the library, and carefully manage pointers.
In general, the easiest way to write software to control the Jrk G2 over USB is to install the Jrk G2 software and then invoke the Jrk G2 Command-line Utility (jrk2cmd), which is built on top of libpololu-jrk2. You can run
jrk2cmd in a command prompt with no arguments to see what arguments the program supports. For example, to send a “Set target” command, you could run
jrk2cmd --target 1234. If jrk2cmd is installed correctly, then its folder should be listed in your PATH environment variable, meaning that other programs can find it and run it without knowing exactly where it is. The jrk2cmd utility takes care of all the details of finding the Jrk you want to talk to, encoding your command properly for the Jrk’s USB interface, sending the command, and cleaning up after itself. If an error happens, jrk2cmd will print an error message to its standard error pipe and return a non-zero exit code. Your software can look at the non-zero exit code to detect if an error happened, or just ignore the error. For more information about getting started with
jrk2cmd, see Section 6.1.
Porting software for the original Jrk controllers
If you have software that uses the native USB interface of the original Jrk 21v3 or Jrk 12v12 controllers but it does not work with the Jrk G2 (for example, the Pololu USB SDK), you might be able to change the code to support the Jrk G2. The difficulty of such a modification depends on which features of the Jrk’s native USB interface you are using. The native USB “Set target” and “Motor off” commands of the Jrk G2 are the same as they were on the original Jrk controllers. If your application only uses those two commands, all you need to do is modify the software so it can recognize and connect to the Jrk G2. If your software uses more advanced features of the native interface, such as changing the Jrk’s settings, then the required modifications to the code will be more complicated. Section 14 documents the Jrk G2’s native USB interface, and you should refer to it when making your modifications.