We develop pedal firmware for learning to play the balalaika

    I really love video tutorials. For some reason, I personally perceive the information from the text very, very badly. But there are things in which there is not much information on paper. Take, for example, the lessons of playing the balalaika: on YouTube there are wonderful discussions on how to play this or that melody (who are interested, we are looking for “Sergey Vorontsov”), but it’s difficult to repeat and memorize the sequence from the streaming video. It is necessary either to write down on paper (judging by the comments under the lessons, some do so), or buy additional materials (but I'm not greedy, but home-made).



    In general, in my balalaika case, and with many others, I have to go this way: I looked at the fragment, paused it, repeated it several times behind the author, and continued watching. If something is not clear - rewound, looked more closely. But how to wind it all up if your hands are busy? Moreover, in my case they are busy, if not with a huge button accordion, but still some, but with a balalaika. So, you need to work with your legs.

    Many, many years ago, when all progressive mankind used PS / 2 keyboards, they brought us dozens of USB keyboards for the project. Of course, we connected them to one machine, pressed Ctrl on one of them, Alt on the second, and Del on the third. The effect has been achieved. Since then, I know that USB keyboards work completely in parallel, so you can connect another one to help the main one, which will send some codes instead.

    So the idea was born to make a pedal that pretends to be a keyboard and sends player control codes. As a player, I initially chose VLC Player, since it has well-documented control buttons, but later it turned out that the codes I selected had exactly the same purpose when watching videos on YouTube in full screen mode. This is good, because with multiple online views, for the impressions of the advertisement, something seems to fall into the author's mind. Watching downloaded would not be so ethical.

    So, we begin designing the device.

    Work logic


    At first I wanted to make several pedals, each for its own function. Initially, I counted 3-4 of these functions: on, off, wind there, wind back. But then I figured out how much plastic it would take, plus - how I would understand the pedals by touch, and was sad. Therefore, it was decided to radically revise the whole logic. What features are needed at all? Start-stop, but it often hangs on the same key, usually on a space. And rewinding. VLC Player has “Shift + Left”. YouTube, as it turned out, also. And, if you think so, there are no more functions.

    Perfectly! Let's make the pedal briefly use the "Start-Stop" function, and long - by the "Rewind" function.

    In the future, you can expand the functionality. You can train the pedal to recognize morse code. My wife, having learned about the idea, suggested coding control impulses using elements of Irish dances ... In general, you can expand the functionality as you like. But one thing is clear: one pedal is enough. Well, now we will do recognition of long and short presses.

    Mechanics


    For those who walk at home in slippers, there is a very simple solution (I found it on the Thingiverse website). We take a button with a diameter of more than a centimeter, screw it into any box-shaped object, we get a pedal. The trouble is that I do not like slippers, so this option does not suit me personally. I need a larger surface so that the foot does not hurt.

    Pedals in huge quantities are sold on Ali Express, you should search for the word Foot Switch. Prices there start at 30 rubles, but at this price, the delivery cost can be about four hundred rubles. After searching, I found that it is quite possible to find a pedal for which the sum “price plus delivery” will be 150 rubles. But you will have to wait an average of a couple of months (I’ve been waiting here recently for an SD card for all three months).

    So I went the faster way: made a pedal on a 3D printer. Personal experience (and all options with Thingiverse) show that the axis must be metal, otherwise everything will quickly break. I took the M6x60 furniture bolt I had with the nut attached to it, as well as the button (PSW-13), which was in the neighboring Radio Parts, and circled them around as plastic as I could. This is how the raw materials looked:



    Here they are, inserted into the lower half. As you can see, the main design feature is the walls, at least four millimeters thick. With these parameters, even a gentle proto-typer becomes quite durable. The button is installed without a nut, since any emptiness beneath it will lead to breaking off the plastic, and it keeps pretty well.



    Here is an almost assembled version:



    And here is the pedal assembly:



    In principle, I will attach the STL files, but the solution was not perfect. Nevertheless, anyone can repeat it (if he finds the M6x60 bolt with the corresponding nut and the PSW-13 button). Enough for the first time, and then - you can stamped mechanics and order with ALI.

    USB device


    Although I have been actively promoting PSoC lately, using it on the pedals is an unheard of waste. I consider the best solution a breadboard based on STM32F103C8T6, which can now be ordered on ALI Express for about 120 rubles (including delivery).



    Of course, we can speculate that there are cheaper boards based on AVR, but the price difference is not significant there, and STM32 has significantly less development time due to debugging via JTAG. An hour of time (even at home) - it also costs something. So, according to the total criterion “device price + labor costs”, STM32F103 is the best option for this task. Moreover, I have one and a half dozen such mock-ups in store for such a case, so the delivery waiting time is now equal to zero for me.

    I surfed the net for ready-made USB keyboards based on this chip. I found an article on Habr how to make a USB mouse. But I need a keyboard. On the topic of keyboards, I found a lot of smart tips on the forums (but I wanted something ready) and a couple of some ready-made, but complex projects on GitHub (but I wanted something clear). But he who seeks will always find. Here is a wonderful article in which there is everything that is needed (although there is one in the code, I’m not afraid of this non-Russian word, a potential DeadLock, but I will write my own code). The main thing is that all steps are clearly described in it, how to get a USB keyboard from a finished “fish” made in Cube MX. The only thing the author did not do was not publish the key codes. Add them here:



    The fly in the ointment is that in the modern version of Cube MX, the names of files, functions, and even constants are slightly different from those specified in that article, but by analogy everything is quickly found. I could write a new version of the text, but where is the guarantee that the developers will not change everything again? They like to do it. In general, you can see the analogs in my example.

    So. I created a basic project in Cube MX, made all the changes recommended by the article mentioned above. What's next? Next, add a description of the button port. I chose PB12 (purely because the corresponding contact is located on the corner of the breadboard). Since I always work with iron through the mcucpp library of Konstantin Chizhov, we remove the “-C99” macro definition in the project properties, rename main.c to main.cpp, after which we add the announcement:

    typedef Mcucpp::IO::Pb12 pedal1;

    We add port initialization to the main () function (enabling port clocking, setting the leg direction, turning on the suspender):

    	
            pedal1::ConfigPort::Enable();
    	pedal1::SetDirRead();
    	pedal1::SetPullUp (pedal1::Port::PullUp);
    

    Actually, everything is initialized. I decided to build the main body in the image of the Verilog process. I don’t know why, I just wanted to. The process is usually called on clock pulses. I decided that system ticks are perfectly taken as ticks. Therefore, the regular function of the system tick handler in the stm32f1xx_it.c file was added as follows:



    Same text:
    void SysTick_Handler(void)
    {
      /* USER CODE BEGIN SysTick_IRQn 0 */
      /* USER CODE END SysTick_IRQn 0 */
      HAL_IncTick();
      HAL_SYSTICK_IRQHandler();
      /* USER CODE BEGIN SysTick_IRQn 1 */
    	TickProcess();
      /* USER CODE END SysTick_IRQn 1 */
    }
    


    I put the TickProcess () function itself in main. cpp . First, consider it in its entirety, then in parts.

    Here is the full function:
    uint8_t report [8] = {0,0,0,0,0,0,0,0};
    uint32_t* pReport = (uint32_t*)report;
    extern "C"
    void TickProcess()
    {
      	// Число должно нацело делиться на 20!!!
      	static const int shortTime = 700;	 // Время короткого щелчка по кнопке
    	static const int longTime = 2000; // Время срабатывания автоповтора
    	static int localTick = 0;
    	static int tickDuringButton = 0;
    	static bool bButtonStatePrev;
    	bool bButtonState = pedal1::IsSet();
    	// кнопку только что нажали
    	if ((!bButtonState) && bButtonStatePrev)
    	{
    		tickDuringButton = 0;
    	}
    	// Кнопку только что отпустили
    	if (bButtonState && (!bButtonStatePrev))
    	{
    		// Её удерживали в течение короткого времени
    		// Но больше, чем 50 мо (антидребезг)
    		if ((tickDuringButton >100)&&(tickDuringButton < shortTime))
    		{
    			// Кладём код пробела
    			report [2] = 0x2C;
    		}
    	}
    	// Кнопку давно удерживают
    	if ((!bButtonState) && (!bButtonStatePrev))
    	{
    		if ((tickDuringButton == shortTime)||(tickDuringButton > longTime))
    		{
    			// Кладём Shift+Влево
    				report [0] = 2;		// Shift
    				report [2] = 0x50;	// Влево
    		}
    	} 
    	// Имитируем автомат Верилоговский
    	bButtonStatePrev = bButtonState;
    	tickDuringButton += 1;
    	if (localTick++ % 20 == 0)
    	{
    			USBD_HID_SendReport (&hUsbDeviceFS,report,sizeof(report));
    			pReport [0] = 0;
    			pReport [1] = 0;
    	}
    }
    


    The first task that is implemented in this handler is simple. Every 20 milliseconds we send a report containing information about the buttons pressed (if there are no buttons, we send anyway, just with zeros). Since the function is called every millisecond, the report should be sent to one of its twenty calls. To do this, there is a variable at the beginning of the function:

    	static int localTick = 0;
    

    and the code at the end (we send the data, after which we erase the buffer so that to start sending zeros from the next session):

    	if (localTick++ % 20 == 0)
    	{
    			USBD_HID_SendReport (&hUsbDeviceFS,report,sizeof(report));
    			pReport [0] = 0;
    			pReport [1] = 0;
    	}
    

    The second task is more complicated. It tracks the nature of pressing the pedal and fills the report for subsequent submission. Why did I say that ideology is like Verilog? Because I always catch differences in that language: I have a variable in which the current state of the button is placed:

    	bool bButtonState = pedal1::IsSet();
    

    and there is a variable in which its previous state is stored (as we remember, the previous state is the state of the button during the previous interrupt processing from the 1 ms timer):

    	static bool bButtonStatePrev;
    

    The pressed button gives the value false , the pressed button - true . Thus, we can always conclude about the dynamic state of the button:

    bButtonStatebButtonStatePrevcondition
    truetrueLong released
    truefalseReleased on the previous measure
    falsetruePressed on previous measure
    falsefalseLong pressed

    We introduce two constants. One sets the short press time. If the press lasted less than 700 ms, then it is short-lived. The second sets the time when auto-repeat is turned on. If just after seven hundred milliseconds you start sending the key code, the player will start to wind too abruptly. This is identified empirically. Therefore, the logic of work is as follows: after 700 ms, a single code “Shift + Left” is sent, after which the user is given the opportunity to release the pedal. If the pedal continues to be held, then from the second second the constant sending of this code already begins until the pedal is released.

    	const int shortTime = 700;	 // Время короткого щелчка по кнопке
    	const int longTime = 2000; // Время срабатывания автоповтора
    

    The time during which the button is pressed is stored in a variable:

    	static int tickDuringButton = 0;
    

    If the button has just been pressed, we zero this variable, starting to measure a new period of time:

    	// кнопку только что нажали
    	if ((!bButtonState) && bButtonStatePrev)
    	{
    		tickDuringButton = 0;
    	}
    

    If the button has just been released, then we check the time how much it was pressed. If just a little bit (now it says “less than 100 ms”) - this is a chatter. This does not count. Ignore this click. If we do nothing more than the duration of the short press, long presses are processed below. If, within a short press, we create a report in the buffer with a space (which will be sent when the time comes for this):

    	// Кнопку только что отпустили
    	if (bButtonState && (!bButtonStatePrev))
    	{
    		// Её удерживали в течение короткого времени
    		// Но больше, чем 100 мо (антидребезг)
    		if ((tickDuringButton >100)&&(tickDuringButton < shortTime))
    		{
    			// Кладём код пробела
    			report [2] = 0x2C;
    		}
    	}
    

    If the button has been held down for a long time, then we send “Shift + Left” in two cases:

    • the button is held exactly 700 ms (single package);
    • the button is held for more than 2 seconds (sending in each subsequent report until the button is released).

    	// Кнопку давно удерживают
    	if ((!bButtonState) && (!bButtonStatePrev))
    	{
    		if ((tickDuringButton == shortTime)||(tickDuringButton > longTime))
    		{
    			// Кладём Shift+Влево
    				report [0] = 2;		// Shift
    				report [2] = 0x50;	// Влево
    		}
    	} 
    

    That, in fact, is all. This code is no more different from the “fish” that Cube MX made to us. We assemble, flash ... No, it is impossible without errors (here they are all caught, but I couldn’t do without them initially), we identify them in 10 minutes via JTAG debugging (hello to AVR), we’re sewing, we’re happy ...

    Alternative design


    In general, such things are useful without a balalaika (or other viewing of video tutorials). In particular, I like to read the news, lying in bed, with a laptop on my stomach. To scroll the text, you have to keep your right hand bent all the time, and this leads to pain in the elbow. Therefore, I have long dreamed of a big red button that could scroll pages without bending my arm. Actually, it can be made from the same components as the pedal, replacing the furniture bolt with a small amount of hot glue. Total: PSW13 button, STM32F103C8T6 breadboard, plastic for 3D printer, hot-melt adhesive. Well, in the “firmware” I replaced the codes with “PgDn” by a short press and “Up” by a long one.





    Conclusion


    You can use your legs to control the display of video tutorials when your hands are busy. To do this, just one pedal that simulates the operation of the USB-keyboard. One pedal can send multiple key codes, selecting them based on different types of keystrokes. The article considers a pedal that parses two types (short and long press).

    The mechanics can be found on Ali Express under the word Foot Switch or can be printed on a 3D printer. As electronics, the breadboard STM32F103C8T6 can be used. "Firmware" is done in less than an hour on the basis of the "fish" created by Cube MX from the manufacturer of controllers STM32. Additional code occupies several screens of text (for a resolution of 2K - one screen).

    In general, the entire device (mechanics + “firmware”) was completely designed in one evening, plus it took about four hours to print mechanics on a 3D printer.

    Ready STL files for pedal printing can be downloaded here (it is desirable to lower the Top element by 0.4 mm to avoid a large number of supports: the surface turned out to be slightly rounded, lowering the model, we will make the printed part flat).

    STL files of the "big red button" can be downloaded here .

    Ready-made source files for the project and the HEX file for the firmware can be downloaded here .

    The date of publication of this article was not chosen by chance. The council decided that it is better to publish an article about such things on a serious site on that day. But in fact, if you look at the videos found on the phrases "Alexey Arkhipovsky", "Dmitry Kalinin", "Cranberry Show", "Alexey Kodenko", it becomes clear that the academic balalaika is like an assembler. Both there and there are combined absolute simplicity and frantic expressive power. And by the phrase "Sergey Vorontsov" you can understand how to learn how to use this tool.

    Addition


    After 8 months of operation, the PSW-13 button began to work once out of many, and only with very strong pressure. When trying to replace, it turned out a very interesting detail. The new button, bought at the same time as the previous one, has a completely different power reserve and works in a completely different position. As a result, she was always depressed on my pedal. I had to grind it with a dremel. Who will repeat my mechanics - keep in mind. You may have to modify the button with a file or vice versa - sculpt an electrical tape on it to increase it. The repeatability of the plastic part of this button was not very. But in general - after such a revision, everything works again.

    Also popular now: