📜 ⬆️ ⬇️

Part 2. HID device for camera rotation

image
This is a continuation of my article about a device for rotating a webcam (the previous article can be found here ).

In this part, I will talk about creating the software part: the firmware for the ATtiny85 microcontroller and the computer program in order to be able to control the device.

To create the firmware of the microcontroller and software, I used the finished project, reworking it for myself. ( This information is mandatory for reading, since I will not describe the details).

Microcontroller firmware

Depending on the control program command, the firmware installs legs 1, 3, 4, 5 into logical 1 or 0. Also, if no command arrives for 2 seconds, then all four legs are set to 0, this is done so that if there is a failure the work of the program on the PC, the device did not fixate on the execution of the last command (wrote the firmware on AVR Studio4, this environment is not friendly with Cyrillic, so check the addresses. You can also use PROTEUS to test the firmware):
... if(bytesRemaining == 0) //    { //    PORTB if ( pdata.b1 ) //   1   PORTB |= _BV(1); else PORTB &= ~_BV(1); if ( pdata.b2 ) //   3   PORTB |= _BV(3); else PORTB &= ~_BV(3); if ( pdata.b3 ) //   4   PORTB |= _BV(4); else PORTB &= ~_BV(4); if ( pdata.b4 ) //   5   PORTB |= _BV(5); else PORTB &= ~_BV(5); } ... if(i==200) // 1,3,4,5   0  2 { PORTB &= ~_BV(1); PORTB &= ~_BV(3); PORTB &= ~_BV(4); PORTB &= ~_BV(5); } ... 

Leg shortage

Attiny85 has only 8 legs. Two of them to power the microcontroller. One to reset the data, and two more are used to use the USB interface. It remains three free, but I need 4 legs to control two engines.
')
image

There are two ways to get out of this situation: the first is a shift register (it can be used to increase the number of controlled outputs to the desired one, but at the same time you have to sacrifice speed and reliability. See here );
The other is to use a fuse bit to redefine the Reset leg to normal input / output. (Read here ).
I used the second method and set RSTDISBL to 0. in fuses (I got an error when reading fuses with the help of SinaProg. I found the solution here ).
When flashing a microcontroller with such fuses parameters, it can only be reflashed again by a high-voltage programmer, so you need to recheck the setting, especially in usbconfig.h. (Contained settings for V-USB)
In case of unsuccessful firmware, you need to manually remove the driver that installs the OS for your device in the “device manager”. Otherwise, the incorrectly installed driver will be used further for all subsequent firmware of the microcontroller.

Management program

I used ready-made code, so I didn’t have problems with setting up a connection. This part of the code is responsible for the formation and sending of commands, as well as for receiving information about the state of the device (in this case, the state of the legs 1 3 4 5. I quote only the class):

 #define Max 230 class Device{ class dataexchange_t //      { public: char b1; //      4 . char b2; //       PORTB.   char b3; //   (  4  ). char b4; }data; class Position{ public: float x; float y; }positionTransform, cameraPosition; /* positionTransform -          cameraPosition -       */ HIDLibrary <dataexchange_t> hid; //        unsigned char processTime; //        FILE *f; //       int SendData(dataexchange_t *); public: bool Connect(); void SetCameraPosition(short int *, short int *); bool MoveCamera(); bool StopMoveCamera(); Device() { processTime = 10; (int&)data = positionTransform.x = positionTransform.y = 0; f = fopen("CameraPosition.txt","r+"); fscanf(f,"%f %f", &cameraPosition.x, &cameraPosition.y); if(cameraPosition.x < -Max || cameraPosition.y < -Max || cameraPosition.y > Max || cameraPosition.x > Max) cameraPosition.x = cameraPosition.y = 0; } ~Device() { fclose(f); } }; ... 


Since I refused to rotate the camera 360 degrees, I had to programmatically introduce a limit of 230 degrees, that is, the camera rotates to the left (230 degrees) and to the right (-230 degrees) 230 degrees from the beginning. (It should be noted that the software limitation is the worst solution to such a problem; it would be better to install mechanical switches that would turn off one of the motor power circuits).

I also introduced a specific coordinate axis to control the rotation of the camera in order not to load the OS by sending commands continuously. The user leads by how many degrees it is necessary to turn the camera relative to the current position. Further, the entered degrees are converted into several commands, which with an interval of 2 seconds should be sent to the device.
 ... //       (    2) if(*x > 0) positionTransform.x = (*x * 0.20832); //         else positionTransform.x = (*x * 0.225); //       (    2) if(*y > 0) positionTransform.y = (*y * 0.20832); else positionTransform.y = (*y * 0.225); ... 


The device first turns the camera horizontally, and then vertically, so as not to overload the USB port by simultaneously supplying two engines.

The result is that the microcontroller is controlled by a program from a computer, which in turn controls the driver of the engine (I used L293), and it already controls two engines.

Video and audio transmission

I had to transfer the signal from the camera and control it from a distance. I found a way out using the Skype API (The problem was only that the Skype API was no longer supported, so there are bugs). To use the Skype API, you need to copy the Skype4COM.dll file to the disk where the OS is installed.

My Skype program monitors chat with a client - a user who uses my device. When the user enters the camera to start the camera operation (in this case, the “0000” command), the program will make a video call and turn on the device. After that, the user can control the camera by entering the following commands into the chat:

“StopMove MoveTo ('X' @ 'Y') VideoOn VideoOff Wait'TimeInSec '”. (Skype will first turn off the camera to the VideoOff team, and then immediately turn it on, if you manually turn on the video display in manual mode, this command works fine):

 ... char comandName[] = {"###"}; //   char comandStart[] = {"0000"}; //   int timeWait = 500; //     //  COM  CoInitialize(NULL); //  Skype  SKYPE4COMLib::ISkypePtr pSkype(__uuidof(SKYPE4COMLib::Skype)); //   Skype API pSkype->Attach(6,VARIANT_TRUE); _bstr_t comand; IChatMessagePtr curMessage, privMessage = NULL; COleDateTime startTime(time(NULL)); for(;;)//      { curMessage = pSkype->GetMessages((_bstr_t)comandName)->GetItem(1); //      comand = curMessage->GetBody(); //    if(!strcmp((char*)comand,comandStart) && (privMessage == NULL || privMessage->GetId() != curMessage->GetId()) && (startTime.m_dt < curMessage->GetTimestamp())) { privMessage = curMessage; curMessage->PutSeen(true); //      ControlDevice(pSkype, comandName, timeWait, privMessage); } else Sleep(5000); } ... _bstr_t comand; IChatMessagePtr curMessage; int timeToSendMessage = (timeWait/100)*80; Device device; ICallPtr call; //  (  ,   ) for(int i = pSkype->GetActiveCalls()->GetCount(); i != 0 ; i--) { call = pSkype->GetActiveCalls()->GetItem(i); //    if(!strcmp((char*)(call->GetPartnerHandle()),comandName)) { call->Finish(); //   Sleep(2000); break; } } call = pSkype->PlaceCall(_bstr_t(comandName), L"", L"", L""); //   pSkype->SendMessage(_bstr_t(comandName), _bstr_t(L"'Ń” ")); if(!device.Connect()) //    pSkype->SendMessage(_bstr_t(comandName), _bstr_t(L"Ń– Ń–  Ń–")); for(int i = 0;i < timeWait && call->Status != clsInProgress;i++) //     Sleep(20); if(call->Status == clsInProgress) { Sleep(2000); call->StartVideoSend(); //  (  ) for(int time = 0; call->Status == clsInProgress;time++) { if(time >= timeWait) //     -   { call->Finish(); break; } curMessage = pSkype->GetMessages((_bstr_t)comandName)->GetItem(1); if(curMessage->GetId() != privMessage->GetId()) //     { privMessage = curMessage; if(time > 0) time = 0; if(!ComandToDevice((char*)curMessage->GetBody(),&device,pSkype,comandName,&time,call))//     pSkype->SendMessage(_bstr_t(comandName), _bstr_t(L"  ")); curMessage->PutSeen(true); } Sleep(200); if(!device.MoveCamera()) { pSkype->SendMessage(_bstr_t(comandName), _bstr_t(L"  Ń” Ń–")); device.StopMoveCamera(); } if(timeToSendMessage == time) pSkype->SendMessage(_bstr_t(comandName), _bstr_t(L" Ń–  Ń”")); } } pSkype->SendMessage(_bstr_t(comandName), _bstr_t(L"'Ń” ")); } ... 

Video demonstration of the device.



Completely all project can be taken here .

Source: https://habr.com/ru/post/215841/


All Articles