PageRenderTime 338ms CodeModel.GetById 0ms RepoModel.GetById 4ms app.codeStats 0ms

/motcont/MotorControl22.nxc

http://nxt-python.googlecode.com/
Unknown | 918 lines | 701 code | 217 blank | 0 comment | 0 complexity | e51729f0f261d95c27d434263c38cd9d MD5 | raw file
Possible License(s): GPL-3.0
  1. //#!C
  2. /*
  3. % The NXT Program MotorControl enables precise motor movement via direct
  4. % commands. It listens to "NXT BT messages", interprets their content (own user-
  5. % defined "protocol", if you will), and carries out highly precise motor actions
  6. % in a different thread for each motor, allowing the upper level program (in
  7. % this case, MATLAB) to carry on with execution...
  8. %
  9. % See also: http://www.mindstorms.rwth-aachen.de/trac/wiki/MotorControl
  10. %
  11. % CHANGELOG:
  12. %
  13. % * Version 2.2, 2010/09/14
  14. % First released with toolbox version 4.04
  15. % - Commented dead code in case compiler optimization doesn't find it
  16. % - No real code changes
  17. % - Version to be recompiled with newer NBC/NXC compiler versions,
  18. % as some multi-threading / optimization bugs were fixed.
  19. % - Not recommending FW version 1.26 anymore
  20. % - Updated version numbers
  21. %
  22. % * Version 2.1, 2009/08/31
  23. % First released with toolbox version 4.01
  24. % - Considered to be stable and working
  25. % - Very occasional freezes with FW 1.26 during
  26. % massive production use, see also:
  27. % http://www.mindstorms.rwth-aachen.de/trac/ticket/51
  28. %
  29. %
  30. % Signature
  31. % Author: Linus Atorf (see AUTHORS)
  32. % Date: 2010/09/14
  33. % Copyright: 2007-2010, RWTH Aachen University
  34. %
  35. %
  36. % ***********************************************************************************************
  37. % * This file is part of the RWTH - Mindstorms NXT Toolbox. *
  38. % * *
  39. % * The RWTH - Mindstorms NXT Toolbox is free software: you can redistribute it and/or modify *
  40. % * it under the terms of the GNU General Public License as published by the Free Software *
  41. % * Foundation, either version 3 of the License, or (at your option) any later version. *
  42. % * *
  43. % * The RWTH - Mindstorms NXT Toolbox is distributed in the hope that it will be useful, *
  44. % * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS *
  45. % * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *
  46. % * *
  47. % * You should have received a copy of the GNU General Public License along with the *
  48. % * RWTH - Mindstorms NXT Toolbox. If not, see <http://www.gnu.org/licenses/>. *
  49. % ***********************************************************************************************
  50. */
  51. // *************** GLOBAL DEFINES
  52. // important to be before includes,
  53. // since they might be used inside the includes!
  54. #define PROGRAM_VERSION "2.2"
  55. #define INBOX 1
  56. #define OUTBOX 0
  57. #define DEBUG_OUTBOX 2
  58. // Protocol constants
  59. #define PROTO_CONTROLLED_MOTORCMD 1
  60. #define PROTO_RESET_ERROR_CORRECTION 2
  61. #define PROTO_ISMOTORREADY 3
  62. #define PROTO_CLASSIC_MOTORCMD 4
  63. #define PROTO_JUMBOPACKET 5
  64. // *************** INCLUDES
  65. #include "Controller.nxc"
  66. // Current file structure:
  67. // + MotorControl.nxc (this file)
  68. // |-+ Controller.nxc
  69. // |-- MotorFunctions.nxc
  70. // |-- SpeedFromPosLookup.nxc
  71. // |-- ControllerCore.nxc (for Motor A)
  72. // |-- ControllerCore.nxc (for Motor B)
  73. // |-- ControllerCore.nxc (for Motor C)
  74. // |-- ControllerCore.nxc (for sync mode)
  75. // *************** PROGRAM STARTS
  76. struct typRunMotorParams {
  77. int power;
  78. long tacholimit;
  79. bool speedreg;
  80. bool holdbrake;
  81. bool smoothstart;
  82. int turnratio;
  83. };
  84. byte SyncPorts;
  85. typRunMotorParams motorParamsA;
  86. typRunMotorParams motorParamsB;
  87. typRunMotorParams motorParamsC;
  88. typRunMotorParams motorParamsSync;
  89. //TODO are the mutexes really still needed?
  90. mutex movingA;
  91. mutex movingB;
  92. mutex movingC;
  93. // these semaphores are actually interpreted as "motorArunning", as they are
  94. // also set and interpreted for synced movements... a bit like the mutexes above
  95. bool taskArunning;
  96. bool taskBrunning;
  97. bool taskCrunning;
  98. #ifdef ENABLEDEBUGGING_SHOWTASKS
  99. bool taskSyncRunning;
  100. #endif
  101. #ifdef ENABLEDEBUGGING_OLDLCDTIMING
  102. long parsedTime;
  103. long taskStartedTime;
  104. #endif
  105. safecall void DisplayMainScreen() {
  106. string tmp;
  107. // nice message to screen:
  108. tmp = StrCat("MotorControl ", PROGRAM_VERSION);
  109. TextOut(0,LCD_LINE1, tmp, true);
  110. TextOut(0,LCD_LINE2, "for FW 1.28-1.29", false);
  111. TextOut(3,LCD_LINE4, "(C) RWTH Aachen", false);
  112. TextOut(3,LCD_LINE5, "University, LfB", false);
  113. TextOut(4,LCD_LINE7, "Press ORANGE to", false);
  114. TextOut(4,LCD_LINE8, "stop all motors", false);
  115. #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
  116. TextOut(0, LCD_LINE8, "SLOW ANTIBUG ON ", true);
  117. #endif// - - - - - - -
  118. }//end void
  119. safecall void TaskBusySignal() {
  120. PlayTone(2000, 50);
  121. Wait(50);
  122. PlayTone(1500, 50);
  123. }//end TaskBusySignal
  124. // tasks
  125. task MoveA() {
  126. //TextOut(0,LCD_LINE6, "Task A started");
  127. //Acquire(movingA);
  128. taskArunning = true;
  129. bool stoppedByDirectCmd;
  130. stoppedByDirectCmd = RunMotorA(OUT_A, motorParamsA.power, motorParamsA.tacholimit, motorParamsA.speedreg, motorParamsA.holdbrake, motorParamsA.smoothstart);
  131. // if we exited from external NXTMotor.Stop command, we might've overwritten
  132. // the power value before exiting the main controller loop, so restore defined
  133. // end state here again:
  134. if (stoppedByDirectCmd) {
  135. if (MotorRegulation(OUT_A) == OUT_REGMODE_SPEED) {
  136. MotorBrake(OUT_A);
  137. } else {
  138. MotorOff(OUT_A);
  139. }//end if
  140. }//end if
  141. taskArunning = false;
  142. //Release(movingA);
  143. //TextOut(0,LCD_LINE6, "Task A stopped");
  144. }//MoveA
  145. task MoveB() {
  146. //TextOut(0,LCD_LINE7, "Task B started");
  147. //Acquire(movingB);
  148. taskBrunning = true;
  149. #ifdef ENABLEDEBUGGING_OLDLCDTIMING
  150. taskStartedTime = CurrentTick() - receivedMsgTime; // NEW DEBUG
  151. #endif
  152. bool stoppedByDirectCmd;
  153. stoppedByDirectCmd = RunMotorB(OUT_B, motorParamsB.power, motorParamsB.tacholimit, motorParamsB.speedreg, motorParamsB.holdbrake, motorParamsB.smoothstart);
  154. // if we exited from external NXTMotor.Stop command, we might've overwritten
  155. // the power value before exiting the main controller loop, so restore defined
  156. // end state here again:
  157. if (stoppedByDirectCmd) {
  158. if (MotorRegulation(OUT_B) == OUT_REGMODE_SPEED) {
  159. MotorBrake(OUT_B);
  160. } else {
  161. MotorOff(OUT_B);
  162. }//end if
  163. }//end if
  164. #ifdef ENABLEDEBUGGING_OLDLCDTIMING
  165. string tmp = ""; // NEW DEBUG
  166. tmp = NumToStr(parsedTime);
  167. tmp = StrCat("Parsed ", tmp, "ms");
  168. TextOut(0,LCD_LINE3, tmp, true);
  169. tmp = NumToStr(taskStartedTime);
  170. tmp = StrCat("Task ", tmp, "ms");
  171. TextOut(0,LCD_LINE5, tmp);
  172. tmp = NumToStr(motorStartedTime);
  173. tmp = StrCat("Motor ", tmp, "ms");
  174. TextOut(0,LCD_LINE7, tmp);
  175. #endif
  176. taskBrunning = false;
  177. //Release(movingB);
  178. }//MoveB
  179. task MoveC() {
  180. //TextOut(0,LCD_LINE8, "Task C started");
  181. //Acquire(movingC);
  182. taskCrunning = true;
  183. bool stoppedByDirectCmd;
  184. stoppedByDirectCmd = RunMotorC(OUT_C, motorParamsC.power, motorParamsC.tacholimit, motorParamsC.speedreg, motorParamsC.holdbrake, motorParamsC.smoothstart);
  185. // if we exited from external NXTMotor.Stop command, we might've overwritten
  186. // the power value before exiting the main controller loop, so restore defined
  187. // end state here again:
  188. if (stoppedByDirectCmd) {
  189. if (MotorRegulation(OUT_C) == OUT_REGMODE_SPEED) {
  190. MotorBrake(OUT_C);
  191. } else {
  192. MotorOff(OUT_C);
  193. }//end if
  194. }//end if
  195. taskCrunning = false;
  196. //Release(movingC);
  197. //TextOut(0,LCD_LINE8, "Task C stopped");
  198. }//MoveC
  199. task MoveSync() {
  200. #ifdef ENABLEDEBUGGING_SHOWTASKS
  201. taskSyncRunning = true;
  202. #endif
  203. bool stoppedByDirectCmd;
  204. if (SyncPorts == 3) { // OUT_AB
  205. //Acquire(movingA);
  206. //Acquire(movingB);
  207. taskArunning = true;
  208. taskBrunning = true;
  209. stoppedByDirectCmd = RunMotor2(OUT_A, motorParamsSync.power, motorParamsSync.tacholimit, false, motorParamsSync.holdbrake, motorParamsSync.smoothstart, OUT_B);
  210. if (stoppedByDirectCmd) {
  211. if (MotorRegulation(OUT_A) == OUT_REGMODE_SPEED) {
  212. MotorBrake2(OUT_A, OUT_B);
  213. } else {
  214. MotorOff2(OUT_A, OUT_B);
  215. }//end if
  216. }//end if
  217. taskArunning = false;
  218. taskBrunning = false;
  219. //Release(movingA);
  220. //Release(movingB);
  221. } else if (SyncPorts == 4) { // OUT_AC
  222. //Acquire(movingA);
  223. //Acquire(movingC);
  224. taskArunning = true;
  225. taskCrunning = true;
  226. stoppedByDirectCmd = RunMotor2(OUT_A, motorParamsSync.power, motorParamsSync.tacholimit, false, motorParamsSync.holdbrake, motorParamsSync.smoothstart, OUT_C);
  227. if (stoppedByDirectCmd) {
  228. if (MotorRegulation(OUT_A) == OUT_REGMODE_SPEED) {
  229. MotorBrake2(OUT_A, OUT_C);
  230. } else {
  231. MotorOff2(OUT_A, OUT_C);
  232. }//end if
  233. }//end if
  234. taskArunning = false;
  235. taskCrunning = false;
  236. //Release(movingA);
  237. //Release(movingC);
  238. } else if (SyncPorts == 5) { // OUT_BC
  239. //Acquire(movingB);
  240. //Acquire(movingC);
  241. taskBrunning = true;
  242. taskCrunning = true;
  243. stoppedByDirectCmd = RunMotor2(OUT_B, motorParamsSync.power, motorParamsSync.tacholimit, false, motorParamsSync.holdbrake, motorParamsSync.smoothstart, OUT_C);
  244. if (stoppedByDirectCmd) {
  245. if (MotorRegulation(OUT_B) == OUT_REGMODE_SPEED) {
  246. MotorBrake2(OUT_B, OUT_C);
  247. } else {
  248. MotorOff2(OUT_B, OUT_C);
  249. }//end if
  250. }//end if
  251. taskBrunning = false;
  252. taskCrunning = false;
  253. //Release(movingB);
  254. //Release(movingC);
  255. }//end if
  256. #ifdef ENABLEDEBUGGING_SHOWTASKS
  257. taskSyncRunning = false;
  258. #endif
  259. }//MoveSync
  260. inline bool IsMotorReady(const byte &port) {
  261. // check output state info, this is simple
  262. if (MotorIsRunning(port)) {
  263. return false;
  264. } else { // maybe braking or coasting or whatever:
  265. switch(port) {
  266. case OUT_A:
  267. return !(taskArunning);
  268. break;
  269. case OUT_B:
  270. return !(taskBrunning);
  271. break;
  272. case OUT_C:
  273. return !(taskCrunning);
  274. break;
  275. }//end switch
  276. }//end if
  277. }//end function
  278. /*
  279. task dummyA() {
  280. int i = 0;
  281. int j = 0;
  282. while(true){
  283. i++;
  284. i = j;
  285. j = MotorTachoCount(OUT_A);
  286. }//end while
  287. }//end task
  288. task dummyB() {
  289. int i = 0;
  290. int j = 0;
  291. while(true){
  292. i++;
  293. i = j;
  294. j = MotorTachoCount(OUT_B);
  295. }//end while
  296. }//end task
  297. task dummyC() {
  298. int i = 0;
  299. int j = 0;
  300. while(true){
  301. i++;
  302. i = j;
  303. j = MotorTachoCount(OUT_C);
  304. }//end while
  305. }//end task
  306. task dummyD() {
  307. int i = 0;
  308. int j = 0;
  309. while(true){
  310. i++;
  311. i = j;
  312. j = MotorTachoCount(OUT_A);
  313. }//end while
  314. }//end task
  315. task dummyE() {
  316. int i = 0;
  317. int j = 0;
  318. while(true){
  319. i++;
  320. i = j;
  321. j = MotorTachoCount(OUT_B);
  322. }//end while
  323. }//end task
  324. */
  325. // -------------------------------------------------
  326. // main task
  327. /*
  328. task TESTmain() {
  329. byte port = OUT_B;
  330. // **** Init
  331. DisplayMainScreen();
  332. //Wait(9000);
  333. // don't forget this
  334. InitSpeedFromPosLUT();
  335. // launch 3 dummy tasks
  336. start dummyA;
  337. start dummyB;
  338. //start dummyC;
  339. //start dummyD;
  340. //start dummyE;
  341. Wait(20);
  342. // **** Init / Reset motor
  343. MotorOff(OUT_A);
  344. MotorOff(OUT_B);
  345. MotorOff(OUT_C);
  346. ResetErrorCorrectionAndBlockCount(OUT_A);
  347. ResetErrorCorrectionAndBlockCount(OUT_B);
  348. ResetErrorCorrectionAndBlockCount(OUT_C);
  349. Wait(1100);
  350. // **** Try out new function
  351. //RunMotor(const byte &port, const int &power, const long &tacholimit, const bool &speedreg, const bool &holdbrake, const bool &smoothstart)
  352. //RunMotor(port, 100, 1000, true, false, false);
  353. //RunMotor2(OUT_B, 100, 1000, false, false, true, OUT_C);
  354. motorParamsA.power = 100;
  355. motorParamsA.tacholimit = 1000;
  356. motorParamsA.speedreg = false;
  357. motorParamsA.holdbrake = false;
  358. motorParamsA.smoothstart = true;
  359. motorParamsB.power = 100;
  360. motorParamsB.tacholimit = 1000;
  361. motorParamsB.speedreg = false;
  362. motorParamsB.holdbrake = false;
  363. motorParamsB.smoothstart = true;
  364. motorParamsC.power = 100;
  365. motorParamsC.tacholimit = 1000;
  366. motorParamsC.speedreg = false;
  367. motorParamsC.holdbrake = false;
  368. motorParamsC.smoothstart = true;
  369. start MoveA;
  370. start MoveB;
  371. start MoveC;
  372. //Wait(4000);
  373. //NumOut(0, LCD_LINE1, MotorTachoCount(OUT_B), true);
  374. //NumOut(0, LCD_LINE2, MotorTachoCount(OUT_C));
  375. }//end task
  376. */
  377. task main(){
  378. // parameter initialization
  379. string in = "";
  380. int i = 0;
  381. byte packetType;
  382. byte port;
  383. int power = 0;
  384. long angle = 0;
  385. int turnratio = 0;
  386. byte modebits = 0;
  387. bool speedreg = false;
  388. bool holdbrake = false;
  389. bool smoothstart = false;
  390. byte port1;
  391. byte port2;
  392. const byte bit1 = 1;
  393. const byte bit2 = 2;
  394. const byte bit3 = 4;
  395. string tmp = "";
  396. //string tmp2 = "";
  397. // init!
  398. taskArunning = false;
  399. taskBrunning = false;
  400. taskCrunning = false;
  401. DisplayMainScreen();
  402. //Wait(9000);
  403. // don't forget this
  404. InitSpeedFromPosLUT();
  405. // purge mailboxes to make sure, in case something is left over,
  406. // I don't know...
  407. in = "...";
  408. while(StrLen(in) > 0) {
  409. ReceiveRemoteString(INBOX, true, in);
  410. }//end while
  411. in = "...";
  412. while(StrLen(in) > 0) {
  413. ReceiveRemoteString(OUTBOX, true, in);
  414. }//end while
  415. #ifdef ENABLEDEBUGGING_REMOTELOGGING
  416. in = "...";
  417. while(StrLen(in) > 0) {
  418. ReceiveRemoteString(DEBUG_OUTBOX, true, in);
  419. }//end while
  420. #endif
  421. in = "";
  422. #ifdef ENABLEDEBUGGING_REMOTELOGGING
  423. SendDebugMessage(99, "Remote logging enabled!");
  424. #endif
  425. while(true){
  426. ReceiveRemoteString(INBOX, true, in);
  427. if(StrLen(in) > 0) {
  428. #ifdef ENABLEDEBUGGING_OLDLCDTIMING
  429. receivedMsgTime = CurrentTick(); // NEW DEBUG
  430. #endif
  431. #ifdef ENABLEDEBUGGING_ACOUSTICPROTOCOL
  432. PlayTone(200, 50);
  433. #endif
  434. // take first value, decide what to do...
  435. tmp = SubStr(in, 0, 1); // pos 0
  436. packetType = StrToNum(tmp);
  437. // main packet handler!
  438. switch (packetType) {
  439. case PROTO_CONTROLLED_MOTORCMD: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  440. // parse...
  441. tmp = SubStr(in, 1, 1); // pos 1
  442. port = StrToNum(tmp);
  443. tmp = SubStr(in, 2, 3); // pos 2 3 4
  444. power = StrToNum(tmp);
  445. tmp = SubStr(in, 5, 6); // pos 5 6 7 8 9 10
  446. angle = StrToNum(tmp);
  447. tmp = SubStr(in, 11, 1); // pos 11
  448. modebits = StrToNum(tmp);
  449. // process...
  450. // power
  451. if(power > 100) {
  452. power = -(power - 100);
  453. }//end if
  454. // bitfield
  455. if (modebits & bit1) {
  456. holdbrake = true;
  457. } else {
  458. holdbrake = false;
  459. }//end if
  460. if (modebits & bit2) {
  461. speedreg = true;
  462. } else {
  463. speedreg = false;
  464. }//end if
  465. if (modebits & bit3) {
  466. smoothstart = true;
  467. } else {
  468. smoothstart = false;
  469. }//end if
  470. // finally, the command
  471. if (port == 0) { // OUT_A
  472. motorParamsA.power = power;
  473. motorParamsA.tacholimit = angle;
  474. motorParamsA.speedreg = speedreg;
  475. motorParamsA.holdbrake = holdbrake;
  476. motorParamsA.smoothstart = smoothstart;
  477. if (taskArunning == false) {
  478. start MoveA;
  479. } else {
  480. TaskBusySignal();
  481. } // end if
  482. } else if (port == 1) { // OUT_B
  483. motorParamsB.power = power;
  484. motorParamsB.tacholimit = angle;
  485. motorParamsB.speedreg = speedreg;
  486. motorParamsB.holdbrake = holdbrake;
  487. motorParamsB.smoothstart = smoothstart;
  488. if (taskBrunning == false) {
  489. #ifdef ENABLEDEBUGGING_OLDLCDTIMING
  490. parsedTime = CurrentTick() - receivedMsgTime; // NEW DEBUG
  491. #endif
  492. start MoveB;
  493. } else {
  494. TaskBusySignal();
  495. } // end if
  496. } else if (port == 2) { // OUT_C
  497. motorParamsC.power = power;
  498. motorParamsC.tacholimit = angle;
  499. motorParamsC.speedreg = speedreg;
  500. motorParamsC.holdbrake = holdbrake;
  501. motorParamsC.smoothstart = smoothstart;
  502. if (taskCrunning == false) {
  503. start MoveC;
  504. } else {
  505. TaskBusySignal();
  506. }// end if
  507. } else { // Otherwise (OUT_AB, OUT_AC, OUT_BC, OUT_ABC?)
  508. SyncPorts = port;
  509. motorParamsSync.power = power;
  510. motorParamsSync.tacholimit = angle;
  511. motorParamsSync.turnratio = 0; //turnratio;
  512. motorParamsSync.speedreg = false; //always for sync!
  513. motorParamsSync.holdbrake = holdbrake;
  514. motorParamsSync.smoothstart = smoothstart;
  515. // this doesn't look elegant at all, but it works.
  516. if ( ((port == 3) && (taskArunning == false) && (taskBrunning == false))
  517. || ((port == 4) && (taskArunning == false) && (taskCrunning == false))
  518. || ((port == 5) && (taskBrunning == false) && (taskCrunning == false)) ) {
  519. start MoveSync;
  520. } else {
  521. TaskBusySignal();
  522. }//end if
  523. }//end if
  524. //PlayTone(440, 50);
  525. break;
  526. case PROTO_RESET_ERROR_CORRECTION: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  527. tmp = SubStr(in, 1, 1); // pos 1
  528. port = StrToNum(tmp);
  529. if (port <= 2) {
  530. ResetErrorCorrectionAndBlockCount(port);
  531. } else if (port == 3) { // OUT_AB
  532. ResetErrorCorrectionAndBlockCount(OUT_A);
  533. ResetErrorCorrectionAndBlockCount(OUT_B);
  534. } else if (port == 4) { // OUT_AC
  535. ResetErrorCorrectionAndBlockCount(OUT_A);
  536. ResetErrorCorrectionAndBlockCount(OUT_C);
  537. } else if (port == 5) { // OUT_BC
  538. ResetErrorCorrectionAndBlockCount(OUT_B);
  539. ResetErrorCorrectionAndBlockCount(OUT_C);
  540. } else if (port == 6) { // OUT_ABC
  541. ResetErrorCorrectionAndBlockCount(OUT_A);
  542. ResetErrorCorrectionAndBlockCount(OUT_B);
  543. ResetErrorCorrectionAndBlockCount(OUT_C);
  544. }//end if
  545. break;
  546. case PROTO_ISMOTORREADY: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  547. tmp = SubStr(in, 1, 1); // pos 1
  548. port = StrToNum(tmp);
  549. // send answer string: portnum, then if ready or not
  550. if (IsMotorReady(port)) {
  551. tmp = StrCat(tmp, "1");
  552. } else {
  553. tmp = StrCat(tmp, "0");
  554. }//end if
  555. SendMessage(OUTBOX, tmp);
  556. break;
  557. case PROTO_CLASSIC_MOTORCMD: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  558. // parse...
  559. tmp = SubStr(in, 1, 1); // pos 1
  560. port = StrToNum(tmp);
  561. tmp = SubStr(in, 2, 3); // pos 2 3 4
  562. power = StrToNum(tmp);
  563. tmp = SubStr(in, 5, 6); // pos 5 6 7 8 9 10
  564. angle = StrToNum(tmp);
  565. tmp = SubStr(in, 11, 1); // pos 11
  566. speedreg = StrToNum(tmp);
  567. // process...
  568. // power
  569. if(power > 100) {
  570. power = -(power - 100);
  571. }//end if
  572. //% OUT_A 0x00
  573. //% OUT_B 0x01
  574. //% OUT_C 0x02
  575. //% OUT_AB 0x03
  576. //% OUT_AC 0x04
  577. //% OUT_BC 0x05
  578. //% OUT_ABC 0x06
  579. if (port <= 2) {
  580. // if no current tacholimit and no new one, allow speed change
  581. if ((MotorTachoLimit(port) == 0) && (angle == 0)) {
  582. MotorCmdSingleReset(port, power, angle, speedreg);
  583. } else {
  584. if (IsMotorReady(port)) {
  585. MotorCmdSingleReset(port, power, angle, speedreg);
  586. } else {
  587. TaskBusySignal();
  588. }//end if
  589. }//end if
  590. } else { // Otherwise (OUT_AB, OUT_AC, OUT_BC, OUT_ABC?)
  591. switch(port) {
  592. case 3: // OUT_AB
  593. port1 = 0;
  594. port2 = 1;
  595. break;
  596. case 4: // OUT_AC
  597. port1 = 0;
  598. port2 = 2;
  599. break;
  600. case 5: // OUT_BC
  601. port1 = 1;
  602. port2 = 2;
  603. break;
  604. }//end switch
  605. // if no current tacholimit and no new one, allow speed change
  606. if ((MotorTachoLimit(port1) == 0) && (MotorTachoLimit(port2) == 0) && (angle == 0)) {
  607. //~~~~BEGIN COPY PASTE CODE~~~~~~~~~~~~~~~~~~
  608. //avoid already synced motors (that doesn't work as we know...)
  609. until((MotorRegulation(port1) == OUT_REGMODE_IDLE) && (MotorRegulation(port2) == OUT_REGMODE_IDLE)) {
  610. // repeatedly setting this is not nice, but so
  611. // we don't need a timeout...!
  612. MotorOff2(port1, port2);
  613. // make sure VM applies our settings
  614. Wait(1);
  615. }//end until
  616. MotorCmdDoubleReset(port1, power, angle, port2);
  617. //~~~~END COPY PASTE CODE~~~~~~~~~~~~~~~~~~
  618. } else {
  619. if (IsMotorReady(port1) && IsMotorReady(port2)) {
  620. //~~~~BEGIN COPY PASTE CODE~~~~~~~~~~~~~~~~~~
  621. //avoid already synced motors (that doesn't work as we know...)
  622. until((MotorRegulation(port1) == OUT_REGMODE_IDLE) && (MotorRegulation(port2) == OUT_REGMODE_IDLE)) {
  623. // repeatedly setting this is not nice, but so
  624. // we don't need a timeout...!
  625. MotorOff2(port1, port2);
  626. // make sure VM applies our settings
  627. Wait(1);
  628. }//end until
  629. MotorCmdDoubleReset(port1, power, angle, port2);
  630. //~~~~END COPY PASTE CODE~~~~~~~~~~~~~~~~~~
  631. } else {
  632. TaskBusySignal();
  633. }//end if
  634. }//end if
  635. }//end if
  636. break;
  637. }//end switch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  638. // reset message !!!!
  639. in = "";
  640. }//end if
  641. // check cancel button:
  642. if (ButtonPressed(BTNCENTER, false)) {
  643. // release all motors
  644. MotorOff(OUT_A);
  645. MotorOff(OUT_B);
  646. MotorOff(OUT_C);
  647. PlayTone(440, 500);
  648. Wait(100);
  649. // release all motors again
  650. MotorOff(OUT_A);
  651. MotorOff(OUT_B);
  652. MotorOff(OUT_C);
  653. TextOut(5,LCD_LINE7, "EMERGENCY STOP ", false);
  654. TextOut(2,LCD_LINE8, "Restart program! ", false);
  655. Wait(2500);
  656. StopAllTasks();
  657. /*
  658. // keep
  659. while(ButtonPressed(BTNCENTER, false)) {
  660. MotorOff(OUT_A);
  661. MotorOff(OUT_B);
  662. MotorOff(OUT_C);
  663. PlayTone(440, 100);
  664. Wait(500);
  665. }//end while
  666. // purge incoming queue...
  667. in = "...";
  668. while(StrLen(in) > 0) {
  669. ReceiveRemoteString(INBOX, true, in);
  670. }//end while
  671. in = "";
  672. // manually reset task-semaphores
  673. // not very clean, but this button is for emergencies anyway...
  674. taskArunning = false;
  675. taskBrunning = false;
  676. taskCrunning = false;
  677. // reset counters for a nice clean start
  678. ResetErrorCorrectionAndBlockCount(OUT_A);
  679. ResetErrorCorrectionAndBlockCount(OUT_B);
  680. ResetErrorCorrectionAndBlockCount(OUT_C);
  681. */
  682. }//end if
  683. // debugging
  684. #ifdef ENABLEDEBUGGING_SHOWTASKS
  685. string taskMsg = "";
  686. string tmpA = "_ ";
  687. string tmpB = "_ ";
  688. string tmpC = "_ ";
  689. string tmpSync = "____ ";
  690. if (taskArunning) tmpA = "A ";
  691. if (taskBrunning) tmpB = "B ";
  692. if (taskCrunning) tmpC = "C ";
  693. if (taskSyncRunning) tmpSync = "Sync ";
  694. taskMsg = StrCat(tmpA, tmpB, tmpC, tmpSync);
  695. TextOut(0, LCD_LINE7, taskMsg);
  696. #endif
  697. }//end while
  698. TextOut(0,LCD_LINE1, "MainLoop exit", true);
  699. PlayTone(500, 1000);
  700. Wait(5000);
  701. }//end task